Merge "Generate additional repackaged BouncyCastle to be used by platform (separate from existing libcore version)."
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ApplicationSpecific.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ApplicationSpecific.java
new file mode 100644
index 0000000..9378fd4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ApplicationSpecific.java
@@ -0,0 +1,248 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * Base class for an ASN.1 ApplicationSpecific object
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ASN1ApplicationSpecific
+    extends ASN1Primitive
+{
+    protected final boolean   isConstructed;
+    protected final int       tag;
+    protected final byte[]    octets;
+
+    ASN1ApplicationSpecific(
+        boolean isConstructed,
+        int tag,
+        byte[] octets)
+    {
+        this.isConstructed = isConstructed;
+        this.tag = tag;
+        this.octets = Arrays.clone(octets);
+    }
+
+    /**
+     * Return an ASN1ApplicationSpecific from the passed in object, which may be a byte array, or null.
+     *
+     * @param obj the object to be converted.
+     * @return obj's representation as an ASN1ApplicationSpecific object.
+     */
+    public static ASN1ApplicationSpecific getInstance(Object obj)
+    {
+        if (obj == null || obj instanceof ASN1ApplicationSpecific)
+        {
+            return (ASN1ApplicationSpecific)obj;
+        }
+        else if (obj instanceof byte[])
+        {
+            try
+            {
+                return ASN1ApplicationSpecific.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("Failed to construct object from byte[]: " + e.getMessage());
+            }
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+    }
+
+    protected static int getLengthOfHeader(byte[] data)
+    {
+        int length = data[1] & 0xff; // TODO: assumes 1 byte tag
+
+        if (length == 0x80)
+        {
+            return 2;      // indefinite-length encoding
+        }
+
+        if (length > 127)
+        {
+            int size = length & 0x7f;
+
+            // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
+            if (size > 4)
+            {
+                throw new IllegalStateException("DER length more than 4 bytes: " + size);
+            }
+
+            return size + 2;
+        }
+
+        return 2;
+    }
+
+    /**
+     * Return true if the object is marked as constructed, false otherwise.
+     *
+     * @return true if constructed, otherwise false.
+     */
+    public boolean isConstructed()
+    {
+        return isConstructed;
+    }
+
+    /**
+     * Return the contents of this object as a byte[]
+     *
+     * @return the encoded contents of the object.
+     */
+    public byte[] getContents()
+    {
+        return Arrays.clone(octets);
+    }
+
+    /**
+     * Return the tag number associated with this object,
+     *
+     * @return the application tag number.
+     */
+    public int getApplicationTag() 
+    {
+        return tag;
+    }
+
+    /**
+     * Return the enclosed object assuming explicit tagging.
+     *
+     * @return  the resulting object
+     * @throws IOException if reconstruction fails.
+     */
+    public ASN1Primitive getObject()
+        throws IOException 
+    {
+        return ASN1Primitive.fromByteArray(getContents());
+    }
+
+    /**
+     * Return the enclosed object assuming implicit tagging.
+     *
+     * @param derTagNo the type tag that should be applied to the object's contents.
+     * @return  the resulting object
+     * @throws IOException if reconstruction fails.
+     */
+    public ASN1Primitive getObject(int derTagNo)
+        throws IOException
+    {
+        if (derTagNo >= 0x1f)
+        {
+            throw new IOException("unsupported tag number");
+        }
+
+        byte[] orig = this.getEncoded();
+        byte[] tmp = replaceTagNumber(derTagNo, orig);
+
+        if ((orig[0] & BERTags.CONSTRUCTED) != 0)
+        {
+            tmp[0] |= BERTags.CONSTRUCTED;
+        }
+
+        return ASN1Primitive.fromByteArray(tmp);
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        return StreamUtil.calculateTagLength(tag) + StreamUtil.calculateBodyLength(octets.length) + octets.length;
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
+     */
+    void encode(ASN1OutputStream out) throws IOException
+    {
+        int classBits = BERTags.APPLICATION;
+        if (isConstructed)
+        {
+            classBits |= BERTags.CONSTRUCTED;
+        }
+
+        out.writeEncoded(classBits, tag, octets);
+    }
+    
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof ASN1ApplicationSpecific))
+        {
+            return false;
+        }
+
+        ASN1ApplicationSpecific other = (ASN1ApplicationSpecific)o;
+
+        return isConstructed == other.isConstructed
+            && tag == other.tag
+            && Arrays.areEqual(octets, other.octets);
+    }
+
+    public int hashCode()
+    {
+        return (isConstructed ? 1 : 0) ^ tag ^ Arrays.hashCode(octets);
+    }
+
+    private byte[] replaceTagNumber(int newTag, byte[] input)
+        throws IOException
+    {
+        int tagNo = input[0] & 0x1f;
+        int index = 1;
+        //
+        // with tagged object tag number is bottom 5 bits, or stored at the start of the content
+        //
+        if (tagNo == 0x1f)
+        {
+            int b = input[index++] & 0xff;
+
+            // X.690-0207 8.1.2.4.2
+            // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
+            if ((b & 0x7f) == 0) // Note: -1 will pass
+            {
+                throw new IOException("corrupted stream - invalid high tag number found");
+            }
+
+            while ((b & 0x80) != 0)
+            {
+                b = input[index++] & 0xff;
+            }
+        }
+
+        byte[] tmp = new byte[input.length - index + 1];
+
+        System.arraycopy(input, index, tmp, 1, tmp.length - 1);
+
+        tmp[0] = (byte)newTag;
+
+        return tmp;
+    }
+
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append("[");
+        if (isConstructed())
+        {
+            sb.append("CONSTRUCTED ");
+        }
+        sb.append("APPLICATION ");
+        sb.append(Integer.toString(getApplicationTag()));
+        sb.append("]");
+        // @todo content encoding somehow?
+        if (this.octets != null)
+        {
+            sb.append(" #");
+            sb.append(Hex.toHexString(this.octets));
+        }
+        else
+        {
+            sb.append(" #null");
+        }
+        sb.append(" ");
+        return sb.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java
new file mode 100644
index 0000000..f4bc6e3
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java
@@ -0,0 +1,21 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Interface to parse ASN.1 ApplicationSpecific objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ASN1ApplicationSpecificParser
+    extends ASN1Encodable, InMemoryRepresentable
+{
+    /**
+     * Read the next object in the parser.
+     *
+     * @return an ASN1Encodable
+     * @throws IOException on a parsing or decoding error.
+     */
+    ASN1Encodable readObject()
+        throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1BitString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1BitString.java
new file mode 100644
index 0000000..e3ae7c4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1BitString.java
@@ -0,0 +1,294 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.io.Streams;
+
+/**
+ * Base class for BIT STRING objects
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ASN1BitString
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private static final char[]  table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+    protected final byte[]      data;
+    protected final int         padBits;
+
+    /**
+     * @param bitString an int containing the BIT STRING
+     * @return the correct number of pad bits for a bit string defined in
+     * a 32 bit constant
+     */
+    static protected int getPadBits(
+        int bitString)
+    {
+        int val = 0;
+        for (int i = 3; i >= 0; i--)
+        {
+            //
+            // this may look a little odd, but if it isn't done like this pre jdk1.2
+            // JVM's break!
+            //
+            if (i != 0)
+            {
+                if ((bitString >> (i * 8)) != 0)
+                {
+                    val = (bitString >> (i * 8)) & 0xFF;
+                    break;
+                }
+            }
+            else
+            {
+                if (bitString != 0)
+                {
+                    val = bitString & 0xFF;
+                    break;
+                }
+            }
+        }
+
+        if (val == 0)
+        {
+            return 0;
+        }
+
+
+        int bits = 1;
+
+        while (((val <<= 1) & 0xFF) != 0)
+        {
+            bits++;
+        }
+
+        return 8 - bits;
+    }
+
+    /**
+     * @param bitString an int containing the BIT STRING
+     * @return the correct number of bytes for a bit string defined in
+     * a 32 bit constant
+     */
+    static protected byte[] getBytes(int bitString)
+    {
+        if (bitString == 0)
+        {
+            return new byte[0];
+        }
+
+        int bytes = 4;
+        for (int i = 3; i >= 1; i--)
+        {
+            if ((bitString & (0xFF << (i * 8))) != 0)
+            {
+                break;
+            }
+            bytes--;
+        }
+
+        byte[] result = new byte[bytes];
+        for (int i = 0; i < bytes; i++)
+        {
+            result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
+        }
+
+        return result;
+    }
+
+    /**
+     * Base constructor.
+     *
+     * @param data the octets making up the bit string.
+     * @param padBits the number of extra bits at the end of the string.
+     */
+    public ASN1BitString(
+        byte[]  data,
+        int     padBits)
+    {
+        if (data == null)
+        {
+            throw new NullPointerException("data cannot be null");
+        }
+        if (data.length == 0 && padBits != 0)
+        {
+            throw new IllegalArgumentException("zero length data with non-zero pad bits");
+        }
+        if (padBits > 7 || padBits < 0)
+        {
+            throw new IllegalArgumentException("pad bits cannot be greater than 7 or less than 0");
+        }
+
+        this.data = Arrays.clone(data);
+        this.padBits = padBits;
+    }
+
+    /**
+     * Return a String representation of this BIT STRING
+     *
+     * @return a String representation.
+     */
+    public String getString()
+    {
+        StringBuffer          buf = new StringBuffer("#");
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+        try
+        {
+            aOut.writeObject(this);
+        }
+        catch (IOException e)
+        {
+            throw new ASN1ParsingException("Internal error encoding BitString: " + e.getMessage(), e);
+        }
+
+        byte[]    string = bOut.toByteArray();
+
+        for (int i = 0; i != string.length; i++)
+        {
+            buf.append(table[(string[i] >>> 4) & 0xf]);
+            buf.append(table[string[i] & 0xf]);
+        }
+
+        return buf.toString();
+    }
+
+    /**
+     * @return the value of the bit string as an int (truncating if necessary)
+     */
+    public int intValue()
+    {
+        int value = 0;
+        byte[] string = data;
+
+        if (padBits > 0 && data.length <= 4)
+        {
+            string = derForm(data, padBits);
+        }
+
+        for (int i = 0; i != string.length && i != 4; i++)
+        {
+            value |= (string[i] & 0xff) << (8 * i);
+        }
+
+        return value;
+    }
+
+    /**
+     * Return the octets contained in this BIT STRING, checking that this BIT STRING really
+     * does represent an octet aligned string. Only use this method when the standard you are
+     * following dictates that the BIT STRING will be octet aligned.
+     *
+     * @return a copy of the octet aligned data.
+     */
+    public byte[] getOctets()
+    {
+        if (padBits != 0)
+        {
+            throw new IllegalStateException("attempt to get non-octet aligned data from BIT STRING");
+        }
+
+        return Arrays.clone(data);
+    }
+
+    public byte[] getBytes()
+    {
+        return derForm(data, padBits);
+    }
+
+    public int getPadBits()
+    {
+        return padBits;
+    }
+
+    public String toString()
+    {
+        return getString();
+    }
+
+    public int hashCode()
+    {
+        return padBits ^ Arrays.hashCode(this.getBytes());
+    }
+
+    protected boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof ASN1BitString))
+        {
+            return false;
+        }
+
+        ASN1BitString other = (ASN1BitString)o;
+
+        return this.padBits == other.padBits
+            && Arrays.areEqual(this.getBytes(), other.getBytes());
+    }
+
+    protected static byte[] derForm(byte[] data, int padBits)
+    {
+        byte[] rv = Arrays.clone(data);
+        // DER requires pad bits be zero
+        if (padBits > 0)
+        {
+            rv[data.length - 1] &= 0xff << padBits;
+        }
+
+        return rv;
+    }
+
+    static ASN1BitString fromInputStream(int length, InputStream stream)
+        throws IOException
+    {
+        if (length < 1)
+        {
+            throw new IllegalArgumentException("truncated BIT STRING detected");
+        }
+
+        int padBits = stream.read();
+        byte[] data = new byte[length - 1];
+
+        if (data.length != 0)
+        {
+            if (Streams.readFully(stream, data) != data.length)
+            {
+                throw new EOFException("EOF encountered in middle of BIT STRING");
+            }
+
+            if (padBits > 0 && padBits < 8)
+            {
+                if (data[data.length - 1] != (byte)(data[data.length - 1] & (0xff << padBits)))
+                {
+                    return new DLBitString(data, padBits);
+                }
+            }
+        }
+
+        return new DERBitString(data, padBits);
+    }
+
+    public ASN1Primitive getLoadedObject()
+    {
+        return this.toASN1Primitive();
+    }
+
+    ASN1Primitive toDERObject()
+    {
+        return new DERBitString(data, padBits);
+    }
+
+    ASN1Primitive toDLObject()
+    {
+        return new DLBitString(data, padBits);
+    }
+
+    abstract void encode(ASN1OutputStream out)
+        throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Boolean.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Boolean.java
new file mode 100644
index 0000000..d6f4dd7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Boolean.java
@@ -0,0 +1,218 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * Public facade of ASN.1 Boolean data.
+ * <p>
+ * Use following to place a new instance of ASN.1 Boolean in your dataset:
+ * <ul>
+ * <li> ASN1Boolean.TRUE literal</li>
+ * <li> ASN1Boolean.FALSE literal</li>
+ * <li> {@link ASN1Boolean#getInstance(boolean) ASN1Boolean.getInstance(boolean)}</li>
+ * <li> {@link ASN1Boolean#getInstance(int) ASN1Boolean.getInstance(int)}</li>
+ * </ul>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1Boolean
+    extends ASN1Primitive
+{
+    private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };
+    private static final byte[] FALSE_VALUE = new byte[] { 0 };
+
+    private final byte[]         value;
+
+    public static final ASN1Boolean FALSE = new ASN1Boolean(false);
+    public static final ASN1Boolean TRUE  = new ASN1Boolean(true);
+
+    /**
+     * Return a boolean from the passed in object.
+     *
+     * @param obj an ASN1Boolean or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return an ASN1Boolean instance.
+     */
+    public static ASN1Boolean getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ASN1Boolean)
+        {
+            return (ASN1Boolean)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            byte[] enc = (byte[])obj;
+            try
+            {
+                return (ASN1Boolean)fromByteArray(enc);
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct boolean from byte[]: " + e.getMessage());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return an ASN1Boolean from the passed in boolean.
+     * @param value true or false depending on the ASN1Boolean wanted.
+     * @return an ASN1Boolean instance.
+     */
+    public static ASN1Boolean getInstance(
+        boolean  value)
+    {
+        return (value ? TRUE : FALSE);
+    }
+
+    /**
+     * Return an ASN1Boolean from the passed in value.
+     * @param value non-zero (true) or zero (false) depending on the ASN1Boolean wanted.
+     * @return an ASN1Boolean instance.
+     */
+    public static ASN1Boolean getInstance(
+        int value)
+    {
+        return (value != 0 ? TRUE : FALSE);
+    }
+
+    // BEGIN Android-added: Unknown reason
+    /**
+     * return a ASN1Boolean from the passed in array.
+     */
+    public static ASN1Boolean getInstance(
+        byte[] octets)
+    {
+        return (octets[0] != 0) ? TRUE : FALSE;
+    }
+
+    // END Android-added: Unknown reason
+    /**
+     * Return a Boolean from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return an ASN1Boolean instance.
+     */
+    public static ASN1Boolean getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof ASN1Boolean)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());
+        }
+    }
+
+    ASN1Boolean(
+        byte[] value)
+    {
+        if (value.length != 1)
+        {
+            throw new IllegalArgumentException("byte value should have 1 byte in it");
+        }
+
+        if (value[0] == 0)
+        {
+            this.value = FALSE_VALUE;
+        }
+        else if ((value[0] & 0xff) == 0xff)
+        {
+            this.value = TRUE_VALUE;
+        }
+        else
+        {
+            this.value = Arrays.clone(value);
+        }
+    }
+
+    /**
+     * @deprecated use getInstance(boolean) method.
+     * @param value true or false.
+     */
+    // Android-changed: Reduce visibility to protected
+    protected ASN1Boolean(
+        boolean     value)
+    {
+        this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
+    }
+
+    public boolean isTrue()
+    {
+        return (value[0] != 0);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 3;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.BOOLEAN, value);
+    }
+
+    protected boolean asn1Equals(
+        ASN1Primitive  o)
+    {
+        if (o instanceof ASN1Boolean)
+        {
+            return (value[0] == ((ASN1Boolean)o).value[0]);
+        }
+
+        return false;
+    }
+
+    public int hashCode()
+    {
+        return value[0];
+    }
+
+
+    public String toString()
+    {
+      return (value[0] != 0) ? "TRUE" : "FALSE";
+    }
+
+    static ASN1Boolean fromOctetString(byte[] value)
+    {
+        if (value.length != 1)
+        {
+            throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it");
+        }
+
+        if (value[0] == 0)
+        {
+            return FALSE;
+        }
+        else if ((value[0] & 0xff) == 0xff)
+        {
+            return TRUE;
+        }
+        else
+        {
+            return new ASN1Boolean(value);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Choice.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Choice.java
new file mode 100644
index 0000000..eec254f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Choice.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+/**
+ * Marker interface for CHOICE objects - if you implement this in a role your
+ * own object any attempt to tag the object implicitly will convert the tag to
+ * an explicit one as the encoding rules require.
+ * <p>
+ * If you use this interface your class should also implement the getInstance()
+ * pattern which takes a tag object and the tagging mode used.
+ * </p>
+ * <p><b>X.690</b></p>
+ * <p><b>8: Basic encoding rules</b></p>
+ * <p><b>8.13 Encoding of a choice value </b></p>
+ * <p>
+ * The encoding of a choice value shall be the same as the encoding of a value of the chosen type.
+ * <blockquote>
+ * NOTE 1 &mdash; The encoding may be primitive or constructed depending on the chosen type.
+ * </blockquote>
+ * <blockquote>
+ * NOTE 2 &mdash; The tag used in the identifier octets is the tag of the chosen type,
+ * as specified in the ASN.1 definition of the choice type.
+ * </blockquote>
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ASN1Choice
+{
+    // marker interface
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Encodable.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Encodable.java
new file mode 100644
index 0000000..fd9903c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Encodable.java
@@ -0,0 +1,15 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+/**
+ * Basic interface to produce serialisers for ASN.1 encodings.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ASN1Encodable
+{
+    /**
+     * Return an object, possibly constructed, of ASN.1 primitives
+     * @return an ASN.1 primitive.
+     */
+    ASN1Primitive toASN1Primitive();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1EncodableVector.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1EncodableVector.java
new file mode 100644
index 0000000..56817e2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1EncodableVector.java
@@ -0,0 +1,65 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * Mutable class for building ASN.1 constructed objects such as SETs or SEQUENCEs.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1EncodableVector
+{
+    private final Vector v = new Vector();
+
+    /**
+     * Base constructor.
+     */
+    public ASN1EncodableVector()
+    {
+    }
+
+    /**
+     * Add an encodable to the vector.
+     *
+     * @param obj the encodable to add.
+     */
+    public void add(ASN1Encodable obj)
+    {
+        v.addElement(obj);
+    }
+
+    /**
+     * Add the contents of another vector.
+     *
+     * @param other the vector to add.
+     */
+    public void addAll(ASN1EncodableVector other)
+    {
+        for (Enumeration en = other.v.elements(); en.hasMoreElements();)
+        {
+            v.addElement(en.nextElement());
+        }
+    }
+
+    /**
+     * Return the object at position i in this vector.
+     *
+     * @param i the index of the object of interest.
+     * @return the object at position i.
+     */
+    public ASN1Encodable get(int i)
+    {
+        return (ASN1Encodable)v.elementAt(i);
+    }
+
+    /**
+     * Return the size of the vector.
+     *
+     * @return the object count in the vector.
+     */
+    public int size()
+    {
+        return v.size();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Encoding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Encoding.java
new file mode 100644
index 0000000..0ea5d58
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Encoding.java
@@ -0,0 +1,24 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+/**
+ * Supported encoding formats.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ASN1Encoding
+{
+    /**
+     * DER - distinguished encoding rules.
+     */
+    static final String DER = "DER";
+
+    /**
+     * DL - definite length encoding.
+     */
+    static final String DL = "DL";
+
+    /**
+     * BER - basic encoding rules.
+     */
+    static final String BER = "BER";
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Enumerated.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Enumerated.java
new file mode 100644
index 0000000..b17af84
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Enumerated.java
@@ -0,0 +1,184 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Properties;
+
+/**
+ * Class representing the ASN.1 ENUMERATED type.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1Enumerated
+    extends ASN1Primitive
+{
+    private final byte[] bytes;
+
+    /**
+     * return an enumerated from the passed in object
+     *
+     * @param obj an ASN1Enumerated or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return an ASN1Enumerated instance, or null.
+     */
+    public static ASN1Enumerated getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ASN1Enumerated)
+        {
+            return (ASN1Enumerated)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (ASN1Enumerated)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return an Enumerated from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return an ASN1Enumerated instance, or null.
+     */
+    public static ASN1Enumerated getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof ASN1Enumerated)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return fromOctetString(((ASN1OctetString)o).getOctets());
+        }
+    }
+
+    /**
+     * Constructor from int.
+     *
+     * @param value the value of this enumerated.
+     */
+    public ASN1Enumerated(
+        int         value)
+    {
+        bytes = BigInteger.valueOf(value).toByteArray();
+    }
+
+    /**
+     * Constructor from BigInteger
+     *
+     * @param value the value of this enumerated.
+     */
+    public ASN1Enumerated(
+        BigInteger   value)
+    {
+        bytes = value.toByteArray();
+    }
+
+    /**
+     * Constructor from encoded BigInteger.
+     *
+     * @param bytes the value of this enumerated as an encoded BigInteger (signed).
+     */
+    public ASN1Enumerated(
+        byte[]   bytes)
+    {
+        if (!Properties.isOverrideSet("com.android.internal.org.bouncycastle.asn1.allow_unsafe_integer"))
+        {
+            if (ASN1Integer.isMalformed(bytes))
+            {
+                throw new IllegalArgumentException("malformed enumerated");
+            }
+        }
+        this.bytes = Arrays.clone(bytes);
+    }
+
+    public BigInteger getValue()
+    {
+        return new BigInteger(bytes);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.ENUMERATED, bytes);
+    }
+    
+    boolean asn1Equals(
+        ASN1Primitive  o)
+    {
+        if (!(o instanceof ASN1Enumerated))
+        {
+            return false;
+        }
+
+        ASN1Enumerated other = (ASN1Enumerated)o;
+
+        return Arrays.areEqual(this.bytes, other.bytes);
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(bytes);
+    }
+
+    private static ASN1Enumerated[] cache = new ASN1Enumerated[12];
+
+    static ASN1Enumerated fromOctetString(byte[] enc)
+    {
+        if (enc.length > 1)
+        {
+            return new ASN1Enumerated(enc);
+        }
+
+        if (enc.length == 0)
+        {
+            throw new IllegalArgumentException("ENUMERATED has zero length");
+        }
+        int value = enc[0] & 0xff;
+
+        if (value >= cache.length)
+        {
+            return new ASN1Enumerated(Arrays.clone(enc));
+        }
+
+        ASN1Enumerated possibleMatch = cache[value];
+
+        if (possibleMatch == null)
+        {
+            possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc));
+        }
+
+        return possibleMatch;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Exception.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Exception.java
new file mode 100644
index 0000000..fc5976e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Exception.java
@@ -0,0 +1,46 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Exception thrown in cases of corrupted or unexpected data in a stream.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1Exception
+    extends IOException
+{
+    private Throwable cause;
+
+    /**
+     * Base constructor
+     *
+     * @param message a message concerning the exception.
+     */
+    ASN1Exception(String message)
+    {
+        super(message);
+    }
+
+    /**
+     * Constructor when this exception is due to another one.
+     *
+     * @param message a message concerning the exception.
+     * @param cause the exception that caused this exception to be thrown.
+     */
+    ASN1Exception(String message, Throwable cause)
+    {
+        super(message);
+        this.cause = cause;
+    }
+
+    /**
+     * Return the underlying cause of this exception, if any.
+     *
+     * @return the exception causing this one, null if there isn't one.
+     */
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1External.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1External.java
new file mode 100644
index 0000000..cdf6bf1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1External.java
@@ -0,0 +1,294 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Class representing the DER-type External
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ASN1External
+    extends ASN1Primitive
+{
+    protected ASN1ObjectIdentifier directReference;
+    protected ASN1Integer indirectReference;
+    protected ASN1Primitive dataValueDescriptor;
+    protected int encoding;
+    protected ASN1Primitive externalContent;
+
+    /**
+     * Construct an EXTERNAL object, the input encoding vector must have exactly two elements on it.
+     * <p>
+     * Acceptable input formats are:
+     * <ul>
+     * <li> {@link ASN1ObjectIdentifier} + data {@link DERTaggedObject} (direct reference form)</li>
+     * <li> {@link ASN1Integer} + data {@link DERTaggedObject} (indirect reference form)</li>
+     * <li> Anything but {@link DERTaggedObject} + data {@link DERTaggedObject} (data value form)</li>
+     * </ul>
+     *
+     * @throws IllegalArgumentException if input size is wrong, or
+     */
+    public ASN1External(ASN1EncodableVector vector)
+    {
+        int offset = 0;
+
+        ASN1Primitive enc = getObjFromVector(vector, offset);
+        if (enc instanceof ASN1ObjectIdentifier)
+        {
+            directReference = (ASN1ObjectIdentifier)enc;
+            offset++;
+            enc = getObjFromVector(vector, offset);
+        }
+        if (enc instanceof ASN1Integer)
+        {
+            indirectReference = (ASN1Integer) enc;
+            offset++;
+            enc = getObjFromVector(vector, offset);
+        }
+        if (!(enc instanceof ASN1TaggedObject))
+        {
+            dataValueDescriptor = (ASN1Primitive) enc;
+            offset++;
+            enc = getObjFromVector(vector, offset);
+        }
+
+        if (vector.size() != offset + 1)
+        {
+            throw new IllegalArgumentException("input vector too large");
+        }
+
+        if (!(enc instanceof ASN1TaggedObject))
+        {
+            throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External");
+        }
+        ASN1TaggedObject obj = (ASN1TaggedObject)enc;
+        setEncoding(obj.getTagNo());
+        externalContent = obj.getObject();
+    }
+
+    private ASN1Primitive getObjFromVector(ASN1EncodableVector v, int index)
+    {
+        if (v.size() <= index)
+        {
+            throw new IllegalArgumentException("too few objects in input vector");
+        }
+
+        return v.get(index).toASN1Primitive();
+    }
+
+    /**
+     * Creates a new instance of External
+     * See X.690 for more informations about the meaning of these parameters
+     * @param directReference The direct reference or <code>null</code> if not set.
+     * @param indirectReference The indirect reference or <code>null</code> if not set.
+     * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
+     * @param externalData The external data in its encoded form.
+     */
+    public ASN1External(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData)
+    {
+        this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive());
+    }
+
+    /**
+     * Creates a new instance of External.
+     * See X.690 for more informations about the meaning of these parameters
+     * @param directReference The direct reference or <code>null</code> if not set.
+     * @param indirectReference The indirect reference or <code>null</code> if not set.
+     * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
+     * @param encoding The encoding to be used for the external data
+     * @param externalData The external data
+     */
+    public ASN1External(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData)
+    {
+        setDirectReference(directReference);
+        setIndirectReference(indirectReference);
+        setDataValueDescriptor(dataValueDescriptor);
+        setEncoding(encoding);
+        setExternalContent(externalData.toASN1Primitive());
+    }
+
+    ASN1Primitive toDERObject()
+     {
+         if (this instanceof DERExternal)
+         {
+             return this;
+         }
+
+         return new DERExternal(directReference, indirectReference, dataValueDescriptor, encoding, externalContent);
+     }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode()
+    {
+        int ret = 0;
+        if (directReference != null)
+        {
+            ret = directReference.hashCode();
+        }
+        if (indirectReference != null)
+        {
+            ret ^= indirectReference.hashCode();
+        }
+        if (dataValueDescriptor != null)
+        {
+            ret ^= dataValueDescriptor.hashCode();
+        }
+        ret ^= externalContent.hashCode();
+        return ret;
+    }
+
+    boolean isConstructed()
+    {
+        return true;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        return this.getEncoded().length;
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.asn1.ASN1Primitive#asn1Equals(org.bouncycastle.asn1.ASN1Primitive)
+     */
+    boolean asn1Equals(ASN1Primitive o)
+    {
+        if (!(o instanceof ASN1External))
+        {
+            return false;
+        }
+        if (this == o)
+        {
+            return true;
+        }
+        ASN1External other = (ASN1External)o;
+        if (directReference != null)
+        {
+            if (other.directReference == null || !other.directReference.equals(directReference))  
+            {
+                return false;
+            }
+        }
+        if (indirectReference != null)
+        {
+            if (other.indirectReference == null || !other.indirectReference.equals(indirectReference))
+            {
+                return false;
+            }
+        }
+        if (dataValueDescriptor != null)
+        {
+            if (other.dataValueDescriptor == null || !other.dataValueDescriptor.equals(dataValueDescriptor))
+            {
+                return false;
+            }
+        }
+        return externalContent.equals(other.externalContent);
+    }
+
+    /**
+     * Returns the data value descriptor
+     * @return The descriptor
+     */
+    public ASN1Primitive getDataValueDescriptor()
+    {
+        return dataValueDescriptor;
+    }
+
+    /**
+     * Returns the direct reference of the external element
+     * @return The reference
+     */
+    public ASN1ObjectIdentifier getDirectReference()
+    {
+        return directReference;
+    }
+
+    /**
+     * Returns the encoding of the content. Valid values are
+     * <ul>
+     * <li><code>0</code> single-ASN1-type</li>
+     * <li><code>1</code> OCTET STRING</li>
+     * <li><code>2</code> BIT STRING</li>
+     * </ul>
+     * @return The encoding
+     */
+    public int getEncoding()
+    {
+        return encoding;
+    }
+    
+    /**
+     * Returns the content of this element
+     * @return The content
+     */
+    public ASN1Primitive getExternalContent()
+    {
+        return externalContent;
+    }
+    
+    /**
+     * Returns the indirect reference of this element
+     * @return The reference
+     */
+    public ASN1Integer getIndirectReference()
+    {
+        return indirectReference;
+    }
+    
+    /**
+     * Sets the data value descriptor
+     * @param dataValueDescriptor The descriptor
+     */
+    private void setDataValueDescriptor(ASN1Primitive dataValueDescriptor)
+    {
+        this.dataValueDescriptor = dataValueDescriptor;
+    }
+
+    /**
+     * Sets the direct reference of the external element
+     * @param directReferemce The reference
+     */
+    private void setDirectReference(ASN1ObjectIdentifier directReferemce)
+    {
+        this.directReference = directReferemce;
+    }
+    
+    /**
+     * Sets the encoding of the content. Valid values are
+     * <ul>
+     * <li><code>0</code> single-ASN1-type</li>
+     * <li><code>1</code> OCTET STRING</li>
+     * <li><code>2</code> BIT STRING</li>
+     * </ul>
+     * @param encoding The encoding
+     */
+    private void setEncoding(int encoding)
+    {
+        if (encoding < 0 || encoding > 2)
+        {
+            throw new IllegalArgumentException("invalid encoding value: " + encoding);
+        }
+        this.encoding = encoding;
+    }
+    
+    /**
+     * Sets the content of this element
+     * @param externalContent The content
+     */
+    private void setExternalContent(ASN1Primitive externalContent)
+    {
+        this.externalContent = externalContent;
+    }
+    
+    /**
+     * Sets the indirect reference of this element
+     * @param indirectReference The reference
+     */
+    private void setIndirectReference(ASN1Integer indirectReference)
+    {
+        this.indirectReference = indirectReference;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1GeneralizedTime.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1GeneralizedTime.java
new file mode 100644
index 0000000..a0b6d44
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1GeneralizedTime.java
@@ -0,0 +1,476 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+// Android-added: Localization support
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.SimpleTimeZone;
+import java.util.TimeZone;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * Base class representing the ASN.1 GeneralizedTime type.
+ * <p>
+ * The main difference between these and UTC time is a 4 digit year.
+ * </p>
+ * <p>
+ * One second resolution date+time on UTC timezone (Z)
+ * with 4 digit year (valid from 0001 to 9999).
+ * </p><p>
+ * Timestamp format is:  yyyymmddHHMMSS'Z'
+ * </p><p>
+ * <h2>X.690</h2>
+ * This is what is called "restricted string",
+ * and it uses ASCII characters to encode digits and supplemental data.
+ *
+ * <h3>11: Restrictions on BER employed by both CER and DER</h3>
+ * <h4>11.7 GeneralizedTime </h4>
+ * <p>
+ * <b>11.7.1</b> The encoding shall terminate with a "Z",
+ * as described in the ITU-T Rec. X.680 | ISO/IEC 8824-1 clause on
+ * GeneralizedTime.
+ * </p><p>
+ * <b>11.7.2</b> The seconds element shall always be present.
+ * </p>
+ * <p>
+ * <b>11.7.3</b> The fractional-seconds elements, if present,
+ * shall omit all trailing zeros; if the elements correspond to 0,
+ * they shall be wholly omitted, and the decimal point element also
+ * shall be omitted.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1GeneralizedTime
+    extends ASN1Primitive
+{
+    protected byte[] time;
+
+    /**
+     * return a generalized time from the passed in object
+     *
+     * @param obj an ASN1GeneralizedTime or an object that can be converted into one.
+     * @return an ASN1GeneralizedTime instance, or null.
+     * @throws IllegalArgumentException if the object cannot be converted.
+     */
+    public static ASN1GeneralizedTime getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof ASN1GeneralizedTime)
+        {
+            return (ASN1GeneralizedTime)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (ASN1GeneralizedTime)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a Generalized Time object from a tagged object.
+     *
+     * @param obj      the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *                 tagged false otherwise.
+     * @return an ASN1GeneralizedTime instance.
+     * @throws IllegalArgumentException if the tagged object cannot
+     * be converted.
+     */
+    public static ASN1GeneralizedTime getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof ASN1GeneralizedTime)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new ASN1GeneralizedTime(((ASN1OctetString)o).getOctets());
+        }
+    }
+
+    /**
+     * The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
+     * for local time, or Z+-HHMM on the end, for difference between local
+     * time and UTC time. The fractional second amount f must consist of at
+     * least one number with trailing zeroes removed.
+     *
+     * @param time the time string.
+     * @throws IllegalArgumentException if String is an illegal format.
+     */
+    public ASN1GeneralizedTime(
+        String time)
+    {
+        this.time = Strings.toByteArray(time);
+        try
+        {
+            this.getDate();
+        }
+        catch (ParseException e)
+        {
+            throw new IllegalArgumentException("invalid date string: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Base constructor from a java.util.date object
+     *
+     * @param time a date object representing the time of interest.
+     */
+    public ASN1GeneralizedTime(
+        Date time)
+    {
+        // Android-changed: Use localized version
+        // SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", DateUtil.EN_Locale);
+        SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.US);
+
+        dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+
+        this.time = Strings.toByteArray(dateF.format(time));
+    }
+
+    /**
+     * Base constructor from a java.util.date and Locale - you may need to use this if the default locale
+     * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations.
+     *
+     * @param time a date object representing the time of interest.
+     * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value.
+     */
+    public ASN1GeneralizedTime(
+        Date time,
+        Locale locale)
+    {
+        // BEGIN Android-changed: Use localized version
+        // SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", locale);
+        SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.US);
+        dateF.setCalendar(Calendar.getInstance(Locale.US));
+        // END Android-changed: Use localized version
+
+        dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+
+        this.time = Strings.toByteArray(dateF.format(time));
+    }
+
+    ASN1GeneralizedTime(
+        byte[] bytes)
+    {
+        this.time = bytes;
+    }
+
+    /**
+     * Return the time.
+     *
+     * @return The time string as it appeared in the encoded object.
+     */
+    public String getTimeString()
+    {
+        return Strings.fromByteArray(time);
+    }
+
+    /**
+     * return the time - always in the form of
+     * YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+     * <p>
+     * Normally in a certificate we would expect "Z" rather than "GMT",
+     * however adding the "GMT" means we can just use:
+     * <pre>
+     *     dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+     * </pre>
+     * To read in the time and get a date which is compatible with our local
+     * time zone.
+     * @return a String representation of the time.
+     */
+    public String getTime()
+    {
+        String stime = Strings.fromByteArray(time);
+
+        //
+        // standardise the format.
+        //
+        if (stime.charAt(stime.length() - 1) == 'Z')
+        {
+            return stime.substring(0, stime.length() - 1) + "GMT+00:00";
+        }
+        else
+        {
+            int signPos = stime.length() - 5;
+            char sign = stime.charAt(signPos);
+            if (sign == '-' || sign == '+')
+            {
+                return stime.substring(0, signPos)
+                    + "GMT"
+                    + stime.substring(signPos, signPos + 3)
+                    + ":"
+                    + stime.substring(signPos + 3);
+            }
+            else
+            {
+                signPos = stime.length() - 3;
+                sign = stime.charAt(signPos);
+                if (sign == '-' || sign == '+')
+                {
+                    return stime.substring(0, signPos)
+                        + "GMT"
+                        + stime.substring(signPos)
+                        + ":00";
+                }
+            }
+        }
+        return stime + calculateGMTOffset();
+    }
+
+    private String calculateGMTOffset()
+    {
+        String sign = "+";
+        TimeZone timeZone = TimeZone.getDefault();
+        int offset = timeZone.getRawOffset();
+        if (offset < 0)
+        {
+            sign = "-";
+            offset = -offset;
+        }
+        int hours = offset / (60 * 60 * 1000);
+        int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000);
+
+        try
+        {
+            if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate()))
+            {
+                hours += sign.equals("+") ? 1 : -1;
+            }
+        }
+        catch (ParseException e)
+        {
+            // we'll do our best and ignore daylight savings
+        }
+
+        return "GMT" + sign + convert(hours) + ":" + convert(minutes);
+    }
+
+    private String convert(int time)
+    {
+        if (time < 10)
+        {
+            return "0" + time;
+        }
+
+        return Integer.toString(time);
+    }
+
+    public Date getDate()
+        throws ParseException
+    {
+        SimpleDateFormat dateF;
+        String stime = Strings.fromByteArray(time);
+        String d = stime;
+
+        if (stime.endsWith("Z"))
+        {
+            if (hasFractionalSeconds())
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'");
+                dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'", Locale.US);
+            }
+            else if (hasSeconds())
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
+                dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.US);
+            }
+            else if (hasMinutes())
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHHmm'Z'");
+                dateF = new SimpleDateFormat("yyyyMMddHHmm'Z'", Locale.US);
+            }
+            else
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHH'Z'");
+                dateF = new SimpleDateFormat("yyyyMMddHH'Z'", Locale.US);
+            }
+
+            dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+        }
+        else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0)
+        {
+            d = this.getTime();
+            if (hasFractionalSeconds())
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz");
+                dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz", Locale.US);
+            }
+            else if (hasSeconds())
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+                dateF = new SimpleDateFormat("yyyyMMddHHmmssz", Locale.US);
+            }
+            else if (hasMinutes())
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHHmmz");
+                dateF = new SimpleDateFormat("yyyyMMddHHmmz", Locale.US);
+            }
+            else
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHHz");
+                dateF = new SimpleDateFormat("yyyyMMddHHz", Locale.US);
+            }
+
+            dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+        }
+        else
+        {
+            if (hasFractionalSeconds())
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
+                dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS", Locale.US);
+            }
+            else if (hasSeconds())
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHHmmss");
+                dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
+            }
+            else if (hasMinutes())
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHHmm");
+                dateF = new SimpleDateFormat("yyyyMMddHHmm", Locale.US);
+            }
+            else
+            {
+                // Android-changed: Use localized version
+                // dateF = new SimpleDateFormat("yyyyMMddHH");
+                dateF = new SimpleDateFormat("yyyyMMddHH", Locale.US);
+            }
+
+            dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
+        }
+
+        if (hasFractionalSeconds())
+        {
+            // java misinterprets extra digits as being milliseconds...
+            String frac = d.substring(14);
+            int index;
+            for (index = 1; index < frac.length(); index++)
+            {
+                char ch = frac.charAt(index);
+                if (!('0' <= ch && ch <= '9'))
+                {
+                    break;
+                }
+            }
+
+            if (index - 1 > 3)
+            {
+                frac = frac.substring(0, 4) + frac.substring(index);
+                d = d.substring(0, 14) + frac;
+            }
+            else if (index - 1 == 1)
+            {
+                frac = frac.substring(0, index) + "00" + frac.substring(index);
+                d = d.substring(0, 14) + frac;
+            }
+            else if (index - 1 == 2)
+            {
+                frac = frac.substring(0, index) + "0" + frac.substring(index);
+                d = d.substring(0, 14) + frac;
+            }
+        }
+
+        return DateUtil.epochAdjust(dateF.parse(d));
+    }
+
+    protected boolean hasFractionalSeconds()
+    {
+        for (int i = 0; i != time.length; i++)
+        {
+            if (time[i] == '.')
+            {
+                if (i == 14)
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    protected boolean hasSeconds()
+    {
+        return isDigit(12) && isDigit(13);
+    }
+
+    protected boolean hasMinutes()
+    {
+        return isDigit(10) && isDigit(11);
+    }
+
+    private boolean isDigit(int pos)
+    {
+        return time.length > pos && time[pos] >= '0' && time[pos] <= '9';
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        int length = time.length;
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.GENERALIZED_TIME, time);
+    }
+
+    ASN1Primitive toDERObject()
+    {
+        return new DERGeneralizedTime(time);
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof ASN1GeneralizedTime))
+        {
+            return false;
+        }
+
+        return Arrays.areEqual(time, ((ASN1GeneralizedTime)o).time);
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(time);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Generator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Generator.java
new file mode 100644
index 0000000..43af521
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Generator.java
@@ -0,0 +1,30 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.OutputStream;
+
+/**
+ * Basic class for streaming generators.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ASN1Generator
+{
+    protected OutputStream _out;
+
+    /**
+     * Base constructor.
+     *
+     * @param out the end output stream that object encodings are written to.
+     */
+    public ASN1Generator(OutputStream out)
+    {
+        _out = out;
+    }
+
+    /**
+     * Return the actual stream object encodings are written to.
+     *
+     * @return the stream that is directly encoded to.
+     */
+    public abstract OutputStream getRawOutputStream();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1InputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1InputStream.java
new file mode 100644
index 0000000..3b3e9bc
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1InputStream.java
@@ -0,0 +1,478 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.android.internal.org.bouncycastle.util.io.Streams;
+
+/**
+ * A general purpose ASN.1 decoder - note: this class differs from the
+ * others in that it returns null after it has read the last object in
+ * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
+ * returned.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1InputStream
+    extends FilterInputStream
+    implements BERTags
+{
+    private final int limit;
+    private final boolean lazyEvaluate;
+
+    private final byte[][] tmpBuffers;
+
+    public ASN1InputStream(
+        InputStream is)
+    {
+        this(is, StreamUtil.findLimit(is));
+    }
+
+    /**
+     * Create an ASN1InputStream based on the input byte array. The length of DER objects in
+     * the stream is automatically limited to the length of the input array.
+     * 
+     * @param input array containing ASN.1 encoded data.
+     */
+    public ASN1InputStream(
+        byte[] input)
+    {
+        this(new ByteArrayInputStream(input), input.length);
+    }
+
+    /**
+     * Create an ASN1InputStream based on the input byte array. The length of DER objects in
+     * the stream is automatically limited to the length of the input array.
+     *
+     * @param input array containing ASN.1 encoded data.
+     * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
+     */
+    public ASN1InputStream(
+        byte[] input,
+        boolean lazyEvaluate)
+    {
+        this(new ByteArrayInputStream(input), input.length, lazyEvaluate);
+    }
+    
+    /**
+     * Create an ASN1InputStream where no DER object will be longer than limit.
+     * 
+     * @param input stream containing ASN.1 encoded data.
+     * @param limit maximum size of a DER encoded object.
+     */
+    public ASN1InputStream(
+        InputStream input,
+        int         limit)
+    {
+        this(input, limit, false);
+    }
+
+    /**
+     * Create an ASN1InputStream where no DER object will be longer than limit, and constructed
+     * objects such as sequences will be parsed lazily.
+     *
+     * @param input stream containing ASN.1 encoded data.
+     * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
+     */
+    public ASN1InputStream(
+        InputStream input,
+        boolean     lazyEvaluate)
+    {
+        this(input, StreamUtil.findLimit(input), lazyEvaluate);
+    }
+
+    /**
+     * Create an ASN1InputStream where no DER object will be longer than limit, and constructed
+     * objects such as sequences will be parsed lazily.
+     *
+     * @param input stream containing ASN.1 encoded data.
+     * @param limit maximum size of a DER encoded object.
+     * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
+     */
+    public ASN1InputStream(
+        InputStream input,
+        int         limit,
+        boolean     lazyEvaluate)
+    {
+        super(input);
+        this.limit = limit;
+        this.lazyEvaluate = lazyEvaluate;
+        this.tmpBuffers = new byte[11][];
+    }
+
+    int getLimit()
+    {
+        return limit;
+    }
+
+    protected int readLength()
+        throws IOException
+    {
+        return readLength(this, limit);
+    }
+
+    protected void readFully(
+        byte[]  bytes)
+        throws IOException
+    {
+        if (Streams.readFully(this, bytes) != bytes.length)
+        {
+            throw new EOFException("EOF encountered in middle of object");
+        }
+    }
+
+    /**
+     * build an object given its tag and the number of bytes to construct it from.
+     *
+     * @param tag the full tag details.
+     * @param tagNo the tagNo defined.
+     * @param length the length of the object.
+     * @return the resulting primitive.
+     * @throws java.io.IOException on processing exception.
+     */
+    protected ASN1Primitive buildObject(
+        int       tag,
+        int       tagNo,
+        int       length)
+        throws IOException
+    {
+        boolean isConstructed = (tag & CONSTRUCTED) != 0;
+
+        DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length);
+
+        if ((tag & APPLICATION) != 0)
+        {
+            return new DLApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
+        }
+
+        if ((tag & TAGGED) != 0)
+        {
+            return new ASN1StreamParser(defIn).readTaggedObject(isConstructed, tagNo);
+        }
+
+        if (isConstructed)
+        {
+            // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+            switch (tagNo)
+            {
+                case OCTET_STRING:
+                    //
+                    // yes, people actually do this...
+                    //
+                    ASN1EncodableVector v = buildDEREncodableVector(defIn);
+                    ASN1OctetString[] strings = new ASN1OctetString[v.size()];
+
+                    for (int i = 0; i != strings.length; i++)
+                    {
+                        strings[i] = (ASN1OctetString)v.get(i);
+                    }
+
+                    return new BEROctetString(strings);
+                case SEQUENCE:
+                    if (lazyEvaluate)
+                    {
+                        return new LazyEncodedSequence(defIn.toByteArray());
+                    }
+                    else
+                    {
+                        return DERFactory.createSequence(buildDEREncodableVector(defIn));   
+                    }
+                case SET:
+                    return DERFactory.createSet(buildDEREncodableVector(defIn));
+                case EXTERNAL:
+                    return new DLExternal(buildDEREncodableVector(defIn));
+                default:
+                    throw new IOException("unknown tag " + tagNo + " encountered");
+            }
+        }
+
+        return createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
+    }
+
+    ASN1EncodableVector buildEncodableVector()
+        throws IOException
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        ASN1Primitive o;
+
+        while ((o = readObject()) != null)
+        {
+            v.add(o);
+        }
+
+        return v;
+    }
+
+    ASN1EncodableVector buildDEREncodableVector(
+        DefiniteLengthInputStream dIn) throws IOException
+    {
+        return new ASN1InputStream(dIn).buildEncodableVector();
+    }
+
+    public ASN1Primitive readObject()
+        throws IOException
+    {
+        int tag = read();
+        if (tag <= 0)
+        {
+            if (tag == 0)
+            {
+                throw new IOException("unexpected end-of-contents marker");
+            }
+
+            return null;
+        }
+
+        //
+        // calculate tag number
+        //
+        int tagNo = readTagNumber(this, tag);
+
+        boolean isConstructed = (tag & CONSTRUCTED) != 0;
+
+        //
+        // calculate length
+        //
+        int length = readLength();
+
+        if (length < 0) // indefinite-length method
+        {
+            if (!isConstructed)
+            {
+                throw new IOException("indefinite-length primitive encoding encountered");
+            }
+
+            IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit);
+            ASN1StreamParser sp = new ASN1StreamParser(indIn, limit);
+
+            if ((tag & APPLICATION) != 0)
+            {
+                return new BERApplicationSpecificParser(tagNo, sp).getLoadedObject();
+            }
+
+            if ((tag & TAGGED) != 0)
+            {
+                return new BERTaggedObjectParser(true, tagNo, sp).getLoadedObject();
+            }
+
+            // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+            switch (tagNo)
+            {
+                case OCTET_STRING:
+                    return new BEROctetStringParser(sp).getLoadedObject();
+                case SEQUENCE:
+                    return new BERSequenceParser(sp).getLoadedObject();
+                case SET:
+                    return new BERSetParser(sp).getLoadedObject();
+                case EXTERNAL:
+                    return new DERExternalParser(sp).getLoadedObject();
+                default:
+                    throw new IOException("unknown BER object encountered");
+            }
+        }
+        else
+        {
+            try
+            {
+                return buildObject(tag, tagNo, length);
+            }
+            catch (IllegalArgumentException e)
+            {
+                throw new ASN1Exception("corrupted stream detected", e);
+            }
+        }
+    }
+
+    static int readTagNumber(InputStream s, int tag) 
+        throws IOException
+    {
+        int tagNo = tag & 0x1f;
+
+        //
+        // with tagged object tag number is bottom 5 bits, or stored at the start of the content
+        //
+        if (tagNo == 0x1f)
+        {
+            tagNo = 0;
+
+            int b = s.read();
+
+            // X.690-0207 8.1.2.4.2
+            // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
+            if ((b & 0x7f) == 0) // Note: -1 will pass
+            {
+                throw new IOException("corrupted stream - invalid high tag number found");
+            }
+
+            while ((b >= 0) && ((b & 0x80) != 0))
+            {
+                tagNo |= (b & 0x7f);
+                tagNo <<= 7;
+                b = s.read();
+            }
+
+            if (b < 0)
+            {
+                throw new EOFException("EOF found inside tag value.");
+            }
+            
+            tagNo |= (b & 0x7f);
+        }
+        
+        return tagNo;
+    }
+
+    static int readLength(InputStream s, int limit)
+        throws IOException
+    {
+        int length = s.read();
+        if (length < 0)
+        {
+            throw new EOFException("EOF found when length expected");
+        }
+
+        if (length == 0x80)
+        {
+            return -1;      // indefinite-length encoding
+        }
+
+        if (length > 127)
+        {
+            int size = length & 0x7f;
+
+            // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
+            if (size > 4)
+            {
+                throw new IOException("DER length more than 4 bytes: " + size);
+            }
+
+            length = 0;
+            for (int i = 0; i < size; i++)
+            {
+                int next = s.read();
+
+                if (next < 0)
+                {
+                    throw new EOFException("EOF found reading length");
+                }
+
+                length = (length << 8) + next;
+            }
+
+            if (length < 0)
+            {
+                throw new IOException("corrupted stream - negative length found");
+            }
+
+            if (length >= limit)   // after all we must have read at least 1 byte
+            {
+                throw new IOException("corrupted stream - out of bounds length found");
+            }
+        }
+
+        return length;
+    }
+
+    private static byte[] getBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
+        throws IOException
+    {
+        int len = defIn.getRemaining();
+        if (defIn.getRemaining() < tmpBuffers.length)
+        {
+            byte[] buf = tmpBuffers[len];
+
+            if (buf == null)
+            {
+                buf = tmpBuffers[len] = new byte[len];
+            }
+
+            Streams.readFully(defIn, buf);
+
+            return buf;
+        }
+        else
+        {
+            return defIn.toByteArray();
+        }
+    }
+
+    private static char[] getBMPCharBuffer(DefiniteLengthInputStream defIn)
+        throws IOException
+    {
+        int len = defIn.getRemaining() / 2;
+        char[] buf = new char[len];
+        int totalRead = 0;
+        while (totalRead < len)
+        {
+            int ch1 = defIn.read();
+            if (ch1 < 0)
+            {
+                break;
+            }
+            int ch2 = defIn.read();
+            if (ch2 < 0)
+            {
+                break;
+            }
+            buf[totalRead++] = (char)((ch1 << 8) | (ch2 & 0xff));
+        }
+
+        return buf;
+    }
+
+    static ASN1Primitive createPrimitiveDERObject(
+        int     tagNo,
+        DefiniteLengthInputStream defIn,
+        byte[][] tmpBuffers)
+        throws IOException
+    {
+        switch (tagNo)
+        {
+            case BIT_STRING:
+                return ASN1BitString.fromInputStream(defIn.getRemaining(), defIn);
+            case BMP_STRING:
+                return new DERBMPString(getBMPCharBuffer(defIn));
+            case BOOLEAN:
+                return ASN1Boolean.fromOctetString(getBuffer(defIn, tmpBuffers));
+            case ENUMERATED:
+                return ASN1Enumerated.fromOctetString(getBuffer(defIn, tmpBuffers));
+            case GENERALIZED_TIME:
+                return new ASN1GeneralizedTime(defIn.toByteArray());
+            case GENERAL_STRING:
+                return new DERGeneralString(defIn.toByteArray());
+            case IA5_STRING:
+                return new DERIA5String(defIn.toByteArray());
+            case INTEGER:
+                return new ASN1Integer(defIn.toByteArray(), false);
+            case NULL:
+                return DERNull.INSTANCE;   // actual content is ignored (enforce 0 length?)
+            case NUMERIC_STRING:
+                return new DERNumericString(defIn.toByteArray());
+            case OBJECT_IDENTIFIER:
+                return ASN1ObjectIdentifier.fromOctetString(getBuffer(defIn, tmpBuffers));
+            case OCTET_STRING:
+                return new DEROctetString(defIn.toByteArray());
+            case PRINTABLE_STRING:
+                return new DERPrintableString(defIn.toByteArray());
+            case T61_STRING:
+                return new DERT61String(defIn.toByteArray());
+            case UNIVERSAL_STRING:
+                return new DERUniversalString(defIn.toByteArray());
+            case UTC_TIME:
+                return new ASN1UTCTime(defIn.toByteArray());
+            case UTF8_STRING:
+                return new DERUTF8String(defIn.toByteArray());
+            case VISIBLE_STRING:
+                return new DERVisibleString(defIn.toByteArray());
+            case GRAPHIC_STRING:
+                return new DERGraphicString(defIn.toByteArray());
+            case VIDEOTEX_STRING:
+                return new DERVideotexString(defIn.toByteArray());
+            default:
+                throw new IOException("unknown tag " + tagNo + " encountered");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Integer.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Integer.java
new file mode 100644
index 0000000..692ae8f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Integer.java
@@ -0,0 +1,224 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Properties;
+
+/**
+ * Class representing the ASN.1 INTEGER type.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1Integer
+    extends ASN1Primitive
+{
+    private final byte[] bytes;
+
+    /**
+     * Return an integer from the passed in object.
+     *
+     * @param obj an ASN1Integer or an object that can be converted into one.
+     * @return an ASN1Integer instance.
+     * @throws IllegalArgumentException if the object cannot be converted.
+     */
+    public static ASN1Integer getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof ASN1Integer)
+        {
+            return (ASN1Integer)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (ASN1Integer)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return an Integer from a tagged object.
+     *
+     * @param obj      the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *                 tagged false otherwise.
+     * @return an ASN1Integer instance.
+     * @throws IllegalArgumentException if the tagged object cannot
+     * be converted.
+     */
+    public static ASN1Integer getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof ASN1Integer)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new ASN1Integer(ASN1OctetString.getInstance(o).getOctets());
+        }
+    }
+
+    /**
+     * Construct an INTEGER from the passed in long value.
+     *
+     * @param value the long representing the value desired.
+     */
+    public ASN1Integer(
+        long value)
+    {
+        bytes = BigInteger.valueOf(value).toByteArray();
+    }
+
+    /**
+     * Construct an INTEGER from the passed in BigInteger value.
+     *
+     * @param value the BigInteger representing the value desired.
+     */
+    public ASN1Integer(
+        BigInteger value)
+    {
+        bytes = value.toByteArray();
+    }
+
+    /**
+     * Construct an INTEGER from the passed in byte array.
+     *
+     * <p>
+     * <b>NB: Strict Validation applied by default.</b>
+     * </p>
+     * <p>
+     * It has turned out that there are still a few applications that struggle with
+     * the ASN.1 BER encoding rules for an INTEGER as described in:
+     *
+     * https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
+     * Section 8.3.2.
+     * </p>
+     * <p>
+     * Users can set the 'org.bouncycastle.asn1.allow_unsafe_integer' to 'true'
+     * and a looser validation will be applied. Users must recognise that this is
+     * not ideal and may pave the way for an exploit based around a faulty encoding
+     * in the future.
+     * </p>
+     *
+     * @param bytes the byte array representing a 2's complement encoding of a BigInteger.
+     */
+    public ASN1Integer(
+        byte[] bytes)
+    {
+        this(bytes, true);
+    }
+
+    ASN1Integer(byte[] bytes, boolean clone)
+    {
+        // Apply loose validation, see note in public constructor ANS1Integer(byte[])
+        if (!Properties.isOverrideSet("com.android.internal.org.bouncycastle.asn1.allow_unsafe_integer"))
+        {
+            if (isMalformed(bytes))
+            {                           
+                throw new IllegalArgumentException("malformed integer");
+            }
+        }
+        this.bytes = (clone) ? Arrays.clone(bytes) : bytes;
+    }
+
+    /**
+     * Apply the correct validation for an INTEGER primitive following the BER rules.
+     *
+     * @param bytes The raw encoding of the integer.
+     * @return true if the (in)put fails this validation.
+     */
+    static boolean isMalformed(byte[] bytes)
+    {
+        if (bytes.length > 1)
+        {
+            if (bytes[0] == 0 && (bytes[1] & 0x80) == 0)
+            {
+                return true;
+            }
+            if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0)
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public BigInteger getValue()
+    {
+        return new BigInteger(bytes);
+    }
+
+    /**
+     * in some cases positive values get crammed into a space,
+     * that's not quite big enough...
+     *
+     * @return the BigInteger that results from treating this ASN.1 INTEGER as unsigned.
+     */
+    public BigInteger getPositiveValue()
+    {
+        return new BigInteger(1, bytes);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.INTEGER, bytes);
+    }
+
+    public int hashCode()
+    {
+        int value = 0;
+
+        for (int i = 0; i != bytes.length; i++)
+        {
+            value ^= (bytes[i] & 0xff) << (i % 4);
+        }
+
+        return value;
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof ASN1Integer))
+        {
+            return false;
+        }
+
+        ASN1Integer other = (ASN1Integer)o;
+
+        return Arrays.areEqual(bytes, other.bytes);
+    }
+
+    public String toString()
+    {
+        return getValue().toString();
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Null.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Null.java
new file mode 100644
index 0000000..e8840f7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Null.java
@@ -0,0 +1,85 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/***************************************************************/
+/******    DO NOT EDIT THIS CLASS bc-java SOURCE FILE     ******/
+/***************************************************************/
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * A NULL object - use DERNull.INSTANCE for populating structures.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ASN1Null
+    extends ASN1Primitive
+{
+    ASN1Null()
+    {
+
+    }
+
+    /**
+     * Return an instance of ASN.1 NULL from the passed in object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link ASN1Null} object
+     * <li> a byte[] containing ASN.1 NULL object
+     * </ul>
+     * </p>
+     *
+     * @param o object to be converted.
+     * @return an instance of ASN1Null, or null.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static ASN1Null getInstance(Object o)
+    {
+        if (o instanceof ASN1Null)
+        {
+            return (ASN1Null)o;
+        }
+
+        if (o != null)
+        {
+            try
+            {
+                return ASN1Null.getInstance(ASN1Primitive.fromByteArray((byte[])o));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct NULL from byte[]: " + e.getMessage());
+            }
+            catch (ClassCastException e)
+            {
+                throw new IllegalArgumentException("unknown object in getInstance(): " + o.getClass().getName());
+            }
+        }
+
+        return null;
+    }
+
+    public int hashCode()
+    {
+        return -1;
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof ASN1Null))
+        {
+            return false;
+        }
+        
+        return true;
+    }
+
+    abstract void encode(ASN1OutputStream out)
+        throws IOException;
+
+    public String toString()
+    {
+         return "NULL";
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Object.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Object.java
new file mode 100644
index 0000000..5d58b5e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Object.java
@@ -0,0 +1,115 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Encodable;
+
+/**
+ * Base class for defining an ASN.1 object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ASN1Object
+    implements ASN1Encodable, Encodable
+{
+    /**
+     * Return the default BER or DER encoding for this object.
+     *
+     * @return BER/DER byte encoded object.
+     * @throws java.io.IOException on encoding error.
+     */
+    public byte[] getEncoded()
+        throws IOException
+    {
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        ASN1OutputStream      aOut = new ASN1OutputStream(bOut);
+
+        aOut.writeObject(this);
+
+        return bOut.toByteArray();
+    }
+
+    /**
+     * Return either the default for "BER" or a DER encoding if "DER" is specified.
+     *
+     * @param encoding name of encoding to use.
+     * @return byte encoded object.
+     * @throws IOException on encoding error.
+     */
+    public byte[] getEncoded(
+        String encoding)
+        throws IOException
+    {
+        if (encoding.equals(ASN1Encoding.DER))
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(this);
+
+            return bOut.toByteArray();
+        }
+        else if (encoding.equals(ASN1Encoding.DL))
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DLOutputStream          dOut = new DLOutputStream(bOut);
+
+            dOut.writeObject(this);
+
+            return bOut.toByteArray();
+        }
+
+        return this.getEncoded();
+    }
+
+    public int hashCode()
+    {
+        return this.toASN1Primitive().hashCode();
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+
+        if (!(o instanceof ASN1Encodable))
+        {
+            return false;
+        }
+
+        ASN1Encodable other = (ASN1Encodable)o;
+
+        return this.toASN1Primitive().equals(other.toASN1Primitive());
+    }
+
+    /**
+     * @deprecated use toASN1Primitive()
+     * @return the underlying primitive type.
+     */
+    public ASN1Primitive toASN1Object()
+    {
+        return this.toASN1Primitive();
+    }
+
+    /**
+     * Return true if obj is a byte array and represents an object with the given tag value.
+     *
+     * @param obj object of interest.
+     * @param tagValue tag value to check for.
+     * @return  true if obj is a byte encoding starting with the given tag value, false otherwise.
+     */
+    protected static boolean hasEncodedTagValue(Object obj, int tagValue)
+    {
+        return (obj instanceof byte[]) && ((byte[])obj)[0] == tagValue;
+    }
+
+    /**
+     * Method providing a primitive representation of this object suitable for encoding.
+     * @return a primitive representation of this object.
+     */
+    public abstract ASN1Primitive toASN1Primitive();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
new file mode 100644
index 0000000..f92cceb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
@@ -0,0 +1,486 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * Class representing the ASN.1 OBJECT IDENTIFIER type.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1ObjectIdentifier
+    extends ASN1Primitive
+{
+    private final String identifier;
+
+    private byte[] body;
+
+    /**
+     * Return an OID from the passed in object
+     *
+     * @param obj an ASN1ObjectIdentifier or an object that can be converted into one.
+     * @return an ASN1ObjectIdentifier instance, or null.
+     * @throws IllegalArgumentException if the object cannot be converted.
+     */
+    public static ASN1ObjectIdentifier getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof ASN1ObjectIdentifier)
+        {
+            return (ASN1ObjectIdentifier)obj;
+        }
+
+        if (obj instanceof ASN1Encodable)
+        {
+            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+            if (primitive instanceof ASN1ObjectIdentifier)
+            {
+                return (ASN1ObjectIdentifier)primitive;
+            }
+        }
+
+        if (obj instanceof byte[])
+        {
+            byte[] enc = (byte[])obj;
+            try
+            {
+                return (ASN1ObjectIdentifier)fromByteArray(enc);
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct object identifier from byte[]: " + e.getMessage());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return an OBJECT IDENTIFIER from a tagged object.
+     *
+     * @param obj      the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *                 tagged false otherwise.
+     * @return an ASN1ObjectIdentifier instance, or null.
+     * @throws IllegalArgumentException if the tagged object cannot
+     * be converted.
+     */
+    public static ASN1ObjectIdentifier getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof ASN1ObjectIdentifier)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(o).getOctets());
+        }
+    }
+
+    private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f;
+
+    ASN1ObjectIdentifier(
+        byte[] bytes)
+    {
+        StringBuffer objId = new StringBuffer();
+        long value = 0;
+        BigInteger bigValue = null;
+        boolean first = true;
+
+        for (int i = 0; i != bytes.length; i++)
+        {
+            int b = bytes[i] & 0xff;
+
+            if (value <= LONG_LIMIT)
+            {
+                value += (b & 0x7f);
+                if ((b & 0x80) == 0)             // end of number reached
+                {
+                    if (first)
+                    {
+                        if (value < 40)
+                        {
+                            objId.append('0');
+                        }
+                        else if (value < 80)
+                        {
+                            objId.append('1');
+                            value -= 40;
+                        }
+                        else
+                        {
+                            objId.append('2');
+                            value -= 80;
+                        }
+                        first = false;
+                    }
+
+                    objId.append('.');
+                    objId.append(value);
+                    value = 0;
+                }
+                else
+                {
+                    value <<= 7;
+                }
+            }
+            else
+            {
+                if (bigValue == null)
+                {
+                    bigValue = BigInteger.valueOf(value);
+                }
+                bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
+                if ((b & 0x80) == 0)
+                {
+                    if (first)
+                    {
+                        objId.append('2');
+                        bigValue = bigValue.subtract(BigInteger.valueOf(80));
+                        first = false;
+                    }
+
+                    objId.append('.');
+                    objId.append(bigValue);
+                    bigValue = null;
+                    value = 0;
+                }
+                else
+                {
+                    bigValue = bigValue.shiftLeft(7);
+                }
+            }
+        }
+
+        // Android-changed: Intern the identifier so there aren't hundreds of duplicates in practice.
+        this.identifier = objId.toString().intern();
+        this.body = Arrays.clone(bytes);
+    }
+
+    /**
+     * Create an OID based on the passed in String.
+     *
+     * @param identifier a string representation of an OID.
+     */
+    public ASN1ObjectIdentifier(
+        String identifier)
+    {
+        if (identifier == null)
+        {
+            throw new IllegalArgumentException("'identifier' cannot be null");
+        }
+        if (!isValidIdentifier(identifier))
+        {
+            throw new IllegalArgumentException("string " + identifier + " not an OID");
+        }
+
+        // Android-changed: Intern the identifier so there aren't hundreds of duplicates in practice.
+        this.identifier = identifier.intern();
+    }
+
+    /**
+     * Create an OID that creates a branch under the current one.
+     *
+     * @param branchID node numbers for the new branch.
+     * @return the OID for the new created branch.
+     */
+    ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branchID)
+    {
+        if (!isValidBranchID(branchID, 0))
+        {
+            throw new IllegalArgumentException("string " + branchID + " not a valid OID branch");
+        }
+
+        this.identifier = oid.getId() + "." + branchID;
+    }
+
+    /**
+     * Return the OID as a string.
+     *
+     * @return the string representation of the OID carried by this object.
+     */
+    public String getId()
+    {
+        return identifier;
+    }
+
+    /**
+     * Return an OID that creates a branch under the current one.
+     *
+     * @param branchID node numbers for the new branch.
+     * @return the OID for the new created branch.
+     */
+    public ASN1ObjectIdentifier branch(String branchID)
+    {
+        return new ASN1ObjectIdentifier(this, branchID);
+    }
+
+    /**
+     * Return true if this oid is an extension of the passed in branch - stem.
+     *
+     * @param stem the arc or branch that is a possible parent.
+     * @return true if the branch is on the passed in stem, false otherwise.
+     */
+    public boolean on(ASN1ObjectIdentifier stem)
+    {
+        String id = getId(), stemId = stem.getId();
+        return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId);
+    }
+
+    private void writeField(
+        ByteArrayOutputStream out,
+        long fieldValue)
+    {
+        byte[] result = new byte[9];
+        int pos = 8;
+        result[pos] = (byte)((int)fieldValue & 0x7f);
+        while (fieldValue >= (1L << 7))
+        {
+            fieldValue >>= 7;
+            result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80);
+        }
+        out.write(result, pos, 9 - pos);
+    }
+
+    private void writeField(
+        ByteArrayOutputStream out,
+        BigInteger fieldValue)
+    {
+        int byteCount = (fieldValue.bitLength() + 6) / 7;
+        if (byteCount == 0)
+        {
+            out.write(0);
+        }
+        else
+        {
+            BigInteger tmpValue = fieldValue;
+            byte[] tmp = new byte[byteCount];
+            for (int i = byteCount - 1; i >= 0; i--)
+            {
+                tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80);
+                tmpValue = tmpValue.shiftRight(7);
+            }
+            tmp[byteCount - 1] &= 0x7f;
+            out.write(tmp, 0, tmp.length);
+        }
+    }
+
+    private void doOutput(ByteArrayOutputStream aOut)
+    {
+        OIDTokenizer tok = new OIDTokenizer(identifier);
+        int first = Integer.parseInt(tok.nextToken()) * 40;
+
+        String secondToken = tok.nextToken();
+        if (secondToken.length() <= 18)
+        {
+            writeField(aOut, first + Long.parseLong(secondToken));
+        }
+        else
+        {
+            writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first)));
+        }
+
+        while (tok.hasMoreTokens())
+        {
+            String token = tok.nextToken();
+            if (token.length() <= 18)
+            {
+                writeField(aOut, Long.parseLong(token));
+            }
+            else
+            {
+                writeField(aOut, new BigInteger(token));
+            }
+        }
+    }
+
+    private synchronized byte[] getBody()
+    {
+        if (body == null)
+        {
+            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+            doOutput(bOut);
+
+            body = bOut.toByteArray();
+        }
+
+        return body;
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = getBody().length;
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        byte[] enc = getBody();
+
+        out.write(BERTags.OBJECT_IDENTIFIER);
+        out.writeLength(enc.length);
+        out.write(enc);
+    }
+
+    public int hashCode()
+    {
+        return identifier.hashCode();
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (!(o instanceof ASN1ObjectIdentifier))
+        {
+            return false;
+        }
+
+        return identifier.equals(((ASN1ObjectIdentifier)o).identifier);
+    }
+
+    public String toString()
+    {
+        return getId();
+    }
+
+    private static boolean isValidBranchID(
+        String branchID, int start)
+    {
+        boolean periodAllowed = false;
+
+        int pos = branchID.length();
+        while (--pos >= start)
+        {
+            char ch = branchID.charAt(pos);
+
+            // TODO Leading zeroes?
+            if ('0' <= ch && ch <= '9')
+            {
+                periodAllowed = true;
+                continue;
+            }
+
+            if (ch == '.')
+            {
+                if (!periodAllowed)
+                {
+                    return false;
+                }
+
+                periodAllowed = false;
+                continue;
+            }
+
+            return false;
+        }
+
+        return periodAllowed;
+    }
+
+    private static boolean isValidIdentifier(
+        String identifier)
+    {
+        if (identifier.length() < 3 || identifier.charAt(1) != '.')
+        {
+            return false;
+        }
+
+        char first = identifier.charAt(0);
+        if (first < '0' || first > '2')
+        {
+            return false;
+        }
+
+        return isValidBranchID(identifier, 2);
+    }
+
+    /**
+     * Intern will return a reference to a pooled version of this object, unless it
+     * is not present in which case intern will add it.
+     * <p>
+     * The pool is also used by the ASN.1 parsers to limit the number of duplicated OID
+     * objects in circulation.
+     * </p>
+     *
+     * @return a reference to the identifier in the pool.
+     */
+    public ASN1ObjectIdentifier intern()
+    {
+        final OidHandle hdl = new OidHandle(getBody());
+        ASN1ObjectIdentifier oid = pool.get(hdl);
+        if (oid == null)
+        {
+            oid = pool.putIfAbsent(hdl, this);
+            if (oid == null)
+            {
+                oid = this;
+            }
+        }
+        return oid;
+    }
+
+    private static final ConcurrentMap<OidHandle, ASN1ObjectIdentifier> pool = new ConcurrentHashMap<OidHandle, ASN1ObjectIdentifier>();
+
+    private static class OidHandle
+    {
+        private final int key;
+        private final byte[] enc;
+
+        OidHandle(byte[] enc)
+        {
+            this.key = Arrays.hashCode(enc);
+            this.enc = enc;
+        }
+
+        public int hashCode()
+        {
+            return key;
+        }
+
+        public boolean equals(Object o)
+        {
+            if (o instanceof OidHandle)
+            {
+                return Arrays.areEqual(enc, ((OidHandle)o).enc);
+            }
+
+            return false;
+        }
+    }
+
+    static ASN1ObjectIdentifier fromOctetString(byte[] enc)
+    {
+        final OidHandle hdl = new OidHandle(enc);
+        ASN1ObjectIdentifier oid = pool.get(hdl);
+        if (oid == null)
+        {
+            return new ASN1ObjectIdentifier(enc);
+        }
+        return oid;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1OctetString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1OctetString.java
new file mode 100644
index 0000000..99f3b23
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1OctetString.java
@@ -0,0 +1,254 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * Abstract base for the ASN.1 OCTET STRING data type
+ * <p>
+ * This supports BER, and DER forms of the data.
+ * </p><p>
+ * DER form is always primitive single OCTET STRING, while
+ * BER support includes the constructed forms.
+ * </p>
+ * <p><b>X.690</b></p>
+ * <p><b>8: Basic encoding rules</b></p>
+ * <p><b>8.7 Encoding of an octetstring value</b></p>
+ * <p>
+ * <b>8.7.1</b> The encoding of an octetstring value shall be
+ * either primitive or constructed at the option of the sender.
+ * <blockquote>
+ * NOTE &mdash; Where it is necessary to transfer part of an octet string
+ * before the entire OCTET STRING is available, the constructed encoding
+ * is used.
+ * </blockquote>
+ * <p>
+ * <b>8.7.2</b> The primitive encoding contains zero,
+ * one or more contents octets equal in value to the octets
+ * in the data value, in the order they appear in the data value,
+ * and with the most significant bit of an octet of the data value
+ * aligned with the most significant bit of an octet of the contents octets.
+ * </p>
+ * <p>
+ * <b>8.7.3</b> The contents octets for the constructed encoding shall consist
+ * of zero, one, or more encodings.
+ * </p>
+ * <blockquote>
+ * NOTE &mdash; Each such encoding includes identifier, length, and contents octets,
+ * and may include end-of-contents octets if it is constructed.
+ * </blockquote>
+ * <p>
+ * <b>8.7.3.1</b> To encode an octetstring value in this way,
+ * it is segmented. Each segment shall consist of a series of
+ * consecutive octets of the value. There shall be no significance
+ * placed on the segment boundaries.</p>
+ * <blockquote>
+ * NOTE &mdash; A segment may be of size zero, i.e. contain no octets.
+ * </blockquote>
+ * <p>
+ * <b>8.7.3.2</b> Each encoding in the contents octets shall represent
+ * a segment of the overall octetstring, the encoding arising from
+ * a recursive application of this subclause.
+ * In this recursive application, each segment is treated as if it were
+ * a octetstring value. The encodings of the segments shall appear in the contents
+ * octets in the order in which their octets appear in the overall value.
+ * </p>
+ * <blockquote>
+ * NOTE 1 &mdash; As a consequence of this recursion,
+ * each encoding in the contents octets may itself
+ * be primitive or constructed.
+ * However, such encodings will usually be primitive.
+ * </blockquote>
+ * <blockquote>
+ * NOTE 2 &mdash; In particular, the tags in the contents octets are always universal class, number 4.
+ * </blockquote>
+ * <p><b>9: Canonical encoding rules</b></p>
+ * <p><b>9.1 Length forms</b></p>
+ * <p>
+ * If the encoding is constructed, it shall employ the indefinite-length form.
+ * If the encoding is primitive, it shall include the fewest length octets necessary.
+ * [Contrast with 8.1.3.2 b).]
+ * </p>
+ * <p><b>9.2 String encoding forms</b></p>
+ * <p>
+ * BIT STRING, OCTET STRING,and restricted character string
+ * values shall be encoded with a primitive encoding if they would
+ * require no more than 1000 contents octets, and as a constructed
+ * encoding otherwise. The string fragments contained in
+ * the constructed encoding shall be encoded with a primitive encoding.
+ * The encoding of each fragment, except possibly
+ * the last, shall have 1000 contents octets. (Contrast with 8.21.6.)
+ * </p><p>
+ * <b>10: Distinguished encoding rules</b>
+ * </p><p>
+ * <b>10.1 Length forms</b>
+ * The definite form of length encoding shall be used,
+ * encoded in the minimum number of octets.
+ * [Contrast with 8.1.3.2 b).] 
+ * </p><p>
+ * <b>10.2 String encoding forms</b>
+ * For BIT STRING, OCTET STRING and restricted character string types,
+ * the constructed form of encoding shall not be used.
+ * (Contrast with 8.21.6.)
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ASN1OctetString
+    extends ASN1Primitive
+    implements ASN1OctetStringParser
+{
+    byte[]  string;
+
+    /**
+     * return an Octet String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want.
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *              be converted.
+     */
+    public static ASN1OctetString getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof ASN1OctetString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return BEROctetString.fromSequence(ASN1Sequence.getInstance(o));
+        }
+    }
+    
+    /**
+     * return an Octet String from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static ASN1OctetString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ASN1OctetString)
+        {
+            return (ASN1OctetString)obj;
+        }
+        else if (obj instanceof byte[])
+        {
+            try
+            {
+                return ASN1OctetString.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct OCTET STRING from byte[]: " + e.getMessage());
+            }
+        }
+        else if (obj instanceof ASN1Encodable)
+        {
+            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+            if (primitive instanceof ASN1OctetString)
+            {
+                return (ASN1OctetString)primitive;
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Base constructor.
+     *
+     * @param string the octets making up the octet string.
+     */
+    public ASN1OctetString(
+        byte[]  string)
+    {
+        if (string == null)
+        {
+            throw new NullPointerException("string cannot be null");
+        }
+        this.string = string;
+    }
+
+    /**
+     * Return the content of the OCTET STRING as an InputStream.
+     *
+     * @return an InputStream representing the OCTET STRING's content.
+     */
+    public InputStream getOctetStream()
+    {
+        return new ByteArrayInputStream(string);
+    }
+
+    /**
+     * Return the parser associated with this object.
+     *
+     * @return a parser based on this OCTET STRING
+     */
+    public ASN1OctetStringParser parser()
+    {
+        return this;
+    }
+
+    /**
+     * Return the content of the OCTET STRING as a byte array.
+     *
+     * @return the byte[] representing the OCTET STRING's content.
+     */
+    public byte[] getOctets()
+    {
+        return string;
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(this.getOctets());
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof ASN1OctetString))
+        {
+            return false;
+        }
+
+        ASN1OctetString  other = (ASN1OctetString)o;
+
+        return Arrays.areEqual(string, other.string);
+    }
+
+    public ASN1Primitive getLoadedObject()
+    {
+        return this.toASN1Primitive();
+    }
+
+    ASN1Primitive toDERObject()
+    {
+        return new DEROctetString(string);
+    }
+
+    ASN1Primitive toDLObject()
+    {
+        return new DEROctetString(string);
+    }
+
+    abstract void encode(ASN1OutputStream out)
+        throws IOException;
+
+    public String toString()
+    {
+      return "#" + Strings.fromByteArray(Hex.encode(string));
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1OctetStringParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1OctetStringParser.java
new file mode 100644
index 0000000..96202a1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1OctetStringParser.java
@@ -0,0 +1,19 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.InputStream;
+
+/**
+ * A basic parser for an OCTET STRING object
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ASN1OctetStringParser
+    extends ASN1Encodable, InMemoryRepresentable
+{
+    /**
+     * Return the content of the OCTET STRING as an InputStream.
+     *
+     * @return an InputStream representing the OCTET STRING's content.
+     */
+    public InputStream getOctetStream();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1OutputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1OutputStream.java
new file mode 100644
index 0000000..7471924
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1OutputStream.java
@@ -0,0 +1,196 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Stream that produces output based on the default encoding for the passed in objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1OutputStream
+{
+    private OutputStream os;
+
+    public ASN1OutputStream(
+        OutputStream    os)
+    {
+        this.os = os;
+    }
+
+    void writeLength(
+        int length)
+        throws IOException
+    {
+        if (length > 127)
+        {
+            int size = 1;
+            int val = length;
+
+            while ((val >>>= 8) != 0)
+            {
+                size++;
+            }
+
+            write((byte)(size | 0x80));
+
+            for (int i = (size - 1) * 8; i >= 0; i -= 8)
+            {
+                write((byte)(length >> i));
+            }
+        }
+        else
+        {
+            write((byte)length);
+        }
+    }
+
+    void write(int b)
+        throws IOException
+    {
+        os.write(b);
+    }
+
+    void write(byte[] bytes)
+        throws IOException
+    {
+        os.write(bytes);
+    }
+
+    void write(byte[] bytes, int off, int len)
+        throws IOException
+    {
+        os.write(bytes, off, len);
+    }
+
+    void writeEncoded(
+        int     tag,
+        byte[]  bytes)
+        throws IOException
+    {
+        write(tag);
+        writeLength(bytes.length);
+        write(bytes);
+    }
+
+    void writeTag(int flags, int tagNo)
+        throws IOException
+    {
+        if (tagNo < 31)
+        {
+            write(flags | tagNo);
+        }
+        else
+        {
+            write(flags | 0x1f);
+            if (tagNo < 128)
+            {
+                write(tagNo);
+            }
+            else
+            {
+                byte[] stack = new byte[5];
+                int pos = stack.length;
+
+                stack[--pos] = (byte)(tagNo & 0x7F);
+
+                do
+                {
+                    tagNo >>= 7;
+                    stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
+                }
+                while (tagNo > 127);
+
+                write(stack, pos, stack.length - pos);
+            }
+        }
+    }
+
+    void writeEncoded(int flags, int tagNo, byte[] bytes)
+        throws IOException
+    {
+        writeTag(flags, tagNo);
+        writeLength(bytes.length);
+        write(bytes);
+    }
+
+    protected void writeNull()
+        throws IOException
+    {
+        os.write(BERTags.NULL);
+        os.write(0x00);
+    }
+
+    public void writeObject(
+        ASN1Encodable obj)
+        throws IOException
+    {
+        if (obj != null)
+        {
+            obj.toASN1Primitive().encode(this);
+        }
+        else
+        {
+            throw new IOException("null object detected");
+        }
+    }
+
+    void writeImplicitObject(ASN1Primitive obj)
+        throws IOException
+    {
+        if (obj != null)
+        {
+            obj.encode(new ImplicitOutputStream(os));
+        }
+        else
+        {
+            throw new IOException("null object detected");
+        }
+    }
+
+    public void close()
+        throws IOException
+    {
+        os.close();
+    }
+
+    public void flush()
+        throws IOException
+    {
+        os.flush();
+    }
+
+    ASN1OutputStream getDERSubStream()
+    {
+        return new DEROutputStream(os);
+    }
+
+    ASN1OutputStream getDLSubStream()
+    {
+        return new DLOutputStream(os);
+    }
+
+    private class ImplicitOutputStream
+        extends ASN1OutputStream
+    {
+        private boolean first = true;
+
+        public ImplicitOutputStream(OutputStream os)
+        {
+            super(os);
+        }
+
+        public void write(int b)
+            throws IOException
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                super.write(b);
+            }
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ParsingException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ParsingException.java
new file mode 100644
index 0000000..38cce7b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1ParsingException.java
@@ -0,0 +1,44 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+/**
+ * Exception thrown when correctly encoded, but unexpected data is found in a stream while building an object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1ParsingException
+    extends IllegalStateException
+{
+    private Throwable cause;
+
+    /**
+     * Base constructor
+     *
+     * @param message a message concerning the exception.
+     */
+    public ASN1ParsingException(String message)
+    {
+        super(message);
+    }
+
+    /**
+     * Constructor when this exception is due to another one.
+     *
+     * @param message a message concerning the exception.
+     * @param cause the exception that caused this exception to be thrown.
+     */
+    public ASN1ParsingException(String message, Throwable cause)
+    {
+        super(message);
+        this.cause = cause;
+    }
+
+    /**
+     * Return the underlying cause of this exception, if any.
+     *
+     * @return the exception causing this one, null if there isn't one.
+     */
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Primitive.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Primitive.java
new file mode 100644
index 0000000..46c1145
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Primitive.java
@@ -0,0 +1,103 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Base class for ASN.1 primitive objects. These are the actual objects used to generate byte encodings.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ASN1Primitive
+    extends ASN1Object
+{
+    ASN1Primitive()
+    {
+
+    }
+
+    /**
+     * Create a base ASN.1 object from a byte stream.
+     *
+     * @param data the byte stream to parse.
+     * @return the base ASN.1 object represented by the byte stream.
+     * @exception IOException if there is a problem parsing the data, or parsing the stream did not exhaust the available data.
+     */
+    public static ASN1Primitive fromByteArray(byte[] data)
+        throws IOException
+    {
+        ASN1InputStream aIn = new ASN1InputStream(data);
+
+        try
+        {
+            ASN1Primitive o = aIn.readObject();
+
+            if (aIn.available() != 0)
+            {
+                throw new IOException("Extra data detected in stream");
+            }
+
+            return o;
+        }
+        catch (ClassCastException e)
+        {
+            throw new IOException("cannot recognise object in stream");
+        }
+    }
+
+    public final boolean equals(Object o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+
+        return (o instanceof ASN1Encodable) && asn1Equals(((ASN1Encodable)o).toASN1Primitive());
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return this;
+    }
+
+    /**
+     * Return the current object as one which encodes using Distinguished Encoding Rules.
+     *
+     * @return a DER version of this.
+     */
+    ASN1Primitive toDERObject()
+    {
+        return this;
+    }
+
+    /**
+     * Return the current object as one which encodes using Definite Length encoding.
+     *
+     * @return a DL version of this.
+     */
+    ASN1Primitive toDLObject()
+    {
+        return this;
+    }
+
+    public abstract int hashCode();
+
+    /**
+     * Return true if this objected is a CONSTRUCTED one, false otherwise.
+     * @return true if CONSTRUCTED bit set on object's tag, false otherwise.
+     */
+    abstract boolean isConstructed();
+
+    /**
+     * Return the length of the encoding this object will produce.
+     * @return the length of the object's encoding.
+     * @throws IOException if the encoding length cannot be calculated.
+     */
+    abstract int encodedLength() throws IOException;
+
+    abstract void encode(ASN1OutputStream out) throws IOException;
+
+    /**
+     * Equality (similarity) comparison for two ASN1Primitive objects.
+     */
+    abstract boolean asn1Equals(ASN1Primitive o);
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Sequence.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Sequence.java
new file mode 100644
index 0000000..95883ab
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Sequence.java
@@ -0,0 +1,398 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * ASN.1 <code>SEQUENCE</code> and <code>SEQUENCE OF</code> constructs.
+ * <p>
+ * DER form is always definite form length fields, while
+ * BER support uses indefinite form.
+ * <hr>
+ * <p><b>X.690</b></p>
+ * <p><b>8: Basic encoding rules</b></p>
+ * <p><b>8.9 Encoding of a sequence value </b></p>
+ * 8.9.1 The encoding of a sequence value shall be constructed.
+ * <p>
+ * <b>8.9.2</b> The contents octets shall consist of the complete
+ * encoding of one data value from each of the types listed in
+ * the ASN.1 definition of the sequence type, in the order of
+ * their appearance in the definition, unless the type was referenced
+ * with the keyword <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
+ * </p><p>
+ * <b>8.9.3</b> The encoding of a data value may, but need not,
+ * be present for a type which was referenced with the keyword
+ * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
+ * If present, it shall appear in the encoding at the point
+ * corresponding to the appearance of the type in the ASN.1 definition.
+ * </p><p>
+ * <b>8.10 Encoding of a sequence-of value </b>
+ * </p><p>
+ * <b>8.10.1</b> The encoding of a sequence-of value shall be constructed.
+ * <p>
+ * <b>8.10.2</b> The contents octets shall consist of zero,
+ * one or more complete encodings of data values from the type listed in
+ * the ASN.1 definition.
+ * <p>
+ * <b>8.10.3</b> The order of the encodings of the data values shall be
+ * the same as the order of the data values in the sequence-of value to
+ * be encoded.
+ * </p>
+ * <p><b>9: Canonical encoding rules</b></p>
+ * <p><b>9.1 Length forms</b></p>
+ * If the encoding is constructed, it shall employ the indefinite-length form.
+ * If the encoding is primitive, it shall include the fewest length octets necessary.
+ * [Contrast with 8.1.3.2 b).]
+ *
+ * <p><b>11: Restrictions on BER employed by both CER and DER</b></p>
+ * <p><b>11.5 Set and sequence components with default value</b></p>
+ * <p>
+ * The encoding of a set value or sequence value shall not include
+ * an encoding for any component value which is equal to
+ * its default value.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ASN1Sequence
+    extends ASN1Primitive
+    implements com.android.internal.org.bouncycastle.util.Iterable<ASN1Encodable>
+{
+    protected Vector seq = new Vector();
+
+    /**
+     * Return an ASN1Sequence from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return an ASN1Sequence instance, or null.
+     */
+    public static ASN1Sequence getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ASN1Sequence)
+        {
+            return (ASN1Sequence)obj;
+        }
+        else if (obj instanceof ASN1SequenceParser)
+        {
+            return ASN1Sequence.getInstance(((ASN1SequenceParser)obj).toASN1Primitive());
+        }
+        else if (obj instanceof byte[])
+        {
+            try
+            {
+                return ASN1Sequence.getInstance(fromByteArray((byte[])obj));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
+            }
+        }
+        else if (obj instanceof ASN1Encodable)
+        {
+            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+            if (primitive instanceof ASN1Sequence)
+            {
+                return (ASN1Sequence)primitive;
+            }
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return an ASN1 SEQUENCE from a tagged object. There is a special
+     * case here, if an object appears to have been explicitly tagged on 
+     * reading but we were expecting it to be implicitly tagged in the 
+     * normal course of events it indicates that we lost the surrounding
+     * sequence - so we need to add it back (this will happen if the tagged
+     * object is a sequence that contains other sequences). If you are
+     * dealing with implicitly tagged sequences you really <b>should</b>
+     * be using this method.
+     *
+     * @param obj the tagged object.
+     * @param explicit true if the object is meant to be explicitly tagged,
+     *          false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *          be converted.
+     * @return an ASN1Sequence instance.
+     */
+    public static ASN1Sequence getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        if (explicit)
+        {
+            if (!obj.isExplicit())
+            {
+                throw new IllegalArgumentException("object implicit - explicit expected.");
+            }
+
+            return ASN1Sequence.getInstance(obj.getObject().toASN1Primitive());
+        }
+        else
+        {
+            ASN1Primitive o = obj.getObject();
+
+            //
+            // constructed object which appears to be explicitly tagged
+            // when it should be implicit means we have to add the
+            // surrounding sequence.
+            //
+            if (obj.isExplicit())
+            {
+                if (obj instanceof BERTaggedObject)
+                {
+                    return new BERSequence(o);
+                }
+                else
+                {
+                    return new DLSequence(o);
+                }
+            }
+            else
+            {
+                if (o instanceof ASN1Sequence)
+                {
+                    return (ASN1Sequence)o;
+                }
+            }
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Create an empty SEQUENCE
+     */
+    protected ASN1Sequence()
+    {
+    }
+
+    /**
+     * Create a SEQUENCE containing one object.
+     * @param obj the object to be put in the SEQUENCE.
+     */
+    protected ASN1Sequence(
+        ASN1Encodable obj)
+    {
+        seq.addElement(obj);
+    }
+
+    /**
+     * Create a SEQUENCE containing a vector of objects.
+     * @param v the vector of objects to be put in the SEQUENCE.
+     */
+    protected ASN1Sequence(
+        ASN1EncodableVector v)
+    {
+        for (int i = 0; i != v.size(); i++)
+        {
+            seq.addElement(v.get(i));
+        }
+    }
+
+    /**
+     * Create a SEQUENCE containing an array of objects.
+     * @param array the array of objects to be put in the SEQUENCE.
+     */
+    protected ASN1Sequence(
+        ASN1Encodable[]   array)
+    {
+        for (int i = 0; i != array.length; i++)
+        {
+            seq.addElement(array[i]);
+        }
+    }
+
+    public ASN1Encodable[] toArray()
+    {
+        ASN1Encodable[] values = new ASN1Encodable[this.size()];
+
+        for (int i = 0; i != this.size(); i++)
+        {
+            values[i] = this.getObjectAt(i);
+        }
+
+        return values;
+    }
+
+    public Enumeration getObjects()
+    {
+        return seq.elements();
+    }
+
+    public ASN1SequenceParser parser()
+    {
+        final ASN1Sequence outer = this;
+
+        return new ASN1SequenceParser()
+        {
+            private final int max = size();
+
+            private int index;
+
+            public ASN1Encodable readObject() throws IOException
+            {
+                if (index == max)
+                {
+                    return null;
+                }
+                
+                ASN1Encodable obj = getObjectAt(index++);
+                if (obj instanceof ASN1Sequence)
+                {
+                    return ((ASN1Sequence)obj).parser();
+                }
+                if (obj instanceof ASN1Set)
+                {
+                    return ((ASN1Set)obj).parser();
+                }
+
+                return obj;
+            }
+
+            public ASN1Primitive getLoadedObject()
+            {
+                return outer;
+            }
+            
+            public ASN1Primitive toASN1Primitive()
+            {
+                return outer;
+            }
+        };
+    }
+
+    /**
+     * Return the object at the sequence position indicated by index.
+     *
+     * @param index the sequence number (starting at zero) of the object
+     * @return the object at the sequence position indicated by index.
+     */
+    public ASN1Encodable getObjectAt(
+        int index)
+    {
+        return (ASN1Encodable)seq.elementAt(index);
+    }
+
+    /**
+     * Return the number of objects in this sequence.
+     *
+     * @return the number of objects in this sequence.
+     */
+    public int size()
+    {
+        return seq.size();
+    }
+
+    public int hashCode()
+    {
+        Enumeration             e = this.getObjects();
+        int                     hashCode = size();
+
+        while (e.hasMoreElements())
+        {
+            Object o = getNext(e);
+            hashCode *= 17;
+
+            hashCode ^= o.hashCode();
+        }
+
+        return hashCode;
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof ASN1Sequence))
+        {
+            return false;
+        }
+        
+        ASN1Sequence   other = (ASN1Sequence)o;
+
+        if (this.size() != other.size())
+        {
+            return false;
+        }
+
+        Enumeration s1 = this.getObjects();
+        Enumeration s2 = other.getObjects();
+
+        while (s1.hasMoreElements())
+        {
+            ASN1Encodable obj1 = getNext(s1);
+            ASN1Encodable obj2 = getNext(s2);
+
+            ASN1Primitive o1 = obj1.toASN1Primitive();
+            ASN1Primitive o2 = obj2.toASN1Primitive();
+
+            if (o1 == o2 || o1.equals(o2))
+            {
+                continue;
+            }
+
+            return false;
+        }
+
+        return true;
+    }
+
+    private ASN1Encodable getNext(Enumeration e)
+    {
+        ASN1Encodable encObj = (ASN1Encodable)e.nextElement();
+
+        return encObj;
+    }
+
+    /**
+     * Change current SEQUENCE object to be encoded as {@link DERSequence}.
+     * This is part of Distinguished Encoding Rules form serialization.
+     */
+    ASN1Primitive toDERObject()
+    {
+        ASN1Sequence derSeq = new DERSequence();
+
+        derSeq.seq = this.seq;
+
+        return derSeq;
+    }
+
+    /**
+     * Change current SEQUENCE object to be encoded as {@link DLSequence}.
+     * This is part of Direct Length form serialization.
+     */
+    ASN1Primitive toDLObject()
+    {
+        ASN1Sequence dlSeq = new DLSequence();
+
+        dlSeq.seq = this.seq;
+
+        return dlSeq;
+    }
+
+    boolean isConstructed()
+    {
+        return true;
+    }
+
+    abstract void encode(ASN1OutputStream out)
+        throws IOException;
+
+    public String toString() 
+    {
+        return seq.toString();
+    }
+
+    public Iterator<ASN1Encodable> iterator()
+    {
+        return new Arrays.Iterator<ASN1Encodable>(toArray());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1SequenceParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1SequenceParser.java
new file mode 100644
index 0000000..6d966a6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1SequenceParser.java
@@ -0,0 +1,21 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * A basic parser for a SEQUENCE object
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ASN1SequenceParser
+    extends ASN1Encodable, InMemoryRepresentable
+{
+    /**
+     * Read the next object from the underlying object representing a SEQUENCE.
+     *
+     * @throws IOException for bad input stream.
+     * @return the next object, null if we are at the end.
+     */
+    ASN1Encodable readObject()
+        throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Set.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Set.java
new file mode 100644
index 0000000..0ef3ba6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1Set.java
@@ -0,0 +1,569 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * ASN.1 <code>SET</code> and <code>SET OF</code> constructs.
+ * <p>
+ * Note: This does not know which syntax the set is!
+ * (The difference: ordering of SET elements or not ordering.)
+ * </p><p>
+ * DER form is always definite form length fields, while
+ * BER support uses indefinite form.
+ * </p><p>
+ * The CER form support does not exist.
+ * </p><p>
+ * <h2>X.690</h2>
+ * <h3>8: Basic encoding rules</h3>
+ * <h4>8.11 Encoding of a set value </h4>
+ * <b>8.11.1</b> The encoding of a set value shall be constructed
+ * <p>
+ * <b>8.11.2</b> The contents octets shall consist of the complete
+ * encoding of a data value from each of the types listed in the
+ * ASN.1 definition of the set type, in an order chosen by the sender,
+ * unless the type was referenced with the keyword
+ * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
+ * </p><p>
+ * <b>8.11.3</b> The encoding of a data value may, but need not,
+ * be present for a type which was referenced with the keyword
+ * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
+ * <blockquote>
+ * NOTE &mdash; The order of data values in a set value is not significant,
+ * and places no constraints on the order during transfer
+ * </blockquote>
+ * <h4>8.12 Encoding of a set-of value</h4>
+ * <p>
+ * <b>8.12.1</b> The encoding of a set-of value shall be constructed.
+ * </p><p>
+ * <b>8.12.2</b> The text of 8.10.2 applies:
+ * <i>The contents octets shall consist of zero,
+ * one or more complete encodings of data values from the type listed in
+ * the ASN.1 definition.</i>
+ * </p><p>
+ * <b>8.12.3</b> The order of data values need not be preserved by
+ * the encoding and subsequent decoding.
+ *
+ * <h3>9: Canonical encoding rules</h3>
+ * <h4>9.1 Length forms</h4>
+ * If the encoding is constructed, it shall employ the indefinite-length form.
+ * If the encoding is primitive, it shall include the fewest length octets necessary.
+ * [Contrast with 8.1.3.2 b).]
+ * <h4>9.3 Set components</h4>
+ * The encodings of the component values of a set value shall
+ * appear in an order determined by their tags as specified
+ * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
+ * Additionally, for the purposes of determining the order in which
+ * components are encoded when one or more component is an untagged
+ * choice type, each untagged choice type is ordered as though it
+ * has a tag equal to that of the smallest tag in that choice type
+ * or any untagged choice types nested within.
+ *
+ * <h3>10: Distinguished encoding rules</h3>
+ * <h4>10.1 Length forms</h4>
+ * The definite form of length encoding shall be used,
+ * encoded in the minimum number of octets.
+ * [Contrast with 8.1.3.2 b).]
+ * <h4>10.3 Set components</h4>
+ * The encodings of the component values of a set value shall appear
+ * in an order determined by their tags as specified
+ * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
+ * <blockquote>
+ * NOTE &mdash; Where a component of the set is an untagged choice type,
+ * the location of that component in the ordering will depend on
+ * the tag of the choice component being encoded.
+ * </blockquote>
+ *
+ * <h3>11: Restrictions on BER employed by both CER and DER</h3>
+ * <h4>11.5 Set and sequence components with default value </h4>
+ * The encoding of a set value or sequence value shall not include
+ * an encoding for any component value which is equal to
+ * its default value.
+ * <h4>11.6 Set-of components </h4>
+ * <p>
+ * The encodings of the component values of a set-of value
+ * shall appear in ascending order, the encodings being compared
+ * as octet strings with the shorter components being padded at
+ * their trailing end with 0-octets.
+ * <blockquote>
+ * NOTE &mdash; The padding octets are for comparison purposes only
+ * and do not appear in the encodings.
+ * </blockquote>
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ASN1Set
+    extends ASN1Primitive
+    implements com.android.internal.org.bouncycastle.util.Iterable<ASN1Encodable>
+{
+    private Vector set = new Vector();
+    private boolean isSorted = false;
+
+    /**
+     * return an ASN1Set from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return an ASN1Set instance, or null.
+     */
+    public static ASN1Set getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ASN1Set)
+        {
+            return (ASN1Set)obj;
+        }
+        else if (obj instanceof ASN1SetParser)
+        {
+            return ASN1Set.getInstance(((ASN1SetParser)obj).toASN1Primitive());
+        }
+        else if (obj instanceof byte[])
+        {
+            try
+            {
+                return ASN1Set.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct set from byte[]: " + e.getMessage());
+            }
+        }
+        else if (obj instanceof ASN1Encodable)
+        {
+            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+            if (primitive instanceof ASN1Set)
+            {
+                return (ASN1Set)primitive;
+            }
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return an ASN1 set from a tagged object. There is a special
+     * case here, if an object appears to have been explicitly tagged on 
+     * reading but we were expecting it to be implicitly tagged in the 
+     * normal course of events it indicates that we lost the surrounding
+     * set - so we need to add it back (this will happen if the tagged
+     * object is a sequence that contains other sequences). If you are
+     * dealing with implicitly tagged sets you really <b>should</b>
+     * be using this method.
+     *
+     * @param obj the tagged object.
+     * @param explicit true if the object is meant to be explicitly tagged
+     *          false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *          be converted.
+     * @return an ASN1Set instance.
+     */
+    public static ASN1Set getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        if (explicit)
+        {
+            if (!obj.isExplicit())
+            {
+                throw new IllegalArgumentException("object implicit - explicit expected.");
+            }
+
+            return (ASN1Set)obj.getObject();
+        }
+        else
+        {
+            ASN1Primitive o = obj.getObject();
+
+            //
+            // constructed object which appears to be explicitly tagged
+            // and it's really implicit means we have to add the
+            // surrounding set.
+            //
+            if (obj.isExplicit())
+            {
+                if (obj instanceof BERTaggedObject)
+                {
+                    return new BERSet(o);
+                }
+                else
+                {
+                    return new DLSet(o);
+                }
+            }
+            else
+            {
+                if (o instanceof ASN1Set)
+                {
+                    return (ASN1Set)o;
+                }
+
+                //
+                // in this case the parser returns a sequence, convert it
+                // into a set.
+                //
+                if (o instanceof ASN1Sequence)
+                {
+                    ASN1Sequence s = (ASN1Sequence)o;
+
+                    if (obj instanceof BERTaggedObject)
+                    {
+                        return new BERSet(s.toArray());
+                    }
+                    else
+                    {
+                        return new DLSet(s.toArray());
+                    }
+                }
+            }
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+    }
+
+    protected ASN1Set()
+    {
+    }
+
+    /**
+     * Create a SET containing one object
+     * @param obj object to be added to the SET.
+     */
+    protected ASN1Set(
+        ASN1Encodable obj)
+    {
+        set.addElement(obj);
+    }
+
+    /**
+     * Create a SET containing a vector of objects.
+     * @param v a vector of objects to make up the SET.
+     * @param doSort true if should be sorted DER style, false otherwise.
+     */
+    protected ASN1Set(
+        ASN1EncodableVector v,
+        boolean                  doSort)
+    {
+        for (int i = 0; i != v.size(); i++)
+        {
+            set.addElement(v.get(i));
+        }
+
+        if (doSort)
+        {
+            this.sort();
+        }
+    }
+
+    /**
+     * Create a SET containing an array of objects.
+     * @param array an array of objects to make up the SET.
+     * @param doSort true if should be sorted DER style, false otherwise.
+     */
+    protected ASN1Set(
+        ASN1Encodable[]   array,
+        boolean doSort)
+    {
+        for (int i = 0; i != array.length; i++)
+        {
+            set.addElement(array[i]);
+        }
+
+        if (doSort)
+        {
+            this.sort();
+        }
+    }
+
+    public Enumeration getObjects()
+    {
+        return set.elements();
+    }
+
+    /**
+     * return the object at the set position indicated by index.
+     *
+     * @param index the set number (starting at zero) of the object
+     * @return the object at the set position indicated by index.
+     */
+    public ASN1Encodable getObjectAt(
+        int index)
+    {
+        return (ASN1Encodable)set.elementAt(index);
+    }
+
+    /**
+     * return the number of objects in this set.
+     *
+     * @return the number of objects in this set.
+     */
+    public int size()
+    {
+        return set.size();
+    }
+
+    public ASN1Encodable[] toArray()
+    {
+        ASN1Encodable[] values = new ASN1Encodable[this.size()];
+
+        for (int i = 0; i != this.size(); i++)
+        {
+            values[i] = this.getObjectAt(i);
+        }
+
+        return values;
+    }
+
+    public ASN1SetParser parser()
+    {
+        final ASN1Set outer = this;
+
+        return new ASN1SetParser()
+        {
+            private final int max = size();
+
+            private int index;
+
+            public ASN1Encodable readObject() throws IOException
+            {
+                if (index == max)
+                {
+                    return null;
+                }
+
+                ASN1Encodable obj = getObjectAt(index++);
+                if (obj instanceof ASN1Sequence)
+                {
+                    return ((ASN1Sequence)obj).parser();
+                }
+                if (obj instanceof ASN1Set)
+                {
+                    return ((ASN1Set)obj).parser();
+                }
+
+                return obj;
+            }
+
+            public ASN1Primitive getLoadedObject()
+            {
+                return outer;
+            }
+
+            public ASN1Primitive toASN1Primitive()
+            {
+                return outer;
+            }
+        };
+    }
+
+    public int hashCode()
+    {
+        Enumeration             e = this.getObjects();
+        int                     hashCode = size();
+
+        while (e.hasMoreElements())
+        {
+            Object o = getNext(e);
+            hashCode *= 17;
+
+            hashCode ^= o.hashCode();
+        }
+
+        return hashCode;
+    }
+
+    /**
+     * Change current SET object to be encoded as {@link DERSet}.
+     * This is part of Distinguished Encoding Rules form serialization.
+     */
+    ASN1Primitive toDERObject()
+    {
+        if (isSorted)
+        {
+            ASN1Set derSet = new DERSet();
+
+            derSet.set = this.set;
+
+            return derSet;
+        }
+        else
+        {
+            Vector v = new Vector();
+
+            for (int i = 0; i != set.size(); i++)
+            {
+                v.addElement(set.elementAt(i));
+            }
+
+            ASN1Set derSet = new DERSet();
+
+            derSet.set = v;
+
+            derSet.sort();
+
+            return derSet;
+        }
+    }
+
+    /**
+     * Change current SET object to be encoded as {@link DLSet}.
+     * This is part of Direct Length form serialization.
+     */
+    ASN1Primitive toDLObject()
+    {
+        ASN1Set derSet = new DLSet();
+
+        derSet.set = this.set;
+
+        return derSet;
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof ASN1Set))
+        {
+            return false;
+        }
+
+        ASN1Set   other = (ASN1Set)o;
+
+        if (this.size() != other.size())
+        {
+            return false;
+        }
+
+        Enumeration s1 = this.getObjects();
+        Enumeration s2 = other.getObjects();
+
+        while (s1.hasMoreElements())
+        {
+            ASN1Encodable obj1 = getNext(s1);
+            ASN1Encodable obj2 = getNext(s2);
+
+            ASN1Primitive o1 = obj1.toASN1Primitive();
+            ASN1Primitive o2 = obj2.toASN1Primitive();
+
+            if (o1 == o2 || o1.equals(o2))
+            {
+                continue;
+            }
+
+            return false;
+        }
+
+        return true;
+    }
+
+    private ASN1Encodable getNext(Enumeration e)
+    {
+        ASN1Encodable encObj = (ASN1Encodable)e.nextElement();
+
+        // unfortunately null was allowed as a substitute for DER null
+        if (encObj == null)
+        {
+            return DERNull.INSTANCE;
+        }
+
+        return encObj;
+    }
+
+    /**
+     * return true if a <= b (arrays are assumed padded with zeros).
+     */
+    private boolean lessThanOrEqual(
+         byte[] a,
+         byte[] b)
+    {
+        int len = Math.min(a.length, b.length);
+        for (int i = 0; i != len; ++i)
+        {
+            if (a[i] != b[i])
+            {
+                return (a[i] & 0xff) < (b[i] & 0xff);
+            }
+        }
+        return len == a.length;
+    }
+
+    private byte[] getDEREncoded(
+        ASN1Encodable obj)
+    {
+        try
+        {
+            return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("cannot encode object added to SET");
+        }
+    }
+
+    protected void sort()
+    {
+        if (!isSorted)
+        {
+            isSorted = true;
+            if (set.size() > 1)
+            {
+                boolean    swapped = true;
+                int        lastSwap = set.size() - 1;
+
+                while (swapped)
+                {
+                    int    index = 0;
+                    int    swapIndex = 0;
+                    byte[] a = getDEREncoded((ASN1Encodable)set.elementAt(0));
+
+                    swapped = false;
+
+                    while (index != lastSwap)
+                    {
+                        byte[] b = getDEREncoded((ASN1Encodable)set.elementAt(index + 1));
+
+                        if (lessThanOrEqual(a, b))
+                        {
+                            a = b;
+                        }
+                        else
+                        {
+                            Object  o = set.elementAt(index);
+
+                            set.setElementAt(set.elementAt(index + 1), index);
+                            set.setElementAt(o, index + 1);
+
+                            swapped = true;
+                            swapIndex = index;
+                        }
+
+                        index++;
+                    }
+
+                    lastSwap = swapIndex;
+                }
+            }
+        }
+    }
+
+    boolean isConstructed()
+    {
+        return true;
+    }
+
+    abstract void encode(ASN1OutputStream out)
+            throws IOException;
+
+    public String toString() 
+    {
+        return set.toString();
+    }
+
+    public Iterator<ASN1Encodable> iterator()
+    {
+        return new Arrays.Iterator<ASN1Encodable>(toArray());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1SetParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1SetParser.java
new file mode 100644
index 0000000..a46c0dd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1SetParser.java
@@ -0,0 +1,21 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * A basic parser for a SET object
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ASN1SetParser
+    extends ASN1Encodable, InMemoryRepresentable
+{
+    /**
+     * Read the next object from the underlying object representing a SET.
+     *
+     * @throws IOException for bad input stream.
+     * @return the next object, null if we are at the end.
+     */
+    public ASN1Encodable readObject()
+        throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1StreamParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1StreamParser.java
new file mode 100644
index 0000000..c34e155
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1StreamParser.java
@@ -0,0 +1,251 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A parser for ASN.1 streams which also returns, where possible, parsers for the objects it encounters.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1StreamParser
+{
+    private final InputStream _in;
+    private final int         _limit;
+    private final byte[][] tmpBuffers;
+
+    public ASN1StreamParser(
+        InputStream in)
+    {
+        this(in, StreamUtil.findLimit(in));
+    }
+
+    public ASN1StreamParser(
+        InputStream in,
+        int         limit)
+    {
+        this._in = in;
+        this._limit = limit;
+
+        this.tmpBuffers = new byte[11][];
+    }
+
+    public ASN1StreamParser(
+        byte[] encoding)
+    {
+        this(new ByteArrayInputStream(encoding), encoding.length);
+    }
+
+    ASN1Encodable readIndef(int tagValue) throws IOException
+    {
+        // Note: INDEF => CONSTRUCTED
+
+        // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+        switch (tagValue)
+        {
+            case BERTags.EXTERNAL:
+                return new DERExternalParser(this);
+            case BERTags.OCTET_STRING:
+                return new BEROctetStringParser(this);
+            case BERTags.SEQUENCE:
+                return new BERSequenceParser(this);
+            case BERTags.SET:
+                return new BERSetParser(this);
+            default:
+                throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue));
+        }
+    }
+
+    ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException
+    {
+        if (_in instanceof IndefiniteLengthInputStream)
+        {
+            if (!constructed)
+            {
+                throw new IOException("indefinite-length primitive encoding encountered");
+            }
+            
+            return readIndef(tag);
+        }
+
+        if (constructed)
+        {
+            switch (tag)
+            {
+                case BERTags.SET:
+                    return new DERSetParser(this);
+                case BERTags.SEQUENCE:
+                    return new DERSequenceParser(this);
+                case BERTags.OCTET_STRING:
+                    return new BEROctetStringParser(this);
+            }
+        }
+        else
+        {
+            switch (tag)
+            {
+                case BERTags.SET:
+                    throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
+                case BERTags.SEQUENCE:
+                    throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
+                case BERTags.OCTET_STRING:
+                    return new DEROctetStringParser((DefiniteLengthInputStream)_in);
+            }
+        }
+
+        throw new ASN1Exception("implicit tagging not implemented");
+    }
+
+    ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException
+    {
+        if (!constructed)
+        {
+            // Note: !CONSTRUCTED => IMPLICIT
+            DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;
+            return new DERTaggedObject(false, tag, new DEROctetString(defIn.toByteArray()));
+        }
+
+        ASN1EncodableVector v = readVector();
+
+        if (_in instanceof IndefiniteLengthInputStream)
+        {
+            return v.size() == 1
+                ?   new BERTaggedObject(true, tag, v.get(0))
+                :   new BERTaggedObject(false, tag, BERFactory.createSequence(v));
+        }
+
+        return v.size() == 1
+            ?   new DERTaggedObject(true, tag, v.get(0))
+            :   new DERTaggedObject(false, tag, DERFactory.createSequence(v));
+    }
+
+    public ASN1Encodable readObject()
+        throws IOException
+    {
+        int tag = _in.read();
+        if (tag == -1)
+        {
+            return null;
+        }
+
+        //
+        // turn of looking for "00" while we resolve the tag
+        //
+        set00Check(false);
+
+        //
+        // calculate tag number
+        //
+        int tagNo = ASN1InputStream.readTagNumber(_in, tag);
+
+        boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0;
+
+        //
+        // calculate length
+        //
+        int length = ASN1InputStream.readLength(_in, _limit);
+
+        if (length < 0) // indefinite-length method
+        {
+            if (!isConstructed)
+            {
+                throw new IOException("indefinite-length primitive encoding encountered");
+            }
+
+            IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
+            ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
+
+            if ((tag & BERTags.APPLICATION) != 0)
+            {
+                return new BERApplicationSpecificParser(tagNo, sp);
+            }
+
+            if ((tag & BERTags.TAGGED) != 0)
+            {
+                return new BERTaggedObjectParser(true, tagNo, sp);
+            }
+
+            return sp.readIndef(tagNo);
+        }
+        else
+        {
+            DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
+
+            if ((tag & BERTags.APPLICATION) != 0)
+            {
+                return new DLApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
+            }
+
+            if ((tag & BERTags.TAGGED) != 0)
+            {
+                return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn));
+            }
+
+            if (isConstructed)
+            {
+                // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+                switch (tagNo)
+                {
+                    case BERTags.OCTET_STRING:
+                        //
+                        // yes, people actually do this...
+                        //
+                        return new BEROctetStringParser(new ASN1StreamParser(defIn));
+                    case BERTags.SEQUENCE:
+                        return new DERSequenceParser(new ASN1StreamParser(defIn));
+                    case BERTags.SET:
+                        return new DERSetParser(new ASN1StreamParser(defIn));
+                    case BERTags.EXTERNAL:
+                        return new DERExternalParser(new ASN1StreamParser(defIn));
+                    default:
+                        throw new IOException("unknown tag " + tagNo + " encountered");
+                }
+            }
+
+            // Some primitive encodings can be handled by parsers too...
+            switch (tagNo)
+            {
+                case BERTags.OCTET_STRING:
+                    return new DEROctetStringParser(defIn);
+            }
+
+            try
+            {
+                return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
+            }
+            catch (IllegalArgumentException e)
+            {
+                throw new ASN1Exception("corrupted stream detected", e);
+            }
+        }
+    }
+
+    private void set00Check(boolean enabled)
+    {
+        if (_in instanceof IndefiniteLengthInputStream)
+        {
+            ((IndefiniteLengthInputStream)_in).setEofOn00(enabled);
+        }
+    }
+
+    ASN1EncodableVector readVector() throws IOException
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        ASN1Encodable obj;
+        while ((obj = readObject()) != null)
+        {
+            if (obj instanceof InMemoryRepresentable)
+            {
+                v.add(((InMemoryRepresentable)obj).getLoadedObject());
+            }
+            else
+            {
+                v.add(obj.toASN1Primitive());
+            }
+        }
+
+        return v;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1String.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1String.java
new file mode 100644
index 0000000..030b7aa
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1String.java
@@ -0,0 +1,15 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+/**
+ * General interface implemented by ASN.1 STRING objects for extracting the content String.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ASN1String
+{
+    /**
+     * Return a Java String representation of this STRING type's content.
+     * @return a Java String representation of this STRING.
+     */
+    public String getString();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1TaggedObject.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1TaggedObject.java
new file mode 100644
index 0000000..54fd1d6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1TaggedObject.java
@@ -0,0 +1,244 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ASN1TaggedObject
+    extends ASN1Primitive
+    implements ASN1TaggedObjectParser
+{
+    int             tagNo;
+    boolean         empty = false;
+    boolean         explicit = true;
+    ASN1Encodable obj = null;
+
+    static public ASN1TaggedObject getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        if (explicit)
+        {
+            return (ASN1TaggedObject)obj.getObject();
+        }
+
+        throw new IllegalArgumentException("implicitly tagged tagged object");
+    }
+
+    static public ASN1TaggedObject getInstance(
+        Object obj) 
+    {
+        if (obj == null || obj instanceof ASN1TaggedObject) 
+        {
+                return (ASN1TaggedObject)obj;
+        }
+        else if (obj instanceof byte[])
+        {
+            try
+            {
+                return ASN1TaggedObject.getInstance(fromByteArray((byte[])obj));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct tagged object from byte[]: " + e.getMessage());
+            }
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Create a tagged object with the style given by the value of explicit.
+     * <p>
+     * If the object implements ASN1Choice the tag style will always be changed
+     * to explicit in accordance with the ASN.1 encoding rules.
+     * </p>
+     * @param explicit true if the object is explicitly tagged.
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public ASN1TaggedObject(
+        boolean         explicit,
+        int             tagNo,
+        ASN1Encodable   obj)
+    {
+        if (obj instanceof ASN1Choice)
+        {
+            this.explicit = true;
+        }
+        else
+        {
+            this.explicit = explicit;
+        }
+        
+        this.tagNo = tagNo;
+
+        if (this.explicit)
+        {
+            this.obj = obj;
+        }
+        else
+        {
+            ASN1Primitive prim = obj.toASN1Primitive();
+
+            if (prim instanceof ASN1Set)
+            {
+                ASN1Set s = null;
+            }
+
+            this.obj = obj;
+        }
+    }
+    
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof ASN1TaggedObject))
+        {
+            return false;
+        }
+        
+        ASN1TaggedObject other = (ASN1TaggedObject)o;
+        
+        if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit)
+        {
+            return false;
+        }
+        
+        if(obj == null)
+        {
+            if (other.obj != null)
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if (!(obj.toASN1Primitive().equals(other.obj.toASN1Primitive())))
+            {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    public int hashCode()
+    {
+        int code = tagNo;
+
+        // TODO: actually this is wrong - the problem is that a re-encoded
+        // object may end up with a different hashCode due to implicit
+        // tagging. As implicit tagging is ambiguous if a sequence is involved
+        // it seems the only correct method for both equals and hashCode is to
+        // compare the encodings...
+        if (obj != null)
+        {
+            code ^= obj.hashCode();
+        }
+
+        return code;
+    }
+
+    /**
+     * Return the tag number associated with this object.
+     *
+     * @return the tag number.
+     */
+    public int getTagNo()
+    {
+        return tagNo;
+    }
+
+    /**
+     * return whether or not the object may be explicitly tagged. 
+     * <p>
+     * Note: if the object has been read from an input stream, the only
+     * time you can be sure if isExplicit is returning the true state of
+     * affairs is if it returns false. An implicitly tagged object may appear
+     * to be explicitly tagged, so you need to understand the context under
+     * which the reading was done as well, see getObject below.
+     */
+    public boolean isExplicit()
+    {
+        return explicit;
+    }
+
+    public boolean isEmpty()
+    {
+        return empty;
+    }
+
+    /**
+     * Return whatever was following the tag.
+     * <p>
+     * Note: tagged objects are generally context dependent if you're
+     * trying to extract a tagged object you should be going via the
+     * appropriate getInstance method.
+     */
+    public ASN1Primitive getObject()
+    {
+        if (obj != null)
+        {
+            return obj.toASN1Primitive();
+        }
+
+        return null;
+    }
+
+    /**
+     * Return the object held in this tagged object as a parser assuming it has
+     * the type of the passed in tag. If the object doesn't have a parser
+     * associated with it, the base object is returned.
+     */
+    public ASN1Encodable getObjectParser(
+        int     tag,
+        boolean isExplicit)
+        throws IOException
+    {
+        switch (tag)
+        {
+        case BERTags.SET:
+            return ASN1Set.getInstance(this, isExplicit).parser();
+        case BERTags.SEQUENCE:
+            return ASN1Sequence.getInstance(this, isExplicit).parser();
+        case BERTags.OCTET_STRING:
+            return ASN1OctetString.getInstance(this, isExplicit).parser();
+        }
+
+        if (isExplicit)
+        {
+            return getObject();
+        }
+
+        throw new ASN1Exception("implicit tagging not implemented for tag: " + tag);
+    }
+
+    public ASN1Primitive getLoadedObject()
+    {
+        return this.toASN1Primitive();
+    }
+
+    ASN1Primitive toDERObject()
+    {
+        return new DERTaggedObject(explicit, tagNo, obj);
+    }
+
+    ASN1Primitive toDLObject()
+    {
+        return new DLTaggedObject(explicit, tagNo, obj);
+    }
+
+    abstract void encode(ASN1OutputStream out)
+        throws IOException;
+
+    public String toString()
+    {
+        return "[" + tagNo + "]" + obj;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1TaggedObjectParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1TaggedObjectParser.java
new file mode 100644
index 0000000..41fcf42
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1TaggedObjectParser.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Interface for the parsing of a generic tagged ASN.1 object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ASN1TaggedObjectParser
+    extends ASN1Encodable, InMemoryRepresentable
+{
+    /**
+     * Return the tag number associated with the underlying tagged object.
+     * @return the object's tag number.
+     */
+    int getTagNo();
+
+    /**
+     * Return a parser for the actual object tagged.
+     *
+     * @param tag the primitive tag value for the object tagged originally.
+     * @param isExplicit true if the tagging was done explicitly.
+     * @return a parser for the tagged object.
+     * @throws IOException if a parser cannot be constructed.
+     */
+    ASN1Encodable getObjectParser(int tag, boolean isExplicit)
+        throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1UTCTime.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1UTCTime.java
new file mode 100644
index 0000000..e47fcbf
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ASN1UTCTime.java
@@ -0,0 +1,328 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+// Android-added: Localization support
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.SimpleTimeZone;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+- * UTC time object.
+ * Internal facade of {@link ASN1UTCTime}.
+ * <p>
+ * This datatype is valid only from 1950-01-01 00:00:00 UTC until 2049-12-31 23:59:59 UTC.
+ * </p>
+ * <hr>
+ * <p><b>X.690</b></p>
+ * <p><b>11: Restrictions on BER employed by both CER and DER</b></p>
+ * <p><b>11.8 UTCTime </b></p>
+ * <b>11.8.1</b> The encoding shall terminate with "Z",
+ * as described in the ITU-T X.680 | ISO/IEC 8824-1 clause on UTCTime.
+ * <p>
+ * <b>11.8.2</b> The seconds element shall always be present.
+ * <p>
+ * <b>11.8.3</b> Midnight (GMT) shall be represented in the form:
+ * <blockquote>
+ * "YYMMDD000000Z"
+ * </blockquote>
+ * where "YYMMDD" represents the day following the midnight in question.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1UTCTime
+    extends ASN1Primitive
+{
+    private byte[]      time;
+
+    /**
+     * Return an UTC Time from the passed in object.
+     *
+     * @param obj an ASN1UTCTime or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return an ASN1UTCTime instance, or null.
+     */
+    public static ASN1UTCTime getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ASN1UTCTime)
+        {
+            return (ASN1UTCTime)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (ASN1UTCTime)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return an UTC Time from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return an ASN1UTCTime instance, or null.
+     */
+    public static ASN1UTCTime getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Object o = obj.getObject();
+
+        if (explicit || o instanceof ASN1UTCTime)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new ASN1UTCTime(((ASN1OctetString)o).getOctets());
+        }
+    }
+
+    /**
+     * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
+     * never encoded. When you're creating one of these objects from scratch, that's
+     * what you want to use, otherwise we'll try to deal with whatever gets read from
+     * the input stream... (this is why the input format is different from the getTime()
+     * method output).
+     * <p>
+     *
+     * @param time the time string.
+     */
+    public ASN1UTCTime(
+        String time)
+    {
+        this.time = Strings.toByteArray(time);
+        try
+        {
+            this.getDate();
+        }
+        catch (ParseException e)
+        {
+            throw new IllegalArgumentException("invalid date string: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Base constructor from a java.util.date object
+     * @param time the Date to build the time from.
+     */
+    public ASN1UTCTime(
+        Date time)
+    {
+        // Android-changed: Use localized version
+        // SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", DateUtil.EN_Locale);
+        SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", Locale.US);
+
+        dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
+
+        this.time = Strings.toByteArray(dateF.format(time));
+    }
+
+    /**
+     * Base constructor from a java.util.date and Locale - you may need to use this if the default locale
+     * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations.
+     *
+     * @param time a date object representing the time of interest.
+     * @param locale an appropriate Locale for producing an ASN.1 UTCTime value.
+     */
+    public ASN1UTCTime(
+        Date time,
+        Locale locale)
+    {
+        // BEGIN Android-changed: Use localized version
+        // SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", locale);
+        SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", Locale.US);
+        dateF.setCalendar(Calendar.getInstance(locale));
+        // END Android-changed: Use localized version
+
+        dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
+
+        this.time = Strings.toByteArray(dateF.format(time));
+    }
+
+    ASN1UTCTime(
+        byte[] time)
+    {
+        this.time = time;
+    }
+
+    /**
+     * Return the time as a date based on whatever a 2 digit year will return. For
+     * standardised processing use getAdjustedDate().
+     *
+     * @return the resulting date
+     * @exception ParseException if the date string cannot be parsed.
+     */
+    public Date getDate()
+        throws ParseException
+    {
+        // Android-changed: Use localized version
+        // SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz");
+        SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz", Locale.US);
+
+        return DateUtil.epochAdjust(dateF.parse(getTime()));
+    }
+
+    /**
+     * Return the time as an adjusted date
+     * in the range of 1950 - 2049.
+     *
+     * @return a date in the range of 1950 to 2049.
+     * @exception ParseException if the date string cannot be parsed.
+     */
+    public Date getAdjustedDate()
+        throws ParseException
+    {
+        // Android-changed: Use localized version
+        // SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+        SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz", Locale.US);
+
+        dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
+        
+        return DateUtil.epochAdjust(dateF.parse(getAdjustedTime()));
+    }
+
+    /**
+     * Return the time - always in the form of
+     *  YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+     * <p>
+     * Normally in a certificate we would expect "Z" rather than "GMT",
+     * however adding the "GMT" means we can just use:
+     * <pre>
+     *     dateF = new SimpleDateFormat("yyMMddHHmmssz");
+     * </pre>
+     * To read in the time and get a date which is compatible with our local
+     * time zone.
+     * <p>
+     * <b>Note:</b> In some cases, due to the local date processing, this
+     * may lead to unexpected results. If you want to stick the normal
+     * convention of 1950 to 2049 use the getAdjustedTime() method.
+     */
+    public String getTime()
+    {
+        String stime = Strings.fromByteArray(time);
+
+        //
+        // standardise the format.
+        //
+        if (stime.indexOf('-') < 0 && stime.indexOf('+') < 0)
+        {
+            if (stime.length() == 11)
+            {
+                return stime.substring(0, 10) + "00GMT+00:00";
+            }
+            else
+            {
+                return stime.substring(0, 12) + "GMT+00:00";
+            }
+        }
+        else
+        {
+            int index = stime.indexOf('-');
+            if (index < 0)
+            {
+                index = stime.indexOf('+');
+            }
+            String d = stime;
+
+            if (index == stime.length() - 3)
+            {
+                d += "00";
+            }
+
+            if (index == 10)
+            {
+                return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15);
+            }
+            else
+            {
+                return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" +  d.substring(15, 17);
+            }
+        }
+    }
+
+    /**
+     * Return a time string as an adjusted date with a 4 digit year. This goes
+     * in the range of 1950 - 2049.
+     */
+    public String getAdjustedTime()
+    {
+        String   d = this.getTime();
+
+        if (d.charAt(0) < '5')
+        {
+            return "20" + d;
+        }
+        else
+        {
+            return "19" + d;
+        }
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        int length = time.length;
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
+    void encode(
+        ASN1OutputStream  out)
+        throws IOException
+    {
+        out.write(BERTags.UTC_TIME);
+
+        int length = time.length;
+
+        out.writeLength(length);
+
+        for (int i = 0; i != length; i++)
+        {
+            out.write((byte)time[i]);
+        }
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof ASN1UTCTime))
+        {
+            return false;
+        }
+
+        return Arrays.areEqual(time, ((ASN1UTCTime)o).time);
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(time);
+    }
+
+    public String toString()
+    {
+      return Strings.fromByteArray(time);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERApplicationSpecific.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERApplicationSpecific.java
new file mode 100644
index 0000000..7263695
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERApplicationSpecific.java
@@ -0,0 +1,116 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * An indefinite-length encoding version of an ASN.1 ApplicationSpecific object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BERApplicationSpecific
+    extends ASN1ApplicationSpecific
+{
+    BERApplicationSpecific(
+        boolean isConstructed,
+        int tag,
+        byte[] octets)
+    {
+        super(isConstructed, tag, octets);
+    }
+
+    /**
+     * Create an application specific object with a tagging of explicit/constructed.
+     *
+     * @param tag the tag number for this object.
+     * @param object the object to be contained.
+     */
+    public BERApplicationSpecific(
+        int tag,
+        ASN1Encodable object)
+        throws IOException
+    {
+        this(true, tag, object);
+    }
+
+    /**
+     * Create an application specific object with the tagging style given by the value of constructed.
+     *
+     * @param constructed true if the object is constructed.
+     * @param tag the tag number for this object.
+     * @param object the object to be contained.
+     */
+    public BERApplicationSpecific(
+        boolean constructed,
+        int tag,
+        ASN1Encodable object)
+        throws IOException
+    {
+        super(constructed || object.toASN1Primitive().isConstructed(), tag, getEncoding(constructed, object));
+    }
+
+    private static byte[] getEncoding(boolean explicit, ASN1Encodable object)
+        throws IOException
+    {
+        byte[] data = object.toASN1Primitive().getEncoded(ASN1Encoding.BER);
+
+        if (explicit)
+        {
+            return data;
+        }
+        else
+        {
+            int lenBytes = getLengthOfHeader(data);
+            byte[] tmp = new byte[data.length - lenBytes];
+            System.arraycopy(data, lenBytes, tmp, 0, tmp.length);
+            return tmp;
+        }
+    }
+
+    /**
+     * Create an application specific object which is marked as constructed
+     *
+     * @param tagNo the tag number for this object.
+     * @param vec the objects making up the application specific object.
+     */
+    public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
+    {
+        super(true, tagNo, getEncodedVector(vec));
+    }
+
+    private static byte[] getEncodedVector(ASN1EncodableVector vec)
+    {
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+        for (int i = 0; i != vec.size(); i++)
+        {
+            try
+            {
+                bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.BER));
+            }
+            catch (IOException e)
+            {
+                throw new ASN1ParsingException("malformed object: " + e, e);
+            }
+        }
+        return bOut.toByteArray();
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
+     */
+    void encode(ASN1OutputStream out) throws IOException
+    {
+        int classBits = BERTags.APPLICATION;
+        if (isConstructed)
+        {
+            classBits |= BERTags.CONSTRUCTED;
+        }
+
+        out.writeTag(classBits, tag);
+        out.write(0x80);
+        out.write(octets);
+        out.write(0x00);
+        out.write(0x00);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERApplicationSpecificParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERApplicationSpecificParser.java
new file mode 100644
index 0000000..a1617b4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERApplicationSpecificParser.java
@@ -0,0 +1,61 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * A parser for indefinite-length ASN.1 ApplicationSpecific objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BERApplicationSpecificParser
+    implements ASN1ApplicationSpecificParser
+{
+    private final int tag;
+    private final ASN1StreamParser parser;
+
+    BERApplicationSpecificParser(int tag, ASN1StreamParser parser)
+    {
+        this.tag = tag;
+        this.parser = parser;
+    }
+
+    /**
+     * Return the object contained in this application specific object,
+     * @return the contained object.
+     * @throws IOException if the underlying stream cannot be read, or does not contain an ASN.1 encoding.
+     */
+    public ASN1Encodable readObject()
+        throws IOException
+    {
+        return parser.readObject();
+    }
+
+    /**
+     * Return an in-memory, encodable, representation of the application specific object.
+     *
+     * @return a BERApplicationSpecific.
+     * @throws IOException if there is an issue loading the data.
+     */
+    public ASN1Primitive getLoadedObject()
+        throws IOException
+    {
+         return new BERApplicationSpecific(tag, parser.readVector());
+    }
+
+    /**
+     * Return a BERApplicationSpecific representing this parser and its contents.
+     *
+     * @return a BERApplicationSpecific
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        try
+        {
+            return getLoadedObject();
+        }
+        catch (IOException e)
+        {
+            throw new ASN1ParsingException(e.getMessage(), e);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERConstructedOctetString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERConstructedOctetString.java
new file mode 100644
index 0000000..6a67881
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERConstructedOctetString.java
@@ -0,0 +1,146 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * @deprecated use BEROctetString
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BERConstructedOctetString
+    extends BEROctetString
+{
+    private static final int MAX_LENGTH = 1000;
+
+    /**
+     * convert a vector of octet strings into a single byte string
+     */
+    static private byte[] toBytes(
+        Vector  octs)
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+
+        for (int i = 0; i != octs.size(); i++)
+        {
+            try
+            {
+                DEROctetString  o = (DEROctetString)octs.elementAt(i);
+
+                bOut.write(o.getOctets());
+            }
+            catch (ClassCastException e)
+            {
+                throw new IllegalArgumentException(octs.elementAt(i).getClass().getName() + " found in input should only contain DEROctetString");
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("exception converting octets " + e.toString());
+            }
+        }
+
+        return bOut.toByteArray();
+    }
+
+    private Vector  octs;
+
+    /**
+     * @param string the octets making up the octet string.
+     */
+    public BERConstructedOctetString(
+        byte[]  string)
+    {
+        super(string);
+    }
+
+    public BERConstructedOctetString(
+        Vector  octs)
+    {
+        super(toBytes(octs));
+
+        this.octs = octs;
+    }
+
+    public BERConstructedOctetString(
+        ASN1Primitive  obj)
+    {
+        super(toByteArray(obj));
+    }
+
+    private static byte[] toByteArray(ASN1Primitive obj)
+    {
+        try
+        {
+            return obj.getEncoded();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("Unable to encode object");
+        }
+    }
+
+    public BERConstructedOctetString(
+        ASN1Encodable  obj)
+    {
+        this(obj.toASN1Primitive());
+    }
+
+    public byte[] getOctets()
+    {
+        return string;
+    }
+
+    /**
+     * return the DER octets that make up this string.
+     */
+    public Enumeration getObjects()
+    {
+        if (octs == null)
+        {
+            return generateOcts().elements();
+        }
+
+        return octs.elements();
+    }
+
+    private Vector generateOcts() 
+    { 
+        Vector vec = new Vector(); 
+        for (int i = 0; i < string.length; i += MAX_LENGTH) 
+        { 
+            int end; 
+
+            if (i + MAX_LENGTH > string.length) 
+            { 
+                end = string.length; 
+            } 
+            else 
+            { 
+                end = i + MAX_LENGTH; 
+            } 
+
+            byte[] nStr = new byte[end - i]; 
+
+            System.arraycopy(string, i, nStr, 0, nStr.length); 
+
+            vec.addElement(new DEROctetString(nStr)); 
+         } 
+        
+         return vec; 
+    }
+
+    public static BEROctetString fromSequence(ASN1Sequence seq)
+    {
+        Vector      v = new Vector();
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            v.addElement(e.nextElement());
+        }
+
+        return new BERConstructedOctetString(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERFactory.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERFactory.java
new file mode 100644
index 0000000..1178928
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERFactory.java
@@ -0,0 +1,18 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+class BERFactory
+{
+    static final BERSequence EMPTY_SEQUENCE = new BERSequence();
+    static final BERSet EMPTY_SET = new BERSet();
+
+    static BERSequence createSequence(ASN1EncodableVector v)
+    {
+        return v.size() < 1 ? EMPTY_SEQUENCE : new BERSequence(v);
+    }
+
+    static BERSet createSet(ASN1EncodableVector v)
+    {
+        return v.size() < 1 ? EMPTY_SET : new BERSet(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERGenerator.java
new file mode 100644
index 0000000..5ae1978
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERGenerator.java
@@ -0,0 +1,92 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Base class for generators for indefinite-length structures.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BERGenerator
+    extends ASN1Generator
+{
+    private boolean      _tagged = false;
+    private boolean      _isExplicit;
+    private int          _tagNo;
+
+    protected BERGenerator(
+        OutputStream out)
+    {
+        super(out);
+    }
+
+    protected BERGenerator(
+        OutputStream out,
+        int tagNo,
+        boolean isExplicit) 
+    {
+        super(out);
+        
+        _tagged = true;
+        _isExplicit = isExplicit;
+        _tagNo = tagNo;
+    }
+
+    public OutputStream getRawOutputStream()
+    {
+        return _out;
+    }
+    
+    private void writeHdr(
+        int tag)
+        throws IOException
+    {
+        _out.write(tag);
+        _out.write(0x80);
+    }
+    
+    protected void writeBERHeader(
+        int tag) 
+        throws IOException
+    {
+        if (_tagged)
+        {
+            int tagNum = _tagNo | BERTags.TAGGED;
+
+            if (_isExplicit)
+            {
+                writeHdr(tagNum | BERTags.CONSTRUCTED);
+                writeHdr(tag);
+            }
+            else
+            {   
+                if ((tag & BERTags.CONSTRUCTED) != 0)
+                {
+                    writeHdr(tagNum | BERTags.CONSTRUCTED);
+                }
+                else
+                {
+                    writeHdr(tagNum);
+                }
+            }
+        }
+        else
+        {
+            writeHdr(tag);
+        }
+    }
+
+    protected void writeBEREnd()
+        throws IOException
+    {
+        _out.write(0x00);
+        _out.write(0x00);
+        
+        if (_tagged && _isExplicit)  // write extra end for tag header
+        {
+            _out.write(0x00);
+            _out.write(0x00);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROctetString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROctetString.java
new file mode 100644
index 0000000..1966b99
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROctetString.java
@@ -0,0 +1,229 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * ASN.1 OctetStrings, with indefinite length rules, and <i>constructed form</i> support.
+ * <p>
+ * The Basic Encoding Rules (BER) format allows encoding using so called "<i>constructed form</i>",
+ * which DER and CER formats forbid allowing only "primitive form".
+ * </p><p>
+ * This class <b>always</b> produces the constructed form with underlying segments
+ * in an indefinite length array.  If the input wasn't the same, then this output
+ * is not faithful reproduction.
+ * </p>
+ * <p>
+ * See {@link ASN1OctetString} for X.690 encoding rules of OCTET-STRING objects.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BEROctetString
+    extends ASN1OctetString
+{
+    private static final int DEFAULT_LENGTH = 1000;
+
+    private final int chunkSize;
+    private final ASN1OctetString[] octs;
+
+    /**
+     * Convert a vector of octet strings into a single byte string
+     */
+    static private byte[] toBytes(
+        ASN1OctetString[]  octs)
+    {
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+        for (int i = 0; i != octs.length; i++)
+        {
+            try
+            {
+                DEROctetString o = (DEROctetString)octs[i];
+
+                bOut.write(o.getOctets());
+            }
+            catch (ClassCastException e)
+            {
+                throw new IllegalArgumentException(octs[i].getClass().getName() + " found in input should only contain DEROctetString");
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("exception converting octets " + e.toString());
+            }
+        }
+
+        return bOut.toByteArray();
+    }
+
+    /**
+     * Create an OCTET-STRING object from a byte[]
+     * @param string the octets making up the octet string.
+     */
+    public BEROctetString(
+        byte[] string)
+    {
+        this(string, DEFAULT_LENGTH);
+    }
+
+    /**
+     * Multiple {@link ASN1OctetString} data blocks are input,
+     * the result is <i>constructed form</i>.
+     *
+     * @param octs an array of OCTET STRING to construct the BER OCTET STRING from.
+     */
+    public BEROctetString(
+        ASN1OctetString[] octs)
+    {
+        this(octs, DEFAULT_LENGTH);
+    }
+
+    /**
+     * Create an OCTET-STRING object from a byte[]
+     * @param string the octets making up the octet string.
+     * @param chunkSize the number of octets stored in each DER encoded component OCTET STRING.
+     */
+    public BEROctetString(
+        byte[] string,
+        int    chunkSize)
+    {
+        this(string, null, chunkSize);
+    }
+
+    /**
+     * Multiple {@link ASN1OctetString} data blocks are input,
+     * the result is <i>constructed form</i>.
+     *
+     * @param octs an array of OCTET STRING to construct the BER OCTET STRING from.
+     * @param chunkSize the number of octets stored in each DER encoded component OCTET STRING.
+     */
+    public BEROctetString(
+        ASN1OctetString[] octs,
+        int chunkSize)
+    {
+        this(toBytes(octs), octs, chunkSize);
+    }
+
+    private BEROctetString(byte[] string, ASN1OctetString[] octs, int chunkSize)
+    {
+        super(string);
+        this.octs = octs;
+        this.chunkSize = chunkSize;
+    }
+
+    /**
+     * Return a concatenated byte array of all the octets making up the constructed OCTET STRING
+     * @return the full OCTET STRING.
+     */
+    public byte[] getOctets()
+    {
+        return string;
+    }
+
+    /**
+     * Return the OCTET STRINGs that make up this string.
+     *
+     * @return an Enumeration of the component OCTET STRINGs.
+     */
+    public Enumeration getObjects()
+    {
+        if (octs == null)
+        {
+            return generateOcts().elements();
+        }
+
+        return new Enumeration()
+        {
+            int counter = 0;
+
+            public boolean hasMoreElements()
+            {
+                return counter < octs.length;
+            }
+
+            public Object nextElement()
+            {
+                return octs[counter++];
+            }
+        };
+    }
+
+    private Vector generateOcts()
+    { 
+        Vector vec = new Vector();
+        for (int i = 0; i < string.length; i += chunkSize)
+        { 
+            int end; 
+
+            if (i + chunkSize > string.length)
+            { 
+                end = string.length; 
+            } 
+            else 
+            { 
+                end = i + chunkSize;
+            } 
+
+            byte[] nStr = new byte[end - i]; 
+
+            System.arraycopy(string, i, nStr, 0, nStr.length);
+
+            vec.addElement(new DEROctetString(nStr));
+         } 
+        
+         return vec; 
+    }
+
+    boolean isConstructed()
+    {
+        return true;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = 0;
+        for (Enumeration e = getObjects(); e.hasMoreElements();)
+        {
+            length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+        }
+
+        return 2 + length + 2;
+    }
+
+    public void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.write(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
+
+        out.write(0x80);
+
+        //
+        // write out the octet array
+        //
+        for (Enumeration e = getObjects(); e.hasMoreElements();)
+        {
+            out.writeObject((ASN1Encodable)e.nextElement());
+        }
+
+        out.write(0x00);
+        out.write(0x00);
+    }
+
+    static BEROctetString fromSequence(ASN1Sequence seq)
+    {
+        ASN1OctetString[]     v = new ASN1OctetString[seq.size()];
+        Enumeration e = seq.getObjects();
+        int                   index = 0;
+
+        while (e.hasMoreElements())
+        {
+            v[index++] = (ASN1OctetString)e.nextElement();
+        }
+
+        return new BEROctetString(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROctetStringGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROctetStringGenerator.java
new file mode 100644
index 0000000..8d3d6a1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROctetStringGenerator.java
@@ -0,0 +1,134 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A generator for indefinite-length OCTET STRINGs
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BEROctetStringGenerator
+    extends BERGenerator
+{
+    /**
+     * Use the passed in stream as the target for the generator, writing out the header tag
+     * for a constructed OCTET STRING.
+     *
+     * @param out target stream
+     * @throws IOException if the target stream cannot be written to.
+     */
+    public BEROctetStringGenerator(OutputStream out) 
+        throws IOException
+    {
+        super(out);
+        
+        writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
+    }
+
+    /**
+     * Use the passed in stream as the target for the generator, writing out the header tag
+     * for a tagged constructed OCTET STRING (possibly implicit).
+     *
+     * @param out target stream
+     * @param tagNo the tag number to introduce
+     * @param isExplicit true if this is an explicitly tagged object, false otherwise.
+     * @throws IOException if the target stream cannot be written to.
+     */
+    public BEROctetStringGenerator(
+        OutputStream out,
+        int tagNo,
+        boolean isExplicit) 
+        throws IOException
+    {
+        super(out, tagNo, isExplicit);
+        
+        writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
+    }
+
+    /**
+     * Return a stream representing the content target for this OCTET STRING
+     *
+     * @return an OutputStream which chunks data in blocks of 1000 (CER limit).
+     */
+    public OutputStream getOctetOutputStream()
+    {
+        return getOctetOutputStream(new byte[1000]); // limit for CER encoding.
+    }
+
+    /**
+     * Return a stream representing the content target for this OCTET STRING
+     *
+     * @param buf the buffer to use for chunking the data.
+     * @return an OutputStream which chunks data in blocks of buf length.
+     */
+    public OutputStream getOctetOutputStream(
+        byte[] buf)
+    {
+        return new BufferedBEROctetStream(buf);
+    }
+   
+    private class BufferedBEROctetStream
+        extends OutputStream
+    {
+        private byte[] _buf;
+        private int    _off;
+        private DEROutputStream _derOut;
+
+        BufferedBEROctetStream(
+            byte[] buf)
+        {
+            _buf = buf;
+            _off = 0;
+            _derOut = new DEROutputStream(_out);
+        }
+        
+        public void write(
+            int b)
+            throws IOException
+        {
+            _buf[_off++] = (byte)b;
+
+            if (_off == _buf.length)
+            {
+                DEROctetString.encode(_derOut, _buf);
+                _off = 0;
+            }
+        }
+
+        public void write(byte[] b, int off, int len) throws IOException
+        {
+            while (len > 0)
+            {
+                int numToCopy = Math.min(len, _buf.length - _off);
+                System.arraycopy(b, off, _buf, _off, numToCopy);
+
+                _off += numToCopy;
+                if (_off < _buf.length)
+                {
+                    break;
+                }
+
+                DEROctetString.encode(_derOut, _buf);
+                _off = 0;
+
+                off += numToCopy;
+                len -= numToCopy;
+            }
+        }
+
+        public void close() 
+            throws IOException
+        {
+            if (_off != 0)
+            {
+                byte[] bytes = new byte[_off];
+                System.arraycopy(_buf, 0, bytes, 0, _off);
+                
+                DEROctetString.encode(_derOut, bytes);
+            }
+            
+             writeBEREnd();
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROctetStringParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROctetStringParser.java
new file mode 100644
index 0000000..64ce07d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROctetStringParser.java
@@ -0,0 +1,62 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.android.internal.org.bouncycastle.util.io.Streams;
+
+/**
+ * A parser for indefinite-length OCTET STRINGs.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BEROctetStringParser
+    implements ASN1OctetStringParser
+{
+    private ASN1StreamParser _parser;
+
+    BEROctetStringParser(
+        ASN1StreamParser parser)
+    {
+        _parser = parser;
+    }
+
+    /**
+     * Return an InputStream representing the contents of the OCTET STRING.
+     *
+     * @return an InputStream with its source as the OCTET STRING content.
+     */
+    public InputStream getOctetStream()
+    {
+        return new ConstructedOctetStream(_parser);
+    }
+
+    /**
+     * Return an in-memory, encodable, representation of the OCTET STRING.
+     *
+     * @return a BEROctetString.
+     * @throws IOException if there is an issue loading the data.
+     */
+    public ASN1Primitive getLoadedObject()
+        throws IOException
+    {
+        return new BEROctetString(Streams.readAll(getOctetStream()));
+    }
+
+    /**
+     * Return an BEROctetString representing this parser and its contents.
+     *
+     * @return an BEROctetString
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        try
+        {
+            return getLoadedObject();
+        }
+        catch (IOException e)
+        {
+            throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROutputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROutputStream.java
new file mode 100644
index 0000000..6e731f0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BEROutputStream.java
@@ -0,0 +1,53 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A class which writes indefinite and definite length objects. Objects which specify DER will be encoded accordingly, but DL or BER
+ * objects will be encoded as defined.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BEROutputStream
+    extends DEROutputStream
+{
+    /**
+     * Base constructor.
+     *
+     * @param os target output stream.
+     */
+    public BEROutputStream(
+        OutputStream    os)
+    {
+        super(os);
+    }
+
+    /**
+     * Write out an ASN.1 object.
+     *
+     * @param obj the object to be encoded.
+     * @throws IOException if there is an issue on encoding or output of the object.
+     */
+    public void writeObject(
+        Object    obj)
+        throws IOException
+    {
+        if (obj == null)
+        {
+            writeNull();
+        }
+        else if (obj instanceof ASN1Primitive)
+        {
+            ((ASN1Primitive)obj).encode(this);
+        }
+        else if (obj instanceof ASN1Encodable)
+        {
+            ((ASN1Encodable)obj).toASN1Primitive().encode(this);
+        }
+        else
+        {
+            throw new IOException("object not BEREncodable");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSequence.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSequence.java
new file mode 100644
index 0000000..d4788e9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSequence.java
@@ -0,0 +1,81 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * Indefinite length SEQUENCE of objects.
+ * <p>
+ * Length field has value 0x80, and the sequence ends with two bytes of: 0x00, 0x00.
+ * </p><p>
+ * For X.690 syntax rules, see {@link ASN1Sequence}.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BERSequence
+    extends ASN1Sequence
+{
+    /**
+     * Create an empty sequence
+     */
+    public BERSequence()
+    {
+    }
+
+    /**
+     * Create a sequence containing one object
+     */
+    public BERSequence(
+        ASN1Encodable obj)
+    {
+        super(obj);
+    }
+
+    /**
+     * Create a sequence containing a vector of objects.
+     */
+    public BERSequence(
+        ASN1EncodableVector v)
+    {
+        super(v);
+    }
+
+    /**
+     * Create a sequence containing an array of objects.
+     */
+    public BERSequence(
+        ASN1Encodable[]   array)
+    {
+        super(array);
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = 0;
+        for (Enumeration e = getObjects(); e.hasMoreElements();)
+        {
+            length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+        }
+
+        return 2 + length + 2;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
+        out.write(0x80);
+
+        Enumeration e = getObjects();
+        while (e.hasMoreElements())
+        {
+            out.writeObject((ASN1Encodable)e.nextElement());
+        }
+
+        out.write(0x00);
+        out.write(0x00);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSequenceParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSequenceParser.java
new file mode 100644
index 0000000..d2ce184
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSequenceParser.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Parser for indefinite-length SEQUENCEs.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BERSequenceParser
+    implements ASN1SequenceParser
+{
+    private ASN1StreamParser _parser;
+
+    BERSequenceParser(ASN1StreamParser parser)
+    {
+        this._parser = parser;
+    }
+
+    /**
+     * Read the next object in the SEQUENCE.
+     *
+     * @return the next object in the SEQUENCE, null if there are no more.
+     * @throws IOException if there is an issue reading the underlying stream.
+     */
+    public ASN1Encodable readObject()
+        throws IOException
+    {
+        return _parser.readObject();
+    }
+
+    /**
+     * Return an in-memory, encodable, representation of the SEQUENCE.
+     *
+     * @return a BERSequence.
+     * @throws IOException if there is an issue loading the data.
+     */
+    public ASN1Primitive getLoadedObject()
+        throws IOException
+    {
+        return new BERSequence(_parser.readVector());
+    }
+
+    /**
+     * Return an BERSequence representing this parser and its contents.
+     *
+     * @return an BERSequence
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        try
+        {
+            return getLoadedObject();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException(e.getMessage());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSet.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSet.java
new file mode 100644
index 0000000..547c7ba
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSet.java
@@ -0,0 +1,91 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * Indefinite length <code>SET</code> and <code>SET OF</code> constructs.
+ * <p>
+ * Note: This does not know which syntax the set is!
+ * </p><p>
+ * Length field has value 0x80, and the set ends with two bytes of: 0x00, 0x00.
+ * </p><p>
+ * For X.690 syntax rules, see {@link ASN1Set}.
+ * </p><p>
+ * In brief: Constructing this form does not sort the supplied elements,
+ * nor does the sorting happen before serialization. This is different
+ * from the way {@link DERSet} does things.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BERSet
+    extends ASN1Set
+{
+    /**
+     * Create an empty SET.
+     */
+    public BERSet()
+    {
+    }
+
+    /**
+     * Create a SET containing one object.
+     *
+     * @param obj - a single object that makes up the set.
+     */
+    public BERSet(
+        ASN1Encodable obj)
+    {
+        super(obj);
+    }
+
+    /**
+     * Create a SET containing multiple objects.
+     * @param v a vector of objects making up the set.
+     */
+    public BERSet(
+        ASN1EncodableVector v)
+    {
+        super(v, false);
+    }
+
+    /**
+     * Create a SET from an array of objects.
+     * @param a an array of ASN.1 objects.
+     */
+    public BERSet(
+        ASN1Encodable[]   a)
+    {
+        super(a, false);
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = 0;
+        for (Enumeration e = getObjects(); e.hasMoreElements();)
+        {
+            length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+        }
+
+        return 2 + length + 2;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.write(BERTags.SET | BERTags.CONSTRUCTED);
+        out.write(0x80);
+
+        Enumeration e = getObjects();
+        while (e.hasMoreElements())
+        {
+            out.writeObject((ASN1Encodable)e.nextElement());
+        }
+
+        out.write(0x00);
+        out.write(0x00);
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSetParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSetParser.java
new file mode 100644
index 0000000..e66b756
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERSetParser.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Parser for indefinite-length SETs.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BERSetParser
+    implements ASN1SetParser
+{
+    private ASN1StreamParser _parser;
+
+    BERSetParser(ASN1StreamParser parser)
+    {
+        this._parser = parser;
+    }
+
+    /**
+     * Read the next object in the SET.
+     *
+     * @return the next object in the SET, null if there are no more.
+     * @throws IOException if there is an issue reading the underlying stream.
+     */
+    public ASN1Encodable readObject()
+        throws IOException
+    {
+        return _parser.readObject();
+    }
+
+    /**
+     * Return an in-memory, encodable, representation of the SET.
+     *
+     * @return a BERSet.
+     * @throws IOException if there is an issue loading the data.
+     */
+    public ASN1Primitive getLoadedObject()
+        throws IOException
+    {
+        return new BERSet(_parser.readVector());
+    }
+
+    /**
+     * Return an BERSet representing this parser and its contents.
+     *
+     * @return an BERSet
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        try
+        {
+            return getLoadedObject();
+        }
+        catch (IOException e)
+        {
+            throw new ASN1ParsingException(e.getMessage(), e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERTaggedObject.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERTaggedObject.java
new file mode 100644
index 0000000..42cd2e1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERTaggedObject.java
@@ -0,0 +1,149 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * BER TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BERTaggedObject
+    extends ASN1TaggedObject
+{
+    /**
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public BERTaggedObject(
+        int             tagNo,
+        ASN1Encodable    obj)
+    {
+        super(true, tagNo, obj);
+    }
+
+    /**
+     * @param explicit true if an explicitly tagged object.
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public BERTaggedObject(
+        boolean         explicit,
+        int             tagNo,
+        ASN1Encodable    obj)
+    {
+        super(explicit, tagNo, obj);
+    }
+
+    /**
+     * create an implicitly tagged object that contains a zero
+     * length sequence.
+     */
+    public BERTaggedObject(
+        int             tagNo)
+    {
+        super(false, tagNo, new BERSequence());
+    }
+
+    boolean isConstructed()
+    {
+        if (!empty)
+        {
+            if (explicit)
+            {
+                return true;
+            }
+            else
+            {
+                ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+
+                return primitive.isConstructed();
+            }
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        if (!empty)
+        {
+            ASN1Primitive primitive = obj.toASN1Primitive();
+            int length = primitive.encodedLength();
+
+            if (explicit)
+            {
+                return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
+            }
+            else
+            {
+                // header length already in calculation
+                length = length - 1;
+
+                return StreamUtil.calculateTagLength(tagNo) + length;
+            }
+        }
+        else
+        {
+            return StreamUtil.calculateTagLength(tagNo) + 1;
+        }
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
+        out.write(0x80);
+
+        if (!empty)
+        {
+            if (!explicit)
+            {
+                Enumeration e;
+                if (obj instanceof ASN1OctetString)
+                {
+                    if (obj instanceof BEROctetString)
+                    {
+                        e = ((BEROctetString)obj).getObjects();
+                    }
+                    else
+                    {
+                        ASN1OctetString             octs = (ASN1OctetString)obj;
+                        BEROctetString berO = new BEROctetString(octs.getOctets());
+                        e = berO.getObjects();
+                    }
+                }
+                else if (obj instanceof ASN1Sequence)
+                {
+                    e = ((ASN1Sequence)obj).getObjects();
+                }
+                else if (obj instanceof ASN1Set)
+                {
+                    e = ((ASN1Set)obj).getObjects();
+                }
+                else
+                {
+                    throw new ASN1Exception("not implemented: " + obj.getClass().getName());
+                }
+
+                while (e.hasMoreElements())
+                {
+                    out.writeObject((ASN1Encodable)e.nextElement());
+                }
+            }
+            else
+            {
+                out.writeObject(obj);
+            }
+        }
+
+        out.write(0x00);
+        out.write(0x00);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERTaggedObjectParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERTaggedObjectParser.java
new file mode 100644
index 0000000..0b8ddfd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERTaggedObjectParser.java
@@ -0,0 +1,100 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Parser for indefinite-length tagged objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BERTaggedObjectParser
+    implements ASN1TaggedObjectParser
+{
+    private boolean _constructed;
+    private int _tagNumber;
+    private ASN1StreamParser _parser;
+
+    BERTaggedObjectParser(
+        boolean             constructed,
+        int                 tagNumber,
+        ASN1StreamParser    parser)
+    {
+        _constructed = constructed;
+        _tagNumber = tagNumber;
+        _parser = parser;
+    }
+
+    /**
+     * Return true if this tagged object is marked as constructed.
+     *
+     * @return true if constructed, false otherwise.
+     */
+    public boolean isConstructed()
+    {
+        return _constructed;
+    }
+
+    /**
+     * Return the tag number associated with this object.
+     *
+     * @return the tag number.
+     */
+    public int getTagNo()
+    {
+        return _tagNumber;
+    }
+
+    /**
+     * Return an object parser for the contents of this tagged object.
+     *
+     * @param tag the actual tag number of the object (needed if implicit).
+     * @param isExplicit true if the contained object was explicitly tagged, false if implicit.
+     * @return an ASN.1 encodable object parser.
+     * @throws IOException if there is an issue building the object parser from the stream.
+     */
+    public ASN1Encodable getObjectParser(
+        int     tag,
+        boolean isExplicit)
+        throws IOException
+    {
+        if (isExplicit)
+        {
+            if (!_constructed)
+            {
+                throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
+            }
+            return _parser.readObject();
+        }
+
+        return _parser.readImplicit(_constructed, tag);
+    }
+
+    /**
+     * Return an in-memory, encodable, representation of the tagged object.
+     *
+     * @return an ASN1TaggedObject.
+     * @throws IOException if there is an issue loading the data.
+     */
+    public ASN1Primitive getLoadedObject()
+        throws IOException
+    {
+        return _parser.readTaggedObject(_constructed, _tagNumber);
+    }
+
+    /**
+     * Return an ASN1TaggedObject representing this parser and its contents.
+     *
+     * @return an ASN1TaggedObject
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        try
+        {
+            return this.getLoadedObject();
+        }
+        catch (IOException e)
+        {
+            throw new ASN1ParsingException(e.getMessage());
+        }
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERTags.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERTags.java
new file mode 100644
index 0000000..87649f6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/BERTags.java
@@ -0,0 +1,40 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface BERTags
+{
+    public static final int BOOLEAN             = 0x01;
+    public static final int INTEGER             = 0x02;
+    public static final int BIT_STRING          = 0x03;
+    public static final int OCTET_STRING        = 0x04;
+    public static final int NULL                = 0x05;
+    public static final int OBJECT_IDENTIFIER   = 0x06;
+    public static final int EXTERNAL            = 0x08;
+    public static final int ENUMERATED          = 0x0a; // decimal 10
+    public static final int SEQUENCE            = 0x10; // decimal 16
+    public static final int SEQUENCE_OF         = 0x10; // for completeness - used to model a SEQUENCE of the same type.
+    public static final int SET                 = 0x11; // decimal 17
+    public static final int SET_OF              = 0x11; // for completeness - used to model a SET of the same type.
+
+
+    public static final int NUMERIC_STRING      = 0x12; // decimal 18
+    public static final int PRINTABLE_STRING    = 0x13; // decimal 19
+    public static final int T61_STRING          = 0x14; // decimal 20
+    public static final int VIDEOTEX_STRING     = 0x15; // decimal 21
+    public static final int IA5_STRING          = 0x16; // decimal 22
+    public static final int UTC_TIME            = 0x17; // decimal 23
+    public static final int GENERALIZED_TIME    = 0x18; // decimal 24
+    public static final int GRAPHIC_STRING      = 0x19; // decimal 25
+    public static final int VISIBLE_STRING      = 0x1a; // decimal 26
+    public static final int GENERAL_STRING      = 0x1b; // decimal 27
+    public static final int UNIVERSAL_STRING    = 0x1c; // decimal 28
+    public static final int BMP_STRING          = 0x1e; // decimal 30
+    public static final int UTF8_STRING         = 0x0c; // decimal 12
+    
+    public static final int CONSTRUCTED         = 0x20; // decimal 32
+    public static final int APPLICATION         = 0x40; // decimal 64
+    public static final int TAGGED              = 0x80; // decimal 128
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ConstructedOctetStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ConstructedOctetStream.java
new file mode 100644
index 0000000..9042c9c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ConstructedOctetStream.java
@@ -0,0 +1,112 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class ConstructedOctetStream
+    extends InputStream
+{
+    private final ASN1StreamParser _parser;
+
+    private boolean                _first = true;
+    private InputStream            _currentStream;
+
+    ConstructedOctetStream(
+        ASN1StreamParser parser)
+    {
+        _parser = parser;
+    }
+
+    public int read(byte[] b, int off, int len) throws IOException
+    {
+        if (_currentStream == null)
+        {
+            if (!_first)
+            {
+                return -1;
+            }
+
+            ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
+
+            if (s == null)
+            {
+                return -1;
+            }
+
+            _first = false;
+            _currentStream = s.getOctetStream();
+        }
+
+        int totalRead = 0;
+
+        for (;;)
+        {
+            int numRead = _currentStream.read(b, off + totalRead, len - totalRead);
+
+            if (numRead >= 0)
+            {
+                totalRead += numRead;
+
+                if (totalRead == len)
+                {
+                    return totalRead;
+                }
+            }
+            else
+            {
+                ASN1OctetStringParser aos = (ASN1OctetStringParser)_parser.readObject();
+
+                if (aos == null)
+                {
+                    _currentStream = null;
+                    return totalRead < 1 ? -1 : totalRead;
+                }
+
+                _currentStream = aos.getOctetStream();
+            }
+        }
+    }
+
+    public int read()
+        throws IOException
+    {
+        if (_currentStream == null)
+        {
+            if (!_first)
+            {
+                return -1;
+            }
+
+            ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
+    
+            if (s == null)
+            {
+                return -1;
+            }
+    
+            _first = false;
+            _currentStream = s.getOctetStream();
+        }
+
+        for (;;)
+        {
+            int b = _currentStream.read();
+
+            if (b >= 0)
+            {
+                return b;
+            }
+
+            ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
+
+            if (s == null)
+            {
+                _currentStream = null;
+                return -1;
+            }
+
+            _currentStream = s.getOctetStream();
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERApplicationSpecific.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERApplicationSpecific.java
new file mode 100644
index 0000000..03ab923
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERApplicationSpecific.java
@@ -0,0 +1,126 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * A DER encoding version of an application specific object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERApplicationSpecific 
+    extends ASN1ApplicationSpecific
+{
+    DERApplicationSpecific(
+        boolean isConstructed,
+        int     tag,
+        byte[]  octets)
+    {
+        super(isConstructed, tag, octets);
+    }
+
+    /**
+     * Create an application specific object from the passed in data. This will assume
+     * the data does not represent a constructed object.
+     *
+     * @param tag the tag number for this object.
+     * @param octets the encoding of the object's body.
+     */
+    public DERApplicationSpecific(
+        int    tag,
+        byte[] octets)
+    {
+        this(false, tag, octets);
+    }
+
+    /**
+     * Create an application specific object with a tagging of explicit/constructed.
+     *
+     * @param tag the tag number for this object.
+     * @param object the object to be contained.
+     */
+    public DERApplicationSpecific(
+        int           tag,
+        ASN1Encodable object)
+        throws IOException 
+    {
+        this(true, tag, object);
+    }
+
+    /**
+     * Create an application specific object with the tagging style given by the value of constructed.
+     *
+     * @param constructed true if the object is constructed.
+     * @param tag the tag number for this object.
+     * @param object the object to be contained.
+     */
+    public DERApplicationSpecific(
+        boolean      constructed,
+        int          tag,
+        ASN1Encodable object)
+        throws IOException
+    {
+        super(constructed || object.toASN1Primitive().isConstructed(), tag, getEncoding(constructed, object));
+    }
+
+    private static byte[] getEncoding(boolean explicit, ASN1Encodable object)
+        throws IOException
+    {
+        byte[] data = object.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+
+        if (explicit)
+        {
+            return data;
+        }
+        else
+        {
+            int lenBytes = getLengthOfHeader(data);
+            byte[] tmp = new byte[data.length - lenBytes];
+            System.arraycopy(data, lenBytes, tmp, 0, tmp.length);
+            return tmp;
+        }
+    }
+
+    /**
+     * Create an application specific object which is marked as constructed
+     *
+     * @param tagNo the tag number for this object.
+     * @param vec the objects making up the application specific object.
+     */
+    public DERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
+    {
+        super(true, tagNo, getEncodedVector(vec));
+    }
+
+    private static byte[] getEncodedVector(ASN1EncodableVector vec)
+    {
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+        for (int i = 0; i != vec.size(); i++)
+        {
+            try
+            {
+                bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.DER));
+            }
+            catch (IOException e)
+            {
+                throw new ASN1ParsingException("malformed object: " + e, e);
+            }
+        }
+        return bOut.toByteArray();
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
+     */
+    void encode(ASN1OutputStream out) throws IOException
+    {
+        int classBits = BERTags.APPLICATION;
+        if (isConstructed)
+        {
+            classBits |= BERTags.CONSTRUCTED;
+        }
+
+        out.writeEncoded(classBits, tag, octets);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERBMPString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERBMPString.java
new file mode 100644
index 0000000..c93b85a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERBMPString.java
@@ -0,0 +1,164 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * DER BMPString object encodes BMP (<i>Basic Multilingual Plane</i>) subset
+ * (aka UCS-2) of UNICODE (ISO 10646) characters in codepoints 0 to 65535.
+ * <p>
+ * At ISO-10646:2011 the term "BMP" has been withdrawn, and replaced by
+ * term "UCS-2".
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERBMPString
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private final char[]  string;
+
+    /**
+     * Return a BMP String from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return a DERBMPString instance, or null.
+     */
+    public static DERBMPString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERBMPString)
+        {
+            return (DERBMPString)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERBMPString)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return a BMP String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *              be converted.
+     * @return a DERBMPString instance.
+     */
+    public static DERBMPString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERBMPString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERBMPString(ASN1OctetString.getInstance(o).getOctets());
+        }
+    }
+
+    /**
+     * Basic constructor - byte encoded string.
+     * @param string the encoded BMP STRING to wrap.
+     */
+    DERBMPString(
+        byte[]   string)
+    {
+        char[]  cs = new char[string.length / 2];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            cs[i] = (char)((string[2 * i] << 8) | (string[2 * i + 1] & 0xff));
+        }
+
+        this.string = cs;
+    }
+
+    DERBMPString(char[] string)
+    {
+        this.string = string;
+    }
+
+    /**
+     * Basic constructor
+     * @param string a String to wrap as a BMP STRING.
+     */
+    public DERBMPString(
+        String   string)
+    {
+        this.string = string.toCharArray();
+    }
+
+    public String getString()
+    {
+        return new String(string);
+    }
+
+    public String toString()
+    {
+        return getString();
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(string);
+    }
+
+    protected boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof DERBMPString))
+        {
+            return false;
+        }
+
+        DERBMPString  s = (DERBMPString)o;
+
+        return Arrays.areEqual(string, s.string);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length * 2) + (string.length * 2);
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.write(BERTags.BMP_STRING);
+        out.writeLength(string.length * 2);
+
+        for (int i = 0; i != string.length; i++)
+        {
+            char c = string[i];
+
+            out.write((byte)(c >> 8));
+            out.write((byte)c);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERBitString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERBitString.java
new file mode 100644
index 0000000..8527564
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERBitString.java
@@ -0,0 +1,158 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * A BIT STRING with DER encoding - the first byte contains the count of padding bits included in the byte array's last byte.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERBitString
+    extends ASN1BitString
+{
+    /**
+     * return a Bit String from the passed in object
+     *
+     * @param obj a DERBitString or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return a DERBitString instance, or null.
+     */
+    public static DERBitString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERBitString)
+        {
+            return (DERBitString)obj;
+        }
+        if (obj instanceof DLBitString)
+        {
+            return new DERBitString(((DLBitString)obj).data, ((DLBitString)obj).padBits);
+        }
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERBitString)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a Bit String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return a DERBitString instance, or null.
+     */
+    public static DERBitString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERBitString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return fromOctetString(((ASN1OctetString)o).getOctets());
+        }
+    }
+    
+    protected DERBitString(
+        byte    data,
+        int     padBits)
+    {
+        this(toByteArray(data), padBits);
+    }
+
+    private static byte[] toByteArray(byte data)
+    {
+        byte[] rv = new byte[1];
+
+        rv[0] = data;
+
+        return rv;
+    }
+
+    /**
+     * @param data the octets making up the bit string.
+     * @param padBits the number of extra bits at the end of the string.
+     */
+    public DERBitString(
+        byte[]  data,
+        int     padBits)
+    {
+        super(data, padBits);
+    }
+
+    public DERBitString(
+        byte[]  data)
+    {
+        this(data, 0);
+    }
+
+    public DERBitString(
+        int value)
+    {
+        super(getBytes(value), getPadBits(value));
+    }
+
+    public DERBitString(
+        ASN1Encodable obj)
+        throws IOException
+    {
+        super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER), 0);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        byte[] string = derForm(data, padBits);
+        byte[] bytes = new byte[string.length + 1];
+
+        bytes[0] = (byte)getPadBits();
+        System.arraycopy(string, 0, bytes, 1, bytes.length - 1);
+
+        out.writeEncoded(BERTags.BIT_STRING, bytes);
+    }
+
+    static DERBitString fromOctetString(byte[] bytes)
+    {
+        if (bytes.length < 1)
+        {
+            throw new IllegalArgumentException("truncated BIT STRING detected");
+        }
+
+        int padBits = bytes[0];
+        byte[] data = new byte[bytes.length - 1];
+
+        if (data.length != 0)
+        {
+            System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
+        }
+
+        return new DERBitString(data, padBits);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERBoolean.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERBoolean.java
new file mode 100644
index 0000000..0b6f8b7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERBoolean.java
@@ -0,0 +1,24 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+/**
+ * @deprecated use ASN1Boolean
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERBoolean
+    extends ASN1Boolean
+{
+    /**
+     * @deprecated use getInstance(boolean) method.
+     * @param value
+     */
+    public DERBoolean(boolean value)
+    {
+        super(value);
+    }
+
+    DERBoolean(byte[] value)
+    {
+        super(value);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEREncodableVector.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEREncodableVector.java
new file mode 100644
index 0000000..2c53b69
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEREncodableVector.java
@@ -0,0 +1,20 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+/**
+ * a general class for building up a vector of DER encodable objects -
+ * this will eventually be superseded by ASN1EncodableVector so you should
+ * use that class in preference.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DEREncodableVector
+    extends ASN1EncodableVector
+{
+    /**
+     * @deprecated use ASN1EncodableVector instead.
+     */
+    public DEREncodableVector()
+    {
+
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEREnumerated.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEREnumerated.java
new file mode 100644
index 0000000..6069d1e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEREnumerated.java
@@ -0,0 +1,39 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.math.BigInteger;
+
+/**
+ * @deprecated Use ASN1Enumerated instead of this.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DEREnumerated
+    extends ASN1Enumerated
+{
+    /**
+     * @param bytes the value of this enumerated as an encoded BigInteger (signed).
+     * @deprecated use ASN1Enumerated
+     */
+    DEREnumerated(byte[] bytes)
+    {
+        super(bytes);
+    }
+
+    /**
+     * @param value the value of this enumerated.
+     * @deprecated use ASN1Enumerated
+     */
+    public DEREnumerated(BigInteger value)
+    {
+        super(value);
+    }
+
+    /**
+     * @param value the value of this enumerated.
+     * @deprecated use ASN1Enumerated
+     */
+    public DEREnumerated(int value)
+    {
+        super(value);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERExternal.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERExternal.java
new file mode 100644
index 0000000..0357b1c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERExternal.java
@@ -0,0 +1,87 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Class representing the DER-type External
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERExternal
+    extends ASN1External
+{
+    /**
+     * Construct a DER EXTERNAL object, the input encoding vector must have exactly two elements on it.
+     * <p>
+     * Acceptable input formats are:
+     * <ul>
+     * <li> {@link ASN1ObjectIdentifier} + data {@link DERTaggedObject} (direct reference form)</li>
+     * <li> {@link ASN1Integer} + data {@link DERTaggedObject} (indirect reference form)</li>
+     * <li> Anything but {@link DERTaggedObject} + data {@link DERTaggedObject} (data value form)</li>
+     * </ul>
+     *
+     * @throws IllegalArgumentException if input size is wrong, or
+     */
+    public DERExternal(ASN1EncodableVector vector)
+    {
+        super(vector);
+    }
+
+    /**
+     * Creates a new instance of DERExternal
+     * See X.690 for more informations about the meaning of these parameters
+     * @param directReference The direct reference or <code>null</code> if not set.
+     * @param indirectReference The indirect reference or <code>null</code> if not set.
+     * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
+     * @param externalData The external data in its encoded form.
+     */
+    public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData)
+    {
+        this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive());
+    }
+
+    /**
+     * Creates a new instance of DERExternal.
+     * See X.690 for more informations about the meaning of these parameters
+     * @param directReference The direct reference or <code>null</code> if not set.
+     * @param indirectReference The indirect reference or <code>null</code> if not set.
+     * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
+     * @param encoding The encoding to be used for the external data
+     * @param externalData The external data
+     */
+    public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData)
+    {
+        super(directReference, indirectReference, dataValueDescriptor, encoding, externalData);
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        return this.getEncoded().length;
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
+     */
+    void encode(ASN1OutputStream out)
+        throws IOException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        if (directReference != null)
+        {
+            baos.write(directReference.getEncoded(ASN1Encoding.DER));
+        }
+        if (indirectReference != null)
+        {
+            baos.write(indirectReference.getEncoded(ASN1Encoding.DER));
+        }
+        if (dataValueDescriptor != null)
+        {
+            baos.write(dataValueDescriptor.getEncoded(ASN1Encoding.DER));
+        }
+        DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent);
+        baos.write(obj.getEncoded(ASN1Encoding.DER));
+        out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERExternalParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERExternalParser.java
new file mode 100644
index 0000000..c400ab4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERExternalParser.java
@@ -0,0 +1,70 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Parser DER EXTERNAL tagged objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERExternalParser
+    implements ASN1Encodable, InMemoryRepresentable
+{
+    private ASN1StreamParser _parser;
+
+    /**
+     * Base constructor.
+     *
+     * @param parser the underlying parser to read the DER EXTERNAL from.
+     */
+    public DERExternalParser(ASN1StreamParser parser)
+    {
+        this._parser = parser;
+    }
+
+    public ASN1Encodable readObject()
+        throws IOException
+    {
+        return _parser.readObject();
+    }
+
+    /**
+     * Return an in-memory, encodable, representation of the EXTERNAL object.
+     *
+     * @return a DERExternal.
+     * @throws IOException if there is an issue loading the data.
+     */
+    public ASN1Primitive getLoadedObject()
+        throws IOException
+    {
+        try
+        {
+            return new DLExternal(_parser.readVector());
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw new ASN1Exception(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Return an DERExternal representing this parser and its contents.
+     *
+     * @return an DERExternal
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        try
+        {
+            return getLoadedObject();
+        }
+        catch (IOException ioe)
+        {
+            throw new ASN1ParsingException("unable to get DER object", ioe);
+        }
+        catch (IllegalArgumentException ioe)
+        {
+            throw new ASN1ParsingException("unable to get DER object", ioe);
+        }
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERFactory.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERFactory.java
new file mode 100644
index 0000000..df38995
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERFactory.java
@@ -0,0 +1,18 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+class DERFactory
+{
+    static final ASN1Sequence EMPTY_SEQUENCE = new DERSequence();
+    static final ASN1Set EMPTY_SET = new DERSet();
+
+    static ASN1Sequence createSequence(ASN1EncodableVector v)
+    {
+        return v.size() < 1 ? EMPTY_SEQUENCE : new DLSequence(v);
+    }
+
+    static ASN1Set createSet(ASN1EncodableVector v)
+    {
+        return v.size() < 1 ? EMPTY_SET : new DLSet(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERGeneralString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERGeneralString.java
new file mode 100644
index 0000000..690a945
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERGeneralString.java
@@ -0,0 +1,151 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * ASN.1 GENERAL-STRING data type.
+ * <p>
+ * This is an 8-bit encoded ISO 646 (ASCII) character set
+ * with optional escapes to other character sets.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERGeneralString 
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private final byte[] string;
+
+    /**
+     * Return a GeneralString from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return a DERBMPString instance, or null.
+     */
+    public static DERGeneralString getInstance(
+        Object obj) 
+    {
+        if (obj == null || obj instanceof DERGeneralString) 
+        {
+            return (DERGeneralString) obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERGeneralString)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: "
+                + obj.getClass().getName());
+    }
+
+    /**
+     * Return a GeneralString from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *              be converted.
+     * @return a DERGeneralString instance.
+     */
+    public static DERGeneralString getInstance(
+        ASN1TaggedObject obj, 
+        boolean explicit) 
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERGeneralString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERGeneralString(((ASN1OctetString)o).getOctets());
+        }
+    }
+
+    DERGeneralString(byte[] string)
+    {
+        this.string = string;
+    }
+
+    /**
+     * Construct a GeneralString from the passed in String.
+     *
+     * @param string the string to be contained in this object.
+     */
+    public DERGeneralString(String string) 
+    {
+        this.string = Strings.toByteArray(string);
+    }
+
+    /**
+     * Return a Java String representation of our contained String.
+     *
+     * @return a Java String representing our contents.
+     */
+    public String getString() 
+    {
+        return Strings.fromByteArray(string);
+    }
+
+    public String toString()
+    {
+        return getString();
+    }
+
+    /**
+     * Return a byte array representation of our contained String.
+     *
+     * @return a byte array representing our contents.
+     */
+    public byte[] getOctets() 
+    {
+        return Arrays.clone(string);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(ASN1OutputStream out)
+        throws IOException 
+    {
+        out.writeEncoded(BERTags.GENERAL_STRING, string);
+    }
+    
+    public int hashCode() 
+    {
+        return Arrays.hashCode(string);
+    }
+    
+    boolean asn1Equals(ASN1Primitive o)
+    {
+        if (!(o instanceof DERGeneralString)) 
+        {
+            return false;
+        }
+        DERGeneralString s = (DERGeneralString)o;
+
+        return Arrays.areEqual(string, s.string);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERGeneralizedTime.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERGeneralizedTime.java
new file mode 100644
index 0000000..a3c4be8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERGeneralizedTime.java
@@ -0,0 +1,118 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Date;
+
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * DER Generalized time object.
+ * <h3>11: Restrictions on BER employed by both CER and DER</h3>
+ * <h4>11.7 GeneralizedTime </h4>
+ * <p>
+ * <b>11.7.1</b> The encoding shall terminate with a "Z",
+ * as described in the ITU-T Rec. X.680 | ISO/IEC 8824-1 clause on
+ * GeneralizedTime.
+ * </p><p>
+ * <b>11.7.2</b> The seconds element shall always be present.
+ * </p>
+ * <p>
+ * <b>11.7.3</b> The fractional-seconds elements, if present,
+ * shall omit all trailing zeros; if the elements correspond to 0,
+ * they shall be wholly omitted, and the decimal point element also
+ * shall be omitted.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERGeneralizedTime
+    extends ASN1GeneralizedTime
+{
+    public DERGeneralizedTime(byte[] time)
+    {
+        super(time);
+    }
+
+    public DERGeneralizedTime(Date time)
+    {
+        super(time);
+    }
+
+    public DERGeneralizedTime(String time)
+    {
+        super(time);
+    }
+
+    private byte[] getDERTime()
+    {
+        if (time[time.length - 1] == 'Z')
+        {
+            if (!hasMinutes())
+            {
+                byte[] derTime = new byte[time.length + 4];
+
+                System.arraycopy(time, 0, derTime, 0, time.length - 1);
+                System.arraycopy(Strings.toByteArray("0000Z"), 0, derTime, time.length - 1, 5);
+
+                return derTime;
+            }
+            else if (!hasSeconds())
+            {
+                byte[] derTime = new byte[time.length + 2];
+
+                System.arraycopy(time, 0, derTime, 0, time.length - 1);
+                System.arraycopy(Strings.toByteArray("00Z"), 0, derTime, time.length - 1, 3);
+
+                return derTime;
+            }
+            else if (hasFractionalSeconds())
+            {
+                int ind = time.length - 2;
+                while (ind > 0 && time[ind] == '0')
+                {
+                    ind--;
+                }
+
+                if (time[ind] == '.')
+                {
+                    byte[] derTime = new byte[ind + 1];
+
+                    System.arraycopy(time, 0, derTime, 0, ind);
+                    derTime[ind] = (byte)'Z';
+
+                    return derTime;
+                }
+                else
+                {
+                    byte[] derTime = new byte[ind + 2];
+
+                    System.arraycopy(time, 0, derTime, 0, ind + 1);
+                    derTime[ind + 1] = (byte)'Z';
+
+                    return derTime;
+                }
+            }
+            else
+            {
+                return time;
+            }
+        }
+        else
+        {
+            return time; // TODO: is there a better way?
+        }
+    }
+
+    int encodedLength()
+    {
+        int length = getDERTime().length;
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.GENERALIZED_TIME, getDERTime());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERGraphicString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERGraphicString.java
new file mode 100644
index 0000000..1a5a2a7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERGraphicString.java
@@ -0,0 +1,128 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERGraphicString
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private final byte[] string;
+    
+    /**
+     * return a Graphic String from the passed in object
+     *
+     * @param obj a DERGraphicString or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return a DERGraphicString instance, or null.
+     */
+    public static DERGraphicString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERGraphicString)
+        {
+            return (DERGraphicString)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERGraphicString)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a Graphic String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return a DERGraphicString instance, or null.
+     */
+    public static DERGraphicString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERGraphicString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERGraphicString(((ASN1OctetString)o).getOctets());
+        }
+    }
+
+    /**
+     * basic constructor - with bytes.
+     * @param string the byte encoding of the characters making up the string.
+     */
+    public DERGraphicString(
+        byte[]   string)
+    {
+        this.string = Arrays.clone(string);
+    }
+    
+    public byte[] getOctets()
+    {
+        return Arrays.clone(string);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.GRAPHIC_STRING, string);
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(string);
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof DERGraphicString))
+        {
+            return false;
+        }
+
+        DERGraphicString  s = (DERGraphicString)o;
+
+        return Arrays.areEqual(string, s.string);
+    }
+
+    public String getString()
+    {
+        return Strings.fromByteArray(string);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERIA5String.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERIA5String.java
new file mode 100644
index 0000000..df90706
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERIA5String.java
@@ -0,0 +1,194 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * DER IA5String object - this is a ISO 646 (ASCII) string encoding code points 0 to 127.
+ * <p>
+ * Explicit character set escape sequences are not allowed.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERIA5String
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private final byte[]  string;
+
+    /**
+     * Return an IA5 string from the passed in object
+     *
+     * @param obj a DERIA5String or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return a DERIA5String instance, or null.
+     */
+    public static DERIA5String getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERIA5String)
+        {
+            return (DERIA5String)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERIA5String)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return an IA5 String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return a DERIA5String instance, or null.
+     */
+    public static DERIA5String getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERIA5String)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERIA5String(((ASN1OctetString)o).getOctets());
+        }
+    }
+
+    /**
+     * Basic constructor - with bytes.
+     * @param string the byte encoding of the characters making up the string.
+     */
+    DERIA5String(
+        byte[]   string)
+    {
+        this.string = string;
+    }
+
+    /**
+     * Basic constructor - without validation.
+     * @param string the base string to use..
+     */
+    public DERIA5String(
+        String   string)
+    {
+        this(string, false);
+    }
+
+    /**
+     * Constructor with optional validation.
+     *
+     * @param string the base string to wrap.
+     * @param validate whether or not to check the string.
+     * @throws IllegalArgumentException if validate is true and the string
+     * contains characters that should not be in an IA5String.
+     */
+    public DERIA5String(
+        String   string,
+        boolean  validate)
+    {
+        if (string == null)
+        {
+            throw new NullPointerException("string cannot be null");
+        }
+        if (validate && !isIA5String(string))
+        {
+            throw new IllegalArgumentException("string contains illegal characters");
+        }
+
+        this.string = Strings.toByteArray(string);
+    }
+
+    public String getString()
+    {
+        return Strings.fromByteArray(string);
+    }
+
+    public String toString()
+    {
+        return getString();
+    }
+
+    public byte[] getOctets()
+    {
+        return Arrays.clone(string);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.IA5_STRING, string);
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(string);
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof DERIA5String))
+        {
+            return false;
+        }
+
+        DERIA5String  s = (DERIA5String)o;
+
+        return Arrays.areEqual(string, s.string);
+    }
+
+    /**
+     * return true if the passed in String can be represented without
+     * loss as an IA5String, false otherwise.
+     *
+     * @param str the string to check.
+     * @return true if character set in IA5String set, false otherwise.
+     */
+    public static boolean isIA5String(
+        String  str)
+    {
+        for (int i = str.length() - 1; i >= 0; i--)
+        {
+            char    ch = str.charAt(i);
+
+            if (ch > 0x007f)
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERInteger.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERInteger.java
new file mode 100644
index 0000000..bc7d548
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERInteger.java
@@ -0,0 +1,32 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.math.BigInteger;
+
+/**
+ * @deprecated  Use ASN1Integer instead of this,
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERInteger
+    extends ASN1Integer
+{
+    /**
+     * Constructor from a byte array containing a signed representation of the number.
+     *
+     * @param bytes a byte array containing the signed number.A copy is made of the byte array.
+     */
+    public DERInteger(byte[] bytes)
+    {
+        super(bytes, true);
+    }
+
+    public DERInteger(BigInteger value)
+    {
+        super(value);
+    }
+
+    public DERInteger(long value)
+    {
+        super(value);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERNull.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERNull.java
new file mode 100644
index 0000000..d080345
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERNull.java
@@ -0,0 +1,43 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * An ASN.1 DER NULL object.
+ * <p>
+ * Preferably use the constant:  DERNull.INSTANCE.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERNull
+    extends ASN1Null
+{
+    public static final DERNull INSTANCE = new DERNull();
+
+    private static final byte[]  zeroBytes = new byte[0];
+
+    /**
+     * @deprecated use DERNull.INSTANCE
+     */
+    // Android-changed: Reduce visibility to protected.
+    protected DERNull()
+    {
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 2;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.NULL, zeroBytes);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERNumericString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERNumericString.java
new file mode 100644
index 0000000..5907975
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERNumericString.java
@@ -0,0 +1,198 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }.
+ * ASN.1 NUMERIC-STRING object.
+ * <p>
+ * This is an ASCII string of characters {0,1,2,3,4,5,6,7,8,9} + space.
+ * <p>
+ * See X.680 section 37.2.
+ * <p>
+ * Explicit character set escape sequences are not allowed.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERNumericString
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private final byte[]  string;
+
+    /**
+     * Return a Numeric string from the passed in object
+     *
+     * @param obj a DERNumericString or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return a DERNumericString instance, or null
+     */
+    public static DERNumericString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERNumericString)
+        {
+            return (DERNumericString)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERNumericString)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return an Numeric String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return a DERNumericString instance, or null.
+     */
+    public static DERNumericString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERNumericString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERNumericString(ASN1OctetString.getInstance(o).getOctets());
+        }
+    }
+
+    /**
+     * Basic constructor - with bytes.
+     */
+    DERNumericString(
+        byte[]   string)
+    {
+        this.string = string;
+    }
+
+    /**
+     * Basic constructor -  without validation..
+     */
+    public DERNumericString(
+        String   string)
+    {
+        this(string, false);
+    }
+
+    /**
+     * Constructor with optional validation.
+     *
+     * @param string the base string to wrap.
+     * @param validate whether or not to check the string.
+     * @throws IllegalArgumentException if validate is true and the string
+     * contains characters that should not be in a NumericString.
+     */
+    public DERNumericString(
+        String   string,
+        boolean  validate)
+    {
+        if (validate && !isNumericString(string))
+        {
+            throw new IllegalArgumentException("string contains illegal characters");
+        }
+
+        this.string = Strings.toByteArray(string);
+    }
+
+    public String getString()
+    {
+        return Strings.fromByteArray(string);
+    }
+
+    public String toString()
+    {
+        return getString();
+    }
+
+    public byte[] getOctets()
+    {
+        return Arrays.clone(string);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.NUMERIC_STRING, string);
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(string);
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof DERNumericString))
+        {
+            return false;
+        }
+
+        DERNumericString  s = (DERNumericString)o;
+
+        return Arrays.areEqual(string, s.string);
+    }
+
+    /**
+     * Return true if the string can be represented as a NumericString ('0'..'9', ' ')
+     *
+     * @param str string to validate.
+     * @return true if numeric, fale otherwise.
+     */
+    public static boolean isNumericString(
+        String  str)
+    {
+        for (int i = str.length() - 1; i >= 0; i--)
+        {
+            char    ch = str.charAt(i);
+
+            if (ch > 0x007f)
+            {
+                return false;
+            }
+
+            if (('0' <= ch && ch <= '9') || ch == ' ')
+            {
+                continue;
+            }
+
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERObjectIdentifier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERObjectIdentifier.java
new file mode 100644
index 0000000..1f497c5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERObjectIdentifier.java
@@ -0,0 +1,26 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+/**
+ *
+ * @deprecated Use ASN1ObjectIdentifier instead of this,
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERObjectIdentifier
+    extends ASN1ObjectIdentifier
+{
+    public DERObjectIdentifier(String identifier)
+    {
+        super(identifier);
+    }
+
+    DERObjectIdentifier(byte[] bytes)
+    {
+        super(bytes);
+    }
+
+    DERObjectIdentifier(ASN1ObjectIdentifier oid, String branch)
+    {
+        super(oid, branch);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEROctetString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEROctetString.java
new file mode 100644
index 0000000..b8f5dfa
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEROctetString.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Carrier class for a DER encoding OCTET STRING
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DEROctetString
+    extends ASN1OctetString
+{
+    /**
+     * Base constructor.
+     *
+     * @param string the octets making up the octet string.
+     */
+    public DEROctetString(
+        byte[]  string)
+    {
+        super(string);
+    }
+
+    /**
+     * Constructor from the encoding of an ASN.1 object.
+     *
+     * @param obj the object to be encoded.
+     */
+    public DEROctetString(
+        ASN1Encodable obj)
+        throws IOException
+    {
+        super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.OCTET_STRING, string);
+    }
+
+    static void encode(
+        DEROutputStream derOut,
+        byte[]          bytes)
+        throws IOException
+    {
+        derOut.writeEncoded(BERTags.OCTET_STRING, bytes);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEROctetStringParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEROctetStringParser.java
new file mode 100644
index 0000000..db2da30
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEROctetStringParser.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Parser for DER encoded OCTET STRINGS
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DEROctetStringParser
+    implements ASN1OctetStringParser
+{
+    private DefiniteLengthInputStream stream;
+
+    DEROctetStringParser(
+        DefiniteLengthInputStream stream)
+    {
+        this.stream = stream;
+    }
+
+    /**
+     * Return an InputStream representing the contents of the OCTET STRING.
+     *
+     * @return an InputStream with its source as the OCTET STRING content.
+     */
+    public InputStream getOctetStream()
+    {
+        return stream;
+    }
+
+    /**
+     * Return an in-memory, encodable, representation of the OCTET STRING.
+     *
+     * @return a DEROctetString.
+     * @throws IOException if there is an issue loading the data.
+     */
+    public ASN1Primitive getLoadedObject()
+        throws IOException
+    {
+        return new DEROctetString(stream.toByteArray());
+    }
+
+    /**
+     * Return an DEROctetString representing this parser and its contents.
+     *
+     * @return an DEROctetString
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        try
+        {
+            return getLoadedObject();
+        }
+        catch (IOException e)
+        {
+            throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEROutputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEROutputStream.java
new file mode 100644
index 0000000..2606c2a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DEROutputStream.java
@@ -0,0 +1,43 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Stream that outputs encoding based on distinguished encoding rules.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DEROutputStream
+    extends ASN1OutputStream
+{
+    public DEROutputStream(
+        OutputStream    os)
+    {
+        super(os);
+    }
+
+    public void writeObject(
+        ASN1Encodable obj)
+        throws IOException
+    {
+        if (obj != null)
+        {
+            obj.toASN1Primitive().toDERObject().encode(this);
+        }
+        else
+        {
+            throw new IOException("null object detected");
+        }
+    }
+
+    ASN1OutputStream getDERSubStream()
+    {
+        return this;
+    }
+
+    ASN1OutputStream getDLSubStream()
+    {
+        return this;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERPrintableString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERPrintableString.java
new file mode 100644
index 0000000..505d509
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERPrintableString.java
@@ -0,0 +1,241 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * DER PrintableString object.
+ * <p>
+ * X.680 section 37.4 defines PrintableString character codes as ASCII subset of following characters:
+ * </p>
+ * <ul>
+ * <li>Latin capital letters: 'A' .. 'Z'</li>
+ * <li>Latin small letters: 'a' .. 'z'</li>
+ * <li>Digits: '0'..'9'</li>
+ * <li>Space</li>
+ * <li>Apostrophe: '\''</li>
+ * <li>Left parenthesis: '('</li>
+ * <li>Right parenthesis: ')'</li>
+ * <li>Plus sign: '+'</li>
+ * <li>Comma: ','</li>
+ * <li>Hyphen-minus: '-'</li>
+ * <li>Full stop: '.'</li>
+ * <li>Solidus: '/'</li>
+ * <li>Colon: ':'</li>
+ * <li>Equals sign: '='</li>
+ * <li>Question mark: '?'</li>
+ * </ul>
+ * <p>
+ * Explicit character set escape sequences are not allowed.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERPrintableString
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private final byte[]  string;
+
+    /**
+     * Return a printable string from the passed in object.
+     *
+     * @param obj a DERPrintableString or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return a DERPrintableString instance, or null.
+     */
+    public static DERPrintableString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERPrintableString)
+        {
+            return (DERPrintableString)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERPrintableString)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return a Printable String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return a DERPrintableString instance, or null.
+     */
+    public static DERPrintableString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERPrintableString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets());
+        }
+    }
+
+    /**
+     * Basic constructor - byte encoded string.
+     */
+    DERPrintableString(
+        byte[]   string)
+    {
+        this.string = string;
+    }
+
+    /**
+     * Basic constructor - this does not validate the string
+     */
+    public DERPrintableString(
+        String   string)
+    {
+        this(string, false);
+    }
+
+    /**
+     * Constructor with optional validation.
+     *
+     * @param string the base string to wrap.
+     * @param validate whether or not to check the string.
+     * @throws IllegalArgumentException if validate is true and the string
+     * contains characters that should not be in a PrintableString.
+     */
+    public DERPrintableString(
+        String   string,
+        boolean  validate)
+    {
+        if (validate && !isPrintableString(string))
+        {
+            throw new IllegalArgumentException("string contains illegal characters");
+        }
+
+        this.string = Strings.toByteArray(string);
+    }
+
+    public String getString()
+    {
+        return Strings.fromByteArray(string);
+    }
+
+    public byte[] getOctets()
+    {
+        return Arrays.clone(string);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.PRINTABLE_STRING, string);
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(string);
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof DERPrintableString))
+        {
+            return false;
+        }
+
+        DERPrintableString  s = (DERPrintableString)o;
+
+        return Arrays.areEqual(string, s.string);
+    }
+
+    public String toString()
+    {
+        return getString();
+    }
+
+    /**
+     * return true if the passed in String can be represented without
+     * loss as a PrintableString, false otherwise.
+     *
+     * @return true if in printable set, false otherwise.
+     */
+    public static boolean isPrintableString(
+        String  str)
+    {
+        for (int i = str.length() - 1; i >= 0; i--)
+        {
+            char    ch = str.charAt(i);
+
+            if (ch > 0x007f)
+            {
+                return false;
+            }
+
+            if ('a' <= ch && ch <= 'z')
+            {
+                continue;
+            }
+
+            if ('A' <= ch && ch <= 'Z')
+            {
+                continue;
+            }
+
+            if ('0' <= ch && ch <= '9')
+            {
+                continue;
+            }
+
+            switch (ch)
+            {
+            case ' ':
+            case '\'':
+            case '(':
+            case ')':
+            case '+':
+            case '-':
+            case '.':
+            case ':':
+            case '=':
+            case '?':
+            case '/':
+            case ',':
+                continue;
+            }
+
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSequence.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSequence.java
new file mode 100644
index 0000000..bbfc9c5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSequence.java
@@ -0,0 +1,109 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * Definite length SEQUENCE, encoding tells explicit number of bytes
+ * that the content of this sequence occupies.
+ * <p>
+ * For X.690 syntax rules, see {@link ASN1Sequence}.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERSequence
+    extends ASN1Sequence
+{
+    private int bodyLength = -1;
+
+    /**
+     * Create an empty sequence
+     */
+    public DERSequence()
+    {
+    }
+
+    /**
+     * Create a sequence containing one object
+     * @param obj the object to go in the sequence.
+     */
+    public DERSequence(
+        ASN1Encodable obj)
+    {
+        super(obj);
+    }
+
+    /**
+     * Create a sequence containing a vector of objects.
+     * @param v the vector of objects to make up the sequence.
+     */
+    public DERSequence(
+        ASN1EncodableVector v)
+    {
+        super(v);
+    }
+
+    /**
+     * Create a sequence containing an array of objects.
+     * @param array the array of objects to make up the sequence.
+     */
+    public DERSequence(
+        ASN1Encodable[]   array)
+    {
+        super(array);
+    }
+
+    private int getBodyLength()
+        throws IOException
+    {
+        if (bodyLength < 0)
+        {
+            int length = 0;
+
+            for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+            {
+                Object    obj = e.nextElement();
+
+                length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength();
+            }
+
+            bodyLength = length;
+        }
+
+        return bodyLength;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = getBodyLength();
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
+    /*
+     * A note on the implementation:
+     * <p>
+     * As DER requires the constructed, definite-length model to
+     * be used for structured types, this varies slightly from the
+     * ASN.1 descriptions given. Rather than just outputting SEQUENCE,
+     * we also have to specify CONSTRUCTED, and the objects length.
+     */
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        ASN1OutputStream        dOut = out.getDERSubStream();
+        int                     length = getBodyLength();
+
+        out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
+        out.writeLength(length);
+
+        for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+        {
+            Object    obj = e.nextElement();
+
+            dOut.writeObject((ASN1Encodable)obj);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSequenceParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSequenceParser.java
new file mode 100644
index 0000000..b402076
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSequenceParser.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Parser class for DER SEQUENCEs.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERSequenceParser
+    implements ASN1SequenceParser
+{
+    private ASN1StreamParser _parser;
+
+    DERSequenceParser(ASN1StreamParser parser)
+    {
+        this._parser = parser;
+    }
+
+    /**
+     * Return the next object in the SEQUENCE.
+     *
+     * @return next object in SEQUENCE.
+     * @throws IOException if there is an issue loading the object.
+     */
+    public ASN1Encodable readObject()
+        throws IOException
+    {
+        return _parser.readObject();
+    }
+
+    /**
+     * Return an in memory, encodable, representation of the SEQUENCE.
+     *
+     * @return a DERSequence.
+     * @throws IOException if there is an issue loading the data.
+     */
+    public ASN1Primitive getLoadedObject()
+        throws IOException
+    {
+         return new DERSequence(_parser.readVector());
+    }
+
+    /**
+     * Return a DERSequence representing this parser and its contents.
+     *
+     * @return a DERSequence.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        try
+        {
+            return getLoadedObject();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException(e.getMessage());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSet.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSet.java
new file mode 100644
index 0000000..ca4f60c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSet.java
@@ -0,0 +1,120 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * A DER encoded SET object
+ * <p>
+ * For X.690 syntax rules, see {@link ASN1Set}.
+ * </p><p>
+ * For short: Constructing this form does sort the supplied elements,
+ * and the sorting happens also before serialization (if necesssary).
+ * This is different from the way {@link BERSet},{@link DLSet} does things.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERSet
+    extends ASN1Set
+{
+    private int bodyLength = -1;
+
+    /**
+     * create an empty set
+     */
+    public DERSet()
+    {
+    }
+
+    /**
+     * create a set containing one object
+     * @param obj the object to go in the set
+     */
+    public DERSet(
+        ASN1Encodable obj)
+    {
+        super(obj);
+    }
+
+    /**
+     * create a set containing a vector of objects.
+     * @param v the vector of objects to make up the set.
+     */
+    public DERSet(
+        ASN1EncodableVector v)
+    {
+        super(v, true);
+    }
+    
+    /**
+     * create a set containing an array of objects.
+     * @param a the array of objects to make up the set.
+     */
+    public DERSet(
+        ASN1Encodable[]   a)
+    {
+        super(a, true);
+    }
+
+    DERSet(
+        ASN1EncodableVector v,
+        boolean                  doSort)
+    {
+        super(v, doSort);
+    }
+
+    private int getBodyLength()
+        throws IOException
+    {
+        if (bodyLength < 0)
+        {
+            int length = 0;
+
+            for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+            {
+                Object    obj = e.nextElement();
+
+                length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength();
+            }
+
+            bodyLength = length;
+        }
+
+        return bodyLength;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = getBodyLength();
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
+    /*
+     * A note on the implementation:
+     * <p>
+     * As DER requires the constructed, definite-length model to
+     * be used for structured types, this varies slightly from the
+     * ASN.1 descriptions given. Rather than just outputting SET,
+     * we also have to specify CONSTRUCTED, and the objects length.
+     */
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        ASN1OutputStream        dOut = out.getDERSubStream();
+        int                     length = getBodyLength();
+
+        out.write(BERTags.SET | BERTags.CONSTRUCTED);
+        out.writeLength(length);
+
+        for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+        {
+            Object    obj = e.nextElement();
+
+            dOut.writeObject((ASN1Encodable)obj);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSetParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSetParser.java
new file mode 100644
index 0000000..38c30dd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERSetParser.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Parser class for DER SETs.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERSetParser
+    implements ASN1SetParser
+{
+    private ASN1StreamParser _parser;
+
+    DERSetParser(ASN1StreamParser parser)
+    {
+        this._parser = parser;
+    }
+
+    /**
+     * Return the next object in the SET.
+     *
+     * @return next object in SET.
+     * @throws IOException if there is an issue loading the object.
+     */
+    public ASN1Encodable readObject()
+        throws IOException
+    {
+        return _parser.readObject();
+    }
+
+    /**
+     * Return an in memory, encodable, representation of the SET.
+     *
+     * @return a DERSet.
+     * @throws IOException if there is an issue loading the data.
+     */
+    public ASN1Primitive getLoadedObject()
+        throws IOException
+    {
+        return new DERSet(_parser.readVector(), false);
+    }
+
+    /**
+     * Return a DERSet representing this parser and its contents.
+     *
+     * @return a DERSet
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        try
+        {
+            return getLoadedObject();
+        }
+        catch (IOException e)
+        {
+            throw new ASN1ParsingException(e.getMessage(), e);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERT61String.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERT61String.java
new file mode 100644
index 0000000..06f2dee
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERT61String.java
@@ -0,0 +1,153 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * DER T61String (also the teletex string), try not to use this if you don't need to. The standard support the encoding for
+ * this has been withdrawn.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERT61String
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private byte[] string;
+
+    /**
+     * Return a T61 string from the passed in object.
+     *
+     * @param obj a DERT61String or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return a DERT61String instance, or null
+     */
+    public static DERT61String getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERT61String)
+        {
+            return (DERT61String)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERT61String)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return an T61 String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return a DERT61String instance, or null
+     */
+    public static DERT61String getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERT61String)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERT61String(ASN1OctetString.getInstance(o).getOctets());
+        }
+    }
+
+    /**
+     * Basic constructor - string encoded as a sequence of bytes.
+     *
+     * @param string the byte encoding of the string to be wrapped.
+     */
+    public DERT61String(
+        byte[]   string)
+    {
+        this.string = Arrays.clone(string);
+    }
+
+    /**
+     * Basic constructor - with string 8 bit assumed.
+     *
+     * @param string the string to be wrapped.
+     */
+    public DERT61String(
+        String   string)
+    {
+        this.string = Strings.toByteArray(string);
+    }
+
+    /**
+     * Decode the encoded string and return it, 8 bit encoding assumed.
+     * @return the decoded String
+     */
+    public String getString()
+    {
+        return Strings.fromByteArray(string);
+    }
+
+    public String toString()
+    {
+        return getString();
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.T61_STRING, string);
+    }
+
+    /**
+     * Return the encoded string as a byte array.
+     * @return the actual bytes making up the encoded body of the T61 string.
+     */
+    public byte[] getOctets()
+    {
+        return Arrays.clone(string);
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof DERT61String))
+        {
+            return false;
+        }
+
+        return Arrays.areEqual(string, ((DERT61String)o).string);
+    }
+    
+    public int hashCode()
+    {
+        return Arrays.hashCode(string);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERTaggedObject.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERTaggedObject.java
new file mode 100644
index 0000000..57f907f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERTaggedObject.java
@@ -0,0 +1,120 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * DER TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERTaggedObject
+    extends ASN1TaggedObject
+{
+    private static final byte[] ZERO_BYTES = new byte[0];
+
+    /**
+     * @param explicit true if an explicitly tagged object.
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public DERTaggedObject(
+        boolean       explicit,
+        int           tagNo,
+        ASN1Encodable obj)
+    {
+        super(explicit, tagNo, obj);
+    }
+
+    public DERTaggedObject(int tagNo, ASN1Encodable encodable)
+    {
+        super(true, tagNo, encodable);
+    }
+
+    boolean isConstructed()
+    {
+        if (!empty)
+        {
+            if (explicit)
+            {
+                return true;
+            }
+            else
+            {
+                ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+
+                return primitive.isConstructed();
+            }
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        if (!empty)
+        {
+            ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+            int length = primitive.encodedLength();
+
+            if (explicit)
+            {
+                return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
+            }
+            else
+            {
+                // header length already in calculation
+                length = length - 1;
+
+                return StreamUtil.calculateTagLength(tagNo) + length;
+            }
+        }
+        else
+        {
+            return StreamUtil.calculateTagLength(tagNo) + 1;
+        }
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        if (!empty)
+        {
+            ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+
+            if (explicit)
+            {
+                out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
+                out.writeLength(primitive.encodedLength());
+                out.writeObject(primitive);
+            }
+            else
+            {
+                //
+                // need to mark constructed types...
+                //
+                int flags;
+                if (primitive.isConstructed())
+                {
+                    flags = BERTags.CONSTRUCTED | BERTags.TAGGED;
+                }
+                else
+                {
+                    flags = BERTags.TAGGED;
+                }
+
+                out.writeTag(flags, tagNo);
+                out.writeImplicitObject(primitive);
+            }
+        }
+        else
+        {
+            out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERTags.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERTags.java
new file mode 100644
index 0000000..fb68afe
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERTags.java
@@ -0,0 +1,11 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+/**
+ * @deprecated use BERTags
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface DERTags
+    extends BERTags
+{
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERUTCTime.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERUTCTime.java
new file mode 100644
index 0000000..4e3c5f2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERUTCTime.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.util.Date;
+
+/**
+ * DER UTC time object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERUTCTime
+    extends ASN1UTCTime
+{
+    DERUTCTime(byte[] bytes)
+    {
+        super(bytes);
+    }
+
+    public DERUTCTime(Date time)
+    {
+        super(time);
+    }
+
+    public DERUTCTime(String time)
+    {
+        super(time);
+    }
+
+    // TODO: create proper DER encoding.
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERUTF8String.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERUTF8String.java
new file mode 100644
index 0000000..b32752c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERUTF8String.java
@@ -0,0 +1,139 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * DER UTF8String object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERUTF8String
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private final byte[]  string;
+
+    /**
+     * Return an UTF8 string from the passed in object.
+     *
+     * @param obj a DERUTF8String or an object that can be converted into one.
+     * @exception IllegalArgumentException
+     *                if the object cannot be converted.
+     * @return a DERUTF8String instance, or null
+     */
+    public static DERUTF8String getInstance(Object obj)
+    {
+        if (obj == null || obj instanceof DERUTF8String)
+        {
+            return (DERUTF8String)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERUTF8String)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: "
+                + obj.getClass().getName());
+    }
+
+    /**
+     * Return an UTF8 String from a tagged object.
+     * 
+     * @param obj
+     *            the tagged object holding the object we want
+     * @param explicit
+     *            true if the object is meant to be explicitly tagged false
+     *            otherwise.
+     * @exception IllegalArgumentException
+     *                if the tagged object cannot be converted.
+     * @return a DERUTF8String instance, or null
+     */
+    public static DERUTF8String getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERUTF8String)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERUTF8String(ASN1OctetString.getInstance(o).getOctets());
+        }
+    }
+
+    /*
+     * Basic constructor - byte encoded string.
+     */
+    DERUTF8String(byte[] string)
+    {
+        this.string = string;
+    }
+
+    /**
+     * Basic constructor
+     *
+     * @param string the string to be carried in the UTF8String object,
+     */
+    public DERUTF8String(String string)
+    {
+        this.string = Strings.toUTF8ByteArray(string);
+    }
+
+    public String getString()
+    {
+        return Strings.fromUTF8ByteArray(string);
+    }
+
+    public String toString()
+    {
+        return getString();
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(string);
+    }
+
+    boolean asn1Equals(ASN1Primitive o)
+    {
+        if (!(o instanceof DERUTF8String))
+        {
+            return false;
+        }
+
+        DERUTF8String s = (DERUTF8String)o;
+
+        return Arrays.areEqual(string, s.string);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.UTF8_STRING, string);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERUniversalString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERUniversalString.java
new file mode 100644
index 0000000..016a53a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERUniversalString.java
@@ -0,0 +1,156 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * DER UniversalString object - encodes UNICODE (ISO 10646) characters using 32-bit format. In Java we
+ * have no way of representing this directly so we rely on byte arrays to carry these.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERUniversalString
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private static final char[]  table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+    private final byte[] string;
+    
+    /**
+     * Return a Universal String from the passed in object.
+     *
+     * @param obj a DERUniversalString or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return a DERUniversalString instance, or null
+     */
+    public static DERUniversalString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERUniversalString)
+        {
+            return (DERUniversalString)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERUniversalString)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return a Universal String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return a DERUniversalString instance, or null
+     */
+    public static DERUniversalString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERUniversalString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERUniversalString(((ASN1OctetString)o).getOctets());
+        }
+    }
+
+    /**
+     * Basic constructor - byte encoded string.
+     *
+     * @param string the byte encoding of the string to be carried in the UniversalString object,
+     */
+    public DERUniversalString(
+        byte[]   string)
+    {
+        this.string = Arrays.clone(string);
+    }
+
+    public String getString()
+    {
+        StringBuffer    buf = new StringBuffer("#");
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        ASN1OutputStream            aOut = new ASN1OutputStream(bOut);
+        
+        try
+        {
+            aOut.writeObject(this);
+        }
+        catch (IOException e)
+        {
+           throw new ASN1ParsingException("internal error encoding UniversalString");
+        }
+        
+        byte[]    string = bOut.toByteArray();
+        
+        for (int i = 0; i != string.length; i++)
+        {
+            buf.append(table[(string[i] >>> 4) & 0xf]);
+            buf.append(table[string[i] & 0xf]);
+        }
+        
+        return buf.toString();
+    }
+
+    public String toString()
+    {
+        return getString();
+    }
+
+    public byte[] getOctets()
+    {
+        return Arrays.clone(string);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.UNIVERSAL_STRING, this.getOctets());
+    }
+    
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof DERUniversalString))
+        {
+            return false;
+        }
+
+        return Arrays.areEqual(string, ((DERUniversalString)o).string);
+    }
+    
+    public int hashCode()
+    {
+        return Arrays.hashCode(string);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERVideotexString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERVideotexString.java
new file mode 100644
index 0000000..f57bd36
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERVideotexString.java
@@ -0,0 +1,128 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERVideotexString
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private final byte[] string;
+    
+    /**
+     * return a Videotex String from the passed in object
+     *
+     * @param obj a DERVideotexString or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return a DERVideotexString instance, or null.
+     */
+    public static DERVideotexString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERVideotexString)
+        {
+            return (DERVideotexString)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERVideotexString)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a Videotex String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return a DERVideotexString instance, or null.
+     */
+    public static DERVideotexString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERVideotexString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERVideotexString(((ASN1OctetString)o).getOctets());
+        }
+    }
+
+    /**
+     * basic constructor - with bytes.
+     * @param string the byte encoding of the characters making up the string.
+     */
+    public DERVideotexString(
+        byte[]   string)
+    {
+        this.string = Arrays.clone(string);
+    }
+    
+    public byte[] getOctets()
+    {
+        return Arrays.clone(string);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.VIDEOTEX_STRING, string);
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(string);
+    }
+
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof DERVideotexString))
+        {
+            return false;
+        }
+
+        DERVideotexString  s = (DERVideotexString)o;
+
+        return Arrays.areEqual(string, s.string);
+    }
+
+    public String getString()
+    {
+        return Strings.fromByteArray(string);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERVisibleString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERVisibleString.java
new file mode 100644
index 0000000..a2db52d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DERVisibleString.java
@@ -0,0 +1,145 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * DER VisibleString object encoding ISO 646 (ASCII) character code points 32 to 126.
+ * <p>
+ * Explicit character set escape sequences are not allowed.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DERVisibleString
+    extends ASN1Primitive
+    implements ASN1String
+{
+    private final byte[]  string;
+
+    /**
+     * Return a Visible String from the passed in object.
+     *
+     * @param obj a DERVisibleString or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return a DERVisibleString instance, or null
+     */
+    public static DERVisibleString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERVisibleString)
+        {
+            return (DERVisibleString)obj;
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (DERVisibleString)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Return a Visible String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return a DERVisibleString instance, or null
+     */
+    public static DERVisibleString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DERVisibleString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERVisibleString(ASN1OctetString.getInstance(o).getOctets());
+        }
+    }
+
+    /*
+     * Basic constructor - byte encoded string.
+     */
+    DERVisibleString(
+        byte[]   string)
+    {
+        this.string = string;
+    }
+
+    /**
+     * Basic constructor
+     *
+     * @param string the string to be carried in the VisibleString object,
+     */
+    public DERVisibleString(
+        String   string)
+    {
+        this.string = Strings.toByteArray(string);
+    }
+
+    public String getString()
+    {
+        return Strings.fromByteArray(string);
+    }
+
+    public String toString()
+    {
+        return getString();
+    }
+
+    public byte[] getOctets()
+    {
+        return Arrays.clone(string);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(BERTags.VISIBLE_STRING, this.string);
+    }
+    
+    boolean asn1Equals(
+        ASN1Primitive o)
+    {
+        if (!(o instanceof DERVisibleString))
+        {
+            return false;
+        }
+
+        return Arrays.areEqual(string, ((DERVisibleString)o).string);
+    }
+    
+    public int hashCode()
+    {
+        return Arrays.hashCode(string);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLApplicationSpecific.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLApplicationSpecific.java
new file mode 100644
index 0000000..9698959
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLApplicationSpecific.java
@@ -0,0 +1,126 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * A DER encoding version of an application specific object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DLApplicationSpecific
+    extends ASN1ApplicationSpecific
+{
+    DLApplicationSpecific(
+        boolean isConstructed,
+        int     tag,
+        byte[]  octets)
+    {
+        super(isConstructed, tag, octets);
+    }
+
+    /**
+     * Create an application specific object from the passed in data. This will assume
+     * the data does not represent a constructed object.
+     *
+     * @param tag the tag number for this object.
+     * @param octets the encoding of the object's body.
+     */
+    public DLApplicationSpecific(
+        int    tag,
+        byte[] octets)
+    {
+        this(false, tag, octets);
+    }
+
+    /**
+     * Create an application specific object with a tagging of explicit/constructed.
+     *
+     * @param tag the tag number for this object.
+     * @param object the object to be contained.
+     */
+    public DLApplicationSpecific(
+        int           tag,
+        ASN1Encodable object)
+        throws IOException
+    {
+        this(true, tag, object);
+    }
+
+    /**
+     * Create an application specific object with the tagging style given by the value of constructed.
+     *
+     * @param constructed true if the object is constructed.
+     * @param tag the tag number for this object.
+     * @param object the object to be contained.
+     */
+    public DLApplicationSpecific(
+        boolean      constructed,
+        int          tag,
+        ASN1Encodable object)
+        throws IOException
+    {
+        super(constructed || object.toASN1Primitive().isConstructed(), tag, getEncoding(constructed, object));
+    }
+
+    private static byte[] getEncoding(boolean explicit, ASN1Encodable object)
+        throws IOException
+    {
+        byte[] data = object.toASN1Primitive().getEncoded(ASN1Encoding.DL);
+
+        if (explicit)
+        {
+            return data;
+        }
+        else
+        {
+            int lenBytes = getLengthOfHeader(data);
+            byte[] tmp = new byte[data.length - lenBytes];
+            System.arraycopy(data, lenBytes, tmp, 0, tmp.length);
+            return tmp;
+        }
+    }
+
+    /**
+     * Create an application specific object which is marked as constructed
+     *
+     * @param tagNo the tag number for this object.
+     * @param vec the objects making up the application specific object.
+     */
+    public DLApplicationSpecific(int tagNo, ASN1EncodableVector vec)
+    {
+        super(true, tagNo, getEncodedVector(vec));
+    }
+
+    private static byte[] getEncodedVector(ASN1EncodableVector vec)
+    {
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+        for (int i = 0; i != vec.size(); i++)
+        {
+            try
+            {
+                bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.DL));
+            }
+            catch (IOException e)
+            {
+                throw new ASN1ParsingException("malformed object: " + e, e);
+            }
+        }
+        return bOut.toByteArray();
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
+     */
+    void encode(ASN1OutputStream out) throws IOException
+    {
+        int classBits = BERTags.APPLICATION;
+        if (isConstructed)
+        {
+            classBits |= BERTags.CONSTRUCTED;
+        }
+
+        out.writeEncoded(classBits, tag, octets);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLBitString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLBitString.java
new file mode 100644
index 0000000..a251422
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLBitString.java
@@ -0,0 +1,158 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * A Definite length BIT STRING
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DLBitString
+    extends ASN1BitString
+{
+    /**
+     * return a Bit String that can be definite-length encoded from the passed in object.
+     *
+     * @param obj a DL or DER BitString or an object that can be converted into one.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     * @return an ASN1BitString instance, or null.
+     */
+    public static ASN1BitString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DLBitString)
+        {
+            return (DLBitString)obj;
+        }
+        if (obj instanceof DERBitString)
+        {
+            return (DERBitString)obj;
+        }
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return (ASN1BitString)fromByteArray((byte[])obj);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
+            }
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a Bit String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     * @return an ASN1BitString instance, or null.
+     */
+    public static ASN1BitString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        ASN1Primitive o = obj.getObject();
+
+        if (explicit || o instanceof DLBitString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return fromOctetString(((ASN1OctetString)o).getOctets());
+        }
+    }
+
+    protected DLBitString(
+        byte    data,
+        int     padBits)
+    {
+        this(toByteArray(data), padBits);
+    }
+
+    private static byte[] toByteArray(byte data)
+    {
+        byte[] rv = new byte[1];
+
+        rv[0] = data;
+
+        return rv;
+    }
+
+    /**
+     * @param data the octets making up the bit string.
+     * @param padBits the number of extra bits at the end of the string.
+     */
+    public DLBitString(
+        byte[]  data,
+        int     padBits)
+    {
+        super(data, padBits);
+    }
+
+    public DLBitString(
+        byte[]  data)
+    {
+        this(data, 0);
+    }
+
+    public DLBitString(
+        int value)
+    {
+        super(getBytes(value), getPadBits(value));
+    }
+
+    public DLBitString(
+        ASN1Encodable obj)
+        throws IOException
+    {
+        super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER), 0);
+    }
+
+    boolean isConstructed()
+    {
+        return false;
+    }
+
+    int encodedLength()
+    {
+        return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1;
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        byte[] string = data;
+        byte[] bytes = new byte[string.length + 1];
+
+        bytes[0] = (byte)getPadBits();
+        System.arraycopy(string, 0, bytes, 1, bytes.length - 1);
+
+        out.writeEncoded(BERTags.BIT_STRING, bytes);
+    }
+
+    static DLBitString fromOctetString(byte[] bytes)
+    {
+        if (bytes.length < 1)
+        {
+            throw new IllegalArgumentException("truncated BIT STRING detected");
+        }
+
+        int padBits = bytes[0];
+        byte[] data = new byte[bytes.length - 1];
+
+        if (data.length != 0)
+        {
+            System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
+        }
+
+        return new DLBitString(data, padBits);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLExternal.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLExternal.java
new file mode 100644
index 0000000..6439b9e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLExternal.java
@@ -0,0 +1,87 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Class representing the Definite-Length-type External
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DLExternal
+    extends ASN1External
+{
+    /**
+     * Construct a Definite-Length EXTERNAL object, the input encoding vector must have exactly two elements on it.
+     * <p>
+     * Acceptable input formats are:
+     * <ul>
+     * <li> {@link ASN1ObjectIdentifier} + data {@link DERTaggedObject} (direct reference form)</li>
+     * <li> {@link ASN1Integer} + data {@link DERTaggedObject} (indirect reference form)</li>
+     * <li> Anything but {@link DERTaggedObject} + data {@link DERTaggedObject} (data value form)</li>
+     * </ul>
+     *
+     * @throws IllegalArgumentException if input size is wrong, or
+     */
+    public DLExternal(ASN1EncodableVector vector)
+    {
+        super(vector);
+    }
+
+    /**
+     * Creates a new instance of DERExternal
+     * See X.690 for more informations about the meaning of these parameters
+     * @param directReference The direct reference or <code>null</code> if not set.
+     * @param indirectReference The indirect reference or <code>null</code> if not set.
+     * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
+     * @param externalData The external data in its encoded form.
+     */
+    public DLExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData)
+    {
+        this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive());
+    }
+
+    /**
+     * Creates a new instance of Definite-Length External.
+     * See X.690 for more informations about the meaning of these parameters
+     * @param directReference The direct reference or <code>null</code> if not set.
+     * @param indirectReference The indirect reference or <code>null</code> if not set.
+     * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
+     * @param encoding The encoding to be used for the external data
+     * @param externalData The external data
+     */
+    public DLExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData)
+    {
+        super(directReference, indirectReference, dataValueDescriptor, encoding, externalData);
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        return this.getEncoded().length;
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
+     */
+    void encode(ASN1OutputStream out)
+        throws IOException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        if (directReference != null)
+        {
+            baos.write(directReference.getEncoded(ASN1Encoding.DL));
+        }
+        if (indirectReference != null)
+        {
+            baos.write(indirectReference.getEncoded(ASN1Encoding.DL));
+        }
+        if (dataValueDescriptor != null)
+        {
+            baos.write(dataValueDescriptor.getEncoded(ASN1Encoding.DL));
+        }
+        DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent);
+        baos.write(obj.getEncoded(ASN1Encoding.DL));
+        out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLOutputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLOutputStream.java
new file mode 100644
index 0000000..b8df994
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLOutputStream.java
@@ -0,0 +1,33 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Stream that outputs encoding based on definite length.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DLOutputStream
+    extends ASN1OutputStream
+{
+    public DLOutputStream(
+        OutputStream os)
+    {
+        super(os);
+    }
+
+    public void writeObject(
+        ASN1Encodable obj)
+        throws IOException
+    {
+        if (obj != null)
+        {
+            obj.toASN1Primitive().toDLObject().encode(this);
+        }
+        else
+        {
+            throw new IOException("null object detected");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLSequence.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLSequence.java
new file mode 100644
index 0000000..27373bb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLSequence.java
@@ -0,0 +1,106 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * The DLSequence encodes a SEQUENCE using definite length form.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DLSequence
+    extends ASN1Sequence
+{
+    private int bodyLength = -1;
+
+    /**
+     * Create an empty sequence
+     */
+    public DLSequence()
+    {
+    }
+
+    /**
+     * create a sequence containing one object
+     * @param obj the object to go in the sequence.
+     */
+    public DLSequence(
+        ASN1Encodable obj)
+    {
+        super(obj);
+    }
+
+    /**
+     * create a sequence containing a vector of objects.
+     * @param v the vector of objects to make up the sequence.
+     */
+    public DLSequence(
+        ASN1EncodableVector v)
+    {
+        super(v);
+    }
+
+    /**
+     * create a sequence containing an array of objects.
+     * @param array the array of objects to make up the sequence.
+     */
+    public DLSequence(
+        ASN1Encodable[] array)
+    {
+        super(array);
+    }
+
+    private int getBodyLength()
+        throws IOException
+    {
+        if (bodyLength < 0)
+        {
+            int length = 0;
+
+            for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+            {
+                Object obj = e.nextElement();
+
+                length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength();
+            }
+
+            bodyLength = length;
+        }
+
+        return bodyLength;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = getBodyLength();
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
+    /**
+     * A note on the implementation:
+     * <p>
+     * As DL requires the constructed, definite-length model to
+     * be used for structured types, this varies slightly from the
+     * ASN.1 descriptions given. Rather than just outputting SEQUENCE,
+     * we also have to specify CONSTRUCTED, and the objects length.
+     */
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        ASN1OutputStream dOut = out.getDLSubStream();
+        int length = getBodyLength();
+
+        out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
+        out.writeLength(length);
+
+        for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+        {
+            Object obj = e.nextElement();
+
+            dOut.writeObject((ASN1Encodable)obj);
+        }
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLSet.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLSet.java
new file mode 100644
index 0000000..e4ea3aa
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLSet.java
@@ -0,0 +1,148 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * The DLSet encodes ASN.1 SET value without element ordering,
+ * and always using definite length form.
+ * <hr>
+ * <h2>X.690</h2>
+ * <h3>8: Basic encoding rules</h3>
+ * <h4>8.11 Encoding of a set value </h4>
+ * <b>8.11.1</b> The encoding of a set value shall be constructed
+ * <p>
+ * <b>8.11.2</b> The contents octets shall consist of the complete
+ * encoding of a data value from each of the types listed in the
+ * ASN.1 definition of the set type, in an order chosen by the sender,
+ * unless the type was referenced with the keyword
+ * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
+ * <p>
+ * <b>8.11.3</b> The encoding of a data value may, but need not,
+ * be present for a type which was referenced with the keyword
+ * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
+ * <blockquote>
+ * NOTE &mdash; The order of data values in a set value is not significant,
+ * and places no constraints on the order during transfer
+ * </blockquote>
+ * <h3>9: Canonical encoding rules</h3>
+ * <h4>9.3 Set components</h4>
+ * The encodings of the component values of a set value shall
+ * appear in an order determined by their tags as specified
+ * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
+ * Additionally, for the purposes of determining the order in which
+ * components are encoded when one or more component is an untagged
+ * choice type, each untagged choice type is ordered as though it
+ * has a tag equal to that of the smallest tag in that choice type
+ * or any untagged choice types nested within.
+ * <h3>10: Distinguished encoding rules</h3>
+ * <h4>10.3 Set components</h4>
+ * The encodings of the component values of a set value shall appear
+ * in an order determined by their tags as specified
+ * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
+ * <blockquote>
+ * NOTE &mdash; Where a component of the set is an untagged choice type,
+ * the location of that component in the ordering will depend on
+ * the tag of the choice component being encoded.
+ * </blockquote>
+ * <h3>11: Restrictions on BER employed by both CER and DER</h3>
+ * <h4>11.5 Set and sequence components with default value </h4>
+ * The encoding of a set value or sequence value shall not include
+ * an encoding for any component value which is equal to
+ * its default value.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DLSet
+    extends ASN1Set
+{
+    private int bodyLength = -1;
+
+    /**
+     * create an empty set
+     */
+    public DLSet()
+    {
+    }
+
+    /**
+     * @param obj - a single object that makes up the set.
+     */
+    public DLSet(
+        ASN1Encodable obj)
+    {
+        super(obj);
+    }
+
+    /**
+     * @param v - a vector of objects making up the set.
+     */
+    public DLSet(
+        ASN1EncodableVector v)
+    {
+        super(v, false);
+    }
+
+    /**
+     * create a set from an array of objects.
+     */
+    public DLSet(
+        ASN1Encodable[] a)
+    {
+        super(a, false);
+    }
+
+    private int getBodyLength()
+        throws IOException
+    {
+        if (bodyLength < 0)
+        {
+            int length = 0;
+
+            for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+            {
+                Object obj = e.nextElement();
+
+                length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength();
+            }
+
+            bodyLength = length;
+        }
+
+        return bodyLength;
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        int length = getBodyLength();
+
+        return 1 + StreamUtil.calculateBodyLength(length) + length;
+    }
+
+    /**
+     * A note on the implementation:
+     * <p>
+     * As DL requires the constructed, definite-length model to
+     * be used for structured types, this varies slightly from the
+     * ASN.1 descriptions given. Rather than just outputting SET,
+     * we also have to specify CONSTRUCTED, and the objects length.
+     */
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        ASN1OutputStream dOut = out.getDLSubStream();
+        int length = getBodyLength();
+
+        out.write(BERTags.SET | BERTags.CONSTRUCTED);
+        out.writeLength(length);
+
+        for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+        {
+            Object obj = e.nextElement();
+
+            dOut.writeObject((ASN1Encodable)obj);
+        }
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLTaggedObject.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLTaggedObject.java
new file mode 100644
index 0000000..68cb4c7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DLTaggedObject.java
@@ -0,0 +1,114 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Definite Length TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DLTaggedObject
+    extends ASN1TaggedObject
+{
+    private static final byte[] ZERO_BYTES = new byte[0];
+
+    /**
+     * @param explicit true if an explicitly tagged object.
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public DLTaggedObject(
+        boolean explicit,
+        int tagNo,
+        ASN1Encodable obj)
+    {
+        super(explicit, tagNo, obj);
+    }
+
+    boolean isConstructed()
+    {
+        if (!empty)
+        {
+            if (explicit)
+            {
+                return true;
+            }
+            else
+            {
+                ASN1Primitive primitive = obj.toASN1Primitive().toDLObject();
+
+                return primitive.isConstructed();
+            }
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        if (!empty)
+        {
+            int length = obj.toASN1Primitive().toDLObject().encodedLength();
+
+            if (explicit)
+            {
+                return  StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
+            }
+            else
+            {
+                // header length already in calculation
+                length = length - 1;
+
+                return StreamUtil.calculateTagLength(tagNo) + length;
+            }
+        }
+        else
+        {
+            return StreamUtil.calculateTagLength(tagNo) + 1;
+        }
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        if (!empty)
+        {
+            ASN1Primitive primitive = obj.toASN1Primitive().toDLObject();
+
+            if (explicit)
+            {
+                out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
+                out.writeLength(primitive.encodedLength());
+                out.writeObject(primitive);
+            }
+            else
+            {
+                //
+                // need to mark constructed types...
+                //
+                int flags;
+                if (primitive.isConstructed())
+                {
+                    flags = BERTags.CONSTRUCTED | BERTags.TAGGED;
+                }
+                else
+                {
+                    flags = BERTags.TAGGED;
+                }
+
+                out.writeTag(flags, tagNo);
+                out.writeImplicitObject(primitive);
+            }
+        }
+        else
+        {
+            out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DateUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DateUtil.java
new file mode 100644
index 0000000..8cecd07
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DateUtil.java
@@ -0,0 +1,81 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+class DateUtil
+{
+    private static Long ZERO = longValueOf(0);
+
+    private static final Map localeCache = new HashMap();
+
+    static Locale EN_Locale = forEN();
+
+    private static Locale forEN()
+    {
+        if ("en".equalsIgnoreCase(Locale.getDefault().getLanguage()))
+        {
+            return Locale.getDefault();
+        }
+        
+        Locale[] locales = Locale.getAvailableLocales();
+        for (int i = 0; i != locales.length; i++)
+        {
+            if ("en".equalsIgnoreCase(locales[i].getLanguage()))
+            {
+                return locales[i];
+            }
+        }
+
+        return Locale.getDefault();
+    }
+
+    static Date epochAdjust(Date date)
+        throws ParseException
+    {
+        Locale locale = Locale.getDefault();
+        if (locale == null)
+        {
+            return date;
+        }
+
+        synchronized (localeCache)
+        {
+            Long adj = (Long)localeCache.get(locale);
+
+            if (adj == null)
+            {
+                SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+                long v = dateF.parse("19700101000000GMT+00:00").getTime();
+
+                if (v == 0)
+                {
+                    adj = ZERO;
+                }
+                else
+                {
+                    adj = longValueOf(v);
+                }
+
+                localeCache.put(locale, adj);
+            }
+
+            if (adj != ZERO)
+            {
+                return new Date(date.getTime() - adj.longValue());
+            }
+
+            return date;
+        }
+    }
+
+    private static Long longValueOf(long v)
+    {
+        return Long.valueOf(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DefiniteLengthInputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DefiniteLengthInputStream.java
new file mode 100644
index 0000000..d1c3e2e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/DefiniteLengthInputStream.java
@@ -0,0 +1,109 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.android.internal.org.bouncycastle.util.io.Streams;
+
+/**
+ * Parse data stream of expected ASN.1 data expecting definite-length encoding..
+ */
+class DefiniteLengthInputStream
+        extends LimitedInputStream
+{
+    private static final byte[] EMPTY_BYTES = new byte[0];
+
+    private final int _originalLength;
+    private int _remaining;
+
+    DefiniteLengthInputStream(
+        InputStream in,
+        int         length)
+    {
+        super(in, length);
+
+        if (length < 0)
+        {
+            throw new IllegalArgumentException("negative lengths not allowed");
+        }
+
+        this._originalLength = length;
+        this._remaining = length;
+
+        if (length == 0)
+        {
+            setParentEofDetect(true);
+        }
+    }
+
+    int getRemaining()
+    {
+        return _remaining;
+    }
+
+    public int read()
+        throws IOException
+    {
+        if (_remaining == 0)
+        {
+            return -1;
+        }
+
+        int b = _in.read();
+
+        if (b < 0)
+        {
+            throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining);
+        }
+
+        if (--_remaining == 0)
+        {
+            setParentEofDetect(true);
+        }
+
+        return b;
+    }
+
+    public int read(byte[] buf, int off, int len)
+        throws IOException
+    {
+        if (_remaining == 0)
+        {
+            return -1;
+        }
+
+        int toRead = Math.min(len, _remaining);
+        int numRead = _in.read(buf, off, toRead);
+
+        if (numRead < 0)
+        {
+            throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining);
+        }
+
+        if ((_remaining -= numRead) == 0)
+        {
+            setParentEofDetect(true);
+        }
+
+        return numRead;
+    }
+
+    byte[] toByteArray()
+        throws IOException
+    {
+        if (_remaining == 0)
+        {
+            return EMPTY_BYTES;
+        }
+
+        byte[] bytes = new byte[_remaining];
+        if ((_remaining -= Streams.readFully(_in, bytes)) != 0)
+        {
+            throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining);
+        }
+        setParentEofDetect(true);
+        return bytes;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/InMemoryRepresentable.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/InMemoryRepresentable.java
new file mode 100644
index 0000000..96e16fe
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/InMemoryRepresentable.java
@@ -0,0 +1,19 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Interface implemented by objects that can be converted from streaming to in-memory objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface InMemoryRepresentable
+{
+    /**
+     * Get the in-memory representation of the ASN.1 object.
+     * @return an ASN1Primitive representing the loaded object.
+     * @throws IOException for bad input data.
+     */
+    ASN1Primitive getLoadedObject()
+        throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/IndefiniteLengthInputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/IndefiniteLengthInputStream.java
new file mode 100644
index 0000000..faf410d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/IndefiniteLengthInputStream.java
@@ -0,0 +1,112 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+class IndefiniteLengthInputStream
+    extends LimitedInputStream
+{
+    private int _b1;
+    private int _b2;
+    private boolean _eofReached = false;
+    private boolean _eofOn00 = true;
+
+    IndefiniteLengthInputStream(
+        InputStream in,
+        int         limit)
+        throws IOException
+    {
+        super(in, limit);
+
+        _b1 = in.read();
+        _b2 = in.read();
+
+        if (_b2 < 0)
+        {
+            // Corrupted stream
+            throw new EOFException();
+        }
+
+        checkForEof();
+    }
+
+    void setEofOn00(
+        boolean eofOn00)
+    {
+        _eofOn00 = eofOn00;
+        checkForEof();
+    }
+
+    private boolean checkForEof()
+    {
+        if (!_eofReached && _eofOn00 && (_b1 == 0x00 && _b2 == 0x00))
+        {
+            _eofReached = true;
+            setParentEofDetect(true);
+        }
+        return _eofReached;
+    }
+
+    public int read(byte[] b, int off, int len)
+        throws IOException
+    {
+        // Only use this optimisation if we aren't checking for 00
+        if (_eofOn00 || len < 3)
+        {
+            return super.read(b, off, len);
+        }
+
+        if (_eofReached)
+        {
+            return -1;
+        }
+
+        int numRead = _in.read(b, off + 2, len - 2);
+
+        if (numRead < 0)
+        {
+            // Corrupted stream
+            throw new EOFException();
+        }
+
+        b[off] = (byte)_b1;
+        b[off + 1] = (byte)_b2;
+
+        _b1 = _in.read();
+        _b2 = _in.read();
+
+        if (_b2 < 0)
+        {
+            // Corrupted stream
+            throw new EOFException();
+        }
+
+        return numRead + 2;
+    }
+
+    public int read()
+        throws IOException
+    {
+        if (checkForEof())
+        {
+            return -1;
+        }
+
+        int b = _in.read();
+
+        if (b < 0)
+        {
+            // Corrupted stream
+            throw new EOFException();
+        }
+
+        int v = _b1;
+
+        _b1 = _b2;
+        _b2 = b;
+
+        return v;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/LazyConstructionEnumeration.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/LazyConstructionEnumeration.java
new file mode 100644
index 0000000..dbabb17
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/LazyConstructionEnumeration.java
@@ -0,0 +1,44 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+class LazyConstructionEnumeration
+    implements Enumeration
+{
+    private ASN1InputStream aIn;
+    private Object          nextObj;
+
+    public LazyConstructionEnumeration(byte[] encoded)
+    {
+        aIn = new ASN1InputStream(encoded, true);
+        nextObj = readObject();
+    }
+
+    public boolean hasMoreElements()
+    {
+        return nextObj != null;
+    }
+
+    public Object nextElement()
+    {
+        Object o = nextObj;
+
+        nextObj = readObject();
+
+        return o;
+    }
+
+    private Object readObject()
+    {
+        try
+        {
+            return aIn.readObject();
+        }
+        catch (IOException e)
+        {
+            throw new ASN1ParsingException("malformed DER construction: " + e, e);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/LazyEncodedSequence.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/LazyEncodedSequence.java
new file mode 100644
index 0000000..be9aaa6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/LazyEncodedSequence.java
@@ -0,0 +1,110 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * Note: this class is for processing DER/DL encoded sequences only.
+ */
+class LazyEncodedSequence
+    extends ASN1Sequence
+{
+    private byte[] encoded;
+
+    LazyEncodedSequence(
+        byte[] encoded)
+        throws IOException
+    {
+        this.encoded = encoded;
+    }
+
+    private void parse()
+    {
+        Enumeration en = new LazyConstructionEnumeration(encoded);
+
+        while (en.hasMoreElements())
+        {
+            seq.addElement(en.nextElement());
+        }
+
+        encoded = null;
+    }
+
+    public synchronized ASN1Encodable getObjectAt(int index)
+    {
+        if (encoded != null)
+        {
+            parse();
+        }
+
+        return super.getObjectAt(index);
+    }
+
+    public synchronized Enumeration getObjects()
+    {
+        if (encoded == null)
+        {
+            return super.getObjects();
+        }
+
+        return new LazyConstructionEnumeration(encoded);
+    }
+
+    public synchronized int size()
+    {
+        if (encoded != null)
+        {
+            parse();
+        }
+
+        return super.size();
+    }
+
+    ASN1Primitive toDERObject()
+    {
+        if (encoded != null)
+        {
+            parse();
+        }
+
+        return super.toDERObject();
+    }
+
+    ASN1Primitive toDLObject()
+    {
+        if (encoded != null)
+        {
+            parse();
+        }
+
+        return super.toDLObject();
+    }
+
+    int encodedLength()
+        throws IOException
+    {
+        if (encoded != null)
+        {
+            return 1 + StreamUtil.calculateBodyLength(encoded.length) + encoded.length;
+        }
+        else
+        {
+            return super.toDLObject().encodedLength();
+        }
+    }
+
+    void encode(
+        ASN1OutputStream out)
+        throws IOException
+    {
+        if (encoded != null)
+        {
+            out.writeEncoded(BERTags.SEQUENCE | BERTags.CONSTRUCTED, encoded);
+        }
+        else
+        {
+            super.toDLObject().encode(out);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/LimitedInputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/LimitedInputStream.java
new file mode 100644
index 0000000..6b525b2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/LimitedInputStream.java
@@ -0,0 +1,36 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.InputStream;
+
+/**
+ * Internal use stream that allows reading of a limited number of bytes from a wrapped stream.
+ */
+abstract class LimitedInputStream
+        extends InputStream
+{
+    protected final InputStream _in;
+    private int _limit;
+
+    LimitedInputStream(
+        InputStream in,
+        int         limit)
+    {
+        this._in = in;
+        this._limit = limit;
+    }
+
+    int getRemaining()
+    {
+        // TODO: maybe one day this can become more accurate
+        return _limit;
+    }
+    
+    protected void setParentEofDetect(boolean on)
+    {
+        if (_in instanceof IndefiniteLengthInputStream)
+        {
+            ((IndefiniteLengthInputStream)_in).setEofOn00(on);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/OIDTokenizer.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/OIDTokenizer.java
new file mode 100644
index 0000000..2a1d8cd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/OIDTokenizer.java
@@ -0,0 +1,65 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+/**
+ * Class for breaking up an OID into it's component tokens, ala
+ * java.util.StringTokenizer. We need this class as some of the
+ * lightweight Java environment don't support classes like
+ * StringTokenizer.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OIDTokenizer
+{
+    private String  oid;
+    private int     index;
+
+    /**
+     * Base constructor.
+     *
+     * @param oid the string representation of the OID.
+     */
+    public OIDTokenizer(
+        String oid)
+    {
+        this.oid = oid;
+        this.index = 0;
+    }
+
+    /**
+     * Return whether or not there are more tokens in this tokenizer.
+     *
+     * @return true if there are more tokens, false otherwise.
+     */
+    public boolean hasMoreTokens()
+    {
+        return (index != -1);
+    }
+
+    /**
+     * Return the next token in the underlying String.
+     *
+     * @return the next token.
+     */
+    public String nextToken()
+    {
+        if (index == -1)
+        {
+            return null;
+        }
+
+        String  token;
+        int     end = oid.indexOf('.', index);
+
+        if (end == -1)
+        {
+            token = oid.substring(index);
+            index = -1;
+            return token;
+        }
+
+        token = oid.substring(index, end);
+
+        index = end + 1;
+        return token;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/StreamUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/StreamUtil.java
new file mode 100644
index 0000000..4411a47
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/StreamUtil.java
@@ -0,0 +1,119 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.channels.FileChannel;
+
+class StreamUtil
+{
+    // Android-removed: Check max memory at runtime
+    // private static final long  MAX_MEMORY = Runtime.getRuntime().maxMemory();
+
+    /**
+     * Find out possible longest length...
+     *
+     * @param in input stream of interest
+     * @return length calculation or MAX_VALUE.
+     */
+    static int findLimit(InputStream in)
+    {
+        if (in instanceof LimitedInputStream)
+        {
+            return ((LimitedInputStream)in).getRemaining();
+        }
+        else if (in instanceof ASN1InputStream)
+        {
+            return ((ASN1InputStream)in).getLimit();
+        }
+        else if (in instanceof ByteArrayInputStream)
+        {
+            return ((ByteArrayInputStream)in).available();
+        }
+        else if (in instanceof FileInputStream)
+        {
+            try
+            {
+                FileChannel channel = ((FileInputStream)in).getChannel();
+                long  size = (channel != null) ? channel.size() : Integer.MAX_VALUE;
+
+                if (size < Integer.MAX_VALUE)
+                {
+                    return (int)size;
+                }
+            }
+            catch (IOException e)
+            {
+                // ignore - they'll find out soon enough!
+            }
+        }
+
+        // BEGIN Android-changed: Check max memory at runtime
+        long maxMemory = Runtime.getRuntime().maxMemory();
+        if (maxMemory > Integer.MAX_VALUE)
+        {
+            return Integer.MAX_VALUE;
+        }
+
+        return (int) maxMemory;
+        // END Android-changed: Check max memory at runtime
+    }
+
+    static int calculateBodyLength(
+        int length)
+    {
+        int count = 1;
+
+        if (length > 127)
+        {
+            int size = 1;
+            int val = length;
+
+            while ((val >>>= 8) != 0)
+            {
+                size++;
+            }
+
+            for (int i = (size - 1) * 8; i >= 0; i -= 8)
+            {
+                count++;
+            }
+        }
+
+        return count;
+    }
+
+    static int calculateTagLength(int tagNo)
+        throws IOException
+    {
+        int length = 1;
+
+        if (tagNo >= 31)
+        {
+            if (tagNo < 128)
+            {
+                length++;
+            }
+            else
+            {
+                byte[] stack = new byte[5];
+                int pos = stack.length;
+
+                stack[--pos] = (byte)(tagNo & 0x7F);
+
+                do
+                {
+                    tagNo >>= 7;
+                    stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
+                }
+                while (tagNo > 127);
+
+                length += stack.length - pos;
+            }
+        }
+
+        return length;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
new file mode 100644
index 0000000..0c8980e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
@@ -0,0 +1,169 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.bc;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ *  Object Identifiers belonging to iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle (1.3.6.1.4.1.22554)
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface BCObjectIdentifiers
+{
+    /**
+     *  iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle
+     *<p>
+     *  1.3.6.1.4.1.22554
+     */
+    public static final ASN1ObjectIdentifier bc = new ASN1ObjectIdentifier("1.3.6.1.4.1.22554");
+
+    /**
+     * pbe(1) algorithms
+     * <p>
+     * 1.3.6.1.4.1.22554.1
+     */
+    public static final ASN1ObjectIdentifier bc_pbe        = bc.branch("1");
+
+    /**
+     * SHA-1(1)
+     * <p>
+     * 1.3.6.1.4.1.22554.1.1
+     */
+    public static final ASN1ObjectIdentifier bc_pbe_sha1   = bc_pbe.branch("1");
+
+    /** SHA-2.SHA-256; 1.3.6.1.4.1.22554.1.2.1 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256 = bc_pbe.branch("2.1");
+    /** SHA-2.SHA-384; 1.3.6.1.4.1.22554.1.2.2 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha384 = bc_pbe.branch("2.2");
+    /** SHA-2.SHA-512; 1.3.6.1.4.1.22554.1.2.3 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha512 = bc_pbe.branch("2.3");
+    /** SHA-2.SHA-224; 1.3.6.1.4.1.22554.1.2.4 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha224 = bc_pbe.branch("2.4");
+
+    /**
+     * PKCS-5(1)|PKCS-12(2)
+     */
+    /** SHA-1.PKCS5;  1.3.6.1.4.1.22554.1.1.1 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs5    = bc_pbe_sha1.branch("1");
+    /** SHA-1.PKCS12; 1.3.6.1.4.1.22554.1.1.2 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12   = bc_pbe_sha1.branch("2");
+
+    /** SHA-256.PKCS12; 1.3.6.1.4.1.22554.1.2.1.1 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs5  = bc_pbe_sha256.branch("1");
+    /** SHA-256.PKCS12; 1.3.6.1.4.1.22554.1.2.1.2 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12 = bc_pbe_sha256.branch("2");
+
+    /**
+     * AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42))
+     */
+    /** 1.3.6.1.4.1.22554.1.1.2.1.2 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc   = bc_pbe_sha1_pkcs12.branch("1.2");
+    /** 1.3.6.1.4.1.22554.1.1.2.1.22 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc   = bc_pbe_sha1_pkcs12.branch("1.22");
+    /** 1.3.6.1.4.1.22554.1.1.2.1.42 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc   = bc_pbe_sha1_pkcs12.branch("1.42");
+
+    /** 1.3.6.1.4.1.22554.1.1.2.2.2 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = bc_pbe_sha256_pkcs12.branch("1.2");
+    /** 1.3.6.1.4.1.22554.1.1.2.2.22 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = bc_pbe_sha256_pkcs12.branch("1.22");
+    /** 1.3.6.1.4.1.22554.1.1.2.2.42 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = bc_pbe_sha256_pkcs12.branch("1.42");
+
+    /**
+     * signature(2) algorithms
+     */
+    public static final ASN1ObjectIdentifier bc_sig        = bc.branch("2");
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    /**
+     * Sphincs-256
+     *
+    public static final ASN1ObjectIdentifier sphincs256                      = bc_sig.branch("1");
+    public static final ASN1ObjectIdentifier sphincs256_with_BLAKE512        = sphincs256.branch("1");
+    public static final ASN1ObjectIdentifier sphincs256_with_SHA512          = sphincs256.branch("2");
+    public static final ASN1ObjectIdentifier sphincs256_with_SHA3_512        = sphincs256.branch("3");
+
+    /**
+     * XMSS
+     */
+    public static final ASN1ObjectIdentifier xmss = bc_sig.branch("2");
+    public static final ASN1ObjectIdentifier xmss_SHA256ph = xmss.branch("1");
+    public static final ASN1ObjectIdentifier xmss_SHA512ph = xmss.branch("2");
+    public static final ASN1ObjectIdentifier xmss_SHAKE128ph = xmss.branch("3");
+    public static final ASN1ObjectIdentifier xmss_SHAKE256ph = xmss.branch("4");
+    public static final ASN1ObjectIdentifier xmss_SHA256 = xmss.branch("5");
+    public static final ASN1ObjectIdentifier xmss_SHA512 = xmss.branch("6");
+    public static final ASN1ObjectIdentifier xmss_SHAKE128 = xmss.branch("7");
+    public static final ASN1ObjectIdentifier xmss_SHAKE256 = xmss.branch("8");
+
+    /**
+     * XMSS^MT
+     */
+    public static final ASN1ObjectIdentifier xmss_mt = bc_sig.branch("3");
+    public static final ASN1ObjectIdentifier xmss_mt_SHA256ph = xmss_mt.branch("1");
+    public static final ASN1ObjectIdentifier xmss_mt_SHA512ph = xmss_mt.branch("2");
+    public static final ASN1ObjectIdentifier xmss_mt_SHAKE128ph = xmss_mt.branch("3");
+    public static final ASN1ObjectIdentifier xmss_mt_SHAKE256ph = xmss_mt.branch("4");
+    public static final ASN1ObjectIdentifier xmss_mt_SHA256 = xmss_mt.branch("5");
+    public static final ASN1ObjectIdentifier xmss_mt_SHA512 = xmss_mt.branch("6");
+    public static final ASN1ObjectIdentifier xmss_mt_SHAKE128 = xmss_mt.branch("7");
+    public static final ASN1ObjectIdentifier xmss_mt_SHAKE256 = xmss_mt.branch("8");
+
+    // old OIDs.
+    /**
+     * @deprecated use xmss_SHA256ph
+     */
+    public static final ASN1ObjectIdentifier xmss_with_SHA256          = xmss_SHA256ph;
+    /**
+     * @deprecated use xmss_SHA512ph
+     */
+    public static final ASN1ObjectIdentifier xmss_with_SHA512 = xmss_SHA512ph;
+    /**
+     * @deprecated use xmss_SHAKE128ph
+     */
+    public static final ASN1ObjectIdentifier xmss_with_SHAKE128 = xmss_SHAKE128ph;
+    /**
+     * @deprecated use xmss_SHAKE256ph
+     */
+    public static final ASN1ObjectIdentifier xmss_with_SHAKE256        = xmss_SHAKE256ph;
+
+    /**
+     * @deprecated use xmss_mt_SHA256ph
+     */
+    public static final ASN1ObjectIdentifier xmss_mt_with_SHA256          = xmss_mt_SHA256ph;
+    /**
+     * @deprecated use xmss_mt_SHA512ph
+     */
+    public static final ASN1ObjectIdentifier xmss_mt_with_SHA512          = xmss_mt_SHA512ph;
+    /**
+     * @deprecated use xmss_mt_SHAKE128ph
+     */
+    public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE128        = xmss_mt_SHAKE128;
+    /**
+     * @deprecated use xmss_mt_SHAKE256ph
+     */
+    public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE256        = xmss_mt_SHAKE256;
+
+    /**
+     * qTESLA
+     */
+    public static final ASN1ObjectIdentifier qTESLA = bc_sig.branch("4");
+    public static final ASN1ObjectIdentifier qTESLA_I = qTESLA.branch("1");
+    public static final ASN1ObjectIdentifier qTESLA_III_size = qTESLA.branch("2");
+    public static final ASN1ObjectIdentifier qTESLA_III_speed = qTESLA.branch("3");
+    public static final ASN1ObjectIdentifier qTESLA_p_I = qTESLA.branch("4");
+    public static final ASN1ObjectIdentifier qTESLA_p_III = qTESLA.branch("5");
+
+    /**
+     * key_exchange(3) algorithms
+     *
+    public static final ASN1ObjectIdentifier bc_exch = bc.branch("3");
+
+    /**
+     * NewHope
+     *
+    public static final ASN1ObjectIdentifier newHope = bc_exch.branch("1");
+    */
+    // END Android-removed: Unsupported algorithms
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/Attribute.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/Attribute.java
new file mode 100644
index 0000000..55e26e6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/Attribute.java
@@ -0,0 +1,112 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#page-14">RFC 5652</a>:
+ * Attribute is a pair of OID (as type identifier) + set of values.
+ * <p>
+ * <pre>
+ * Attribute ::= SEQUENCE {
+ *     attrType OBJECT IDENTIFIER,
+ *     attrValues SET OF AttributeValue
+ * }
+ * 
+ * AttributeValue ::= ANY
+ * </pre>
+ * <p>
+ * General rule on values is that same AttributeValue must not be included
+ * multiple times into the set. That is, if the value is a SET OF INTEGERs,
+ * then having same value repeated is wrong: (1, 1), but different values is OK: (1, 2).
+ * Normally the AttributeValue syntaxes are more complicated than that.
+ * <p>
+ * General rule of Attribute usage is that the {@link Attributes} containers
+ * must not have multiple Attribute:s with same attrType (OID) there.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Attribute
+    extends ASN1Object
+{
+    private ASN1ObjectIdentifier attrType;
+    private ASN1Set             attrValues;
+
+    /**
+     * Return an Attribute object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link Attribute} object
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with Attribute structure inside
+     * </ul>
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static Attribute getInstance(
+        Object o)
+    {
+        if (o instanceof Attribute)
+        {
+            return (Attribute)o;
+        }
+        
+        if (o != null)
+        {
+            return new Attribute(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
+    }
+    
+    private Attribute(
+        ASN1Sequence seq)
+    {
+        attrType = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+        attrValues = (ASN1Set)seq.getObjectAt(1);
+    }
+
+    public Attribute(
+        ASN1ObjectIdentifier attrType,
+        ASN1Set             attrValues)
+    {
+        this.attrType = attrType;
+        this.attrValues = attrValues;
+    }
+
+    public ASN1ObjectIdentifier getAttrType()
+    {
+        return attrType;
+    }
+    
+    public ASN1Set getAttrValues()
+    {
+        return attrValues;
+    }
+
+    public ASN1Encodable[] getAttributeValues()
+    {
+        return attrValues.toArray();
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(attrType);
+        v.add(attrValues);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/AttributeTable.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/AttributeTable.java
new file mode 100644
index 0000000..e9cc12b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/AttributeTable.java
@@ -0,0 +1,242 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.DERSet;
+
+/**
+ * This is helper tool to construct {@link Attributes} sets.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AttributeTable
+{
+    private Hashtable attributes = new Hashtable();
+
+    public AttributeTable(
+        Hashtable  attrs)
+    {
+        attributes = copyTable(attrs);
+    }
+
+    public AttributeTable(
+        ASN1EncodableVector v)
+    {
+        for (int i = 0; i != v.size(); i++)
+        {
+            Attribute   a = Attribute.getInstance(v.get(i));
+
+            addAttribute(a.getAttrType(), a);
+        }
+    }
+
+    public AttributeTable(
+        ASN1Set    s)
+    {
+        for (int i = 0; i != s.size(); i++)
+        {
+            Attribute   a = Attribute.getInstance(s.getObjectAt(i));
+
+            addAttribute(a.getAttrType(), a);
+        }
+    }
+
+    public AttributeTable(
+        Attribute    attr)
+    {
+        addAttribute(attr.getAttrType(), attr);
+    }
+
+    public AttributeTable(
+        Attributes    attrs)
+    {
+        this(ASN1Set.getInstance(attrs.toASN1Primitive()));
+    }
+
+    private void addAttribute(
+        ASN1ObjectIdentifier oid,
+        Attribute           a)
+    {
+        Object value = attributes.get(oid);
+        
+        if (value == null)
+        {
+            attributes.put(oid, a);
+        }
+        else
+        {
+            Vector v;
+            
+            if (value instanceof Attribute)
+            {
+                v = new Vector();
+                
+                v.addElement(value);
+                v.addElement(a);
+            }
+            else
+            {
+                v = (Vector)value;
+            
+                v.addElement(a);
+            }
+            
+            attributes.put(oid, v);
+        }
+    }
+
+    /**
+     * Return the first attribute matching the OBJECT IDENTIFIER oid.
+     * 
+     * @param oid type of attribute required.
+     * @return first attribute found of type oid.
+     */
+    public Attribute get(
+        ASN1ObjectIdentifier oid)
+    {
+        Object value = attributes.get(oid);
+        
+        if (value instanceof Vector)
+        {
+            return (Attribute)((Vector)value).elementAt(0);
+        }
+        
+        return (Attribute)value;
+    }
+
+    /**
+     * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be 
+     * empty if there are no attributes of the required type present.
+     * 
+     * @param oid type of attribute required.
+     * @return a vector of all the attributes found of type oid.
+     */
+    public ASN1EncodableVector getAll(
+        ASN1ObjectIdentifier oid)
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        Object value = attributes.get(oid);
+        
+        if (value instanceof Vector)
+        {
+            Enumeration e = ((Vector)value).elements();
+            
+            while (e.hasMoreElements())
+            {
+                v.add((Attribute)e.nextElement());
+            }
+        }
+        else if (value != null)
+        {
+            v.add((Attribute)value);
+        }
+        
+        return v;
+    }
+
+    public int size()
+    {
+        int size = 0;
+
+        for (Enumeration en = attributes.elements(); en.hasMoreElements();)
+        {
+            Object o = en.nextElement();
+
+            if (o instanceof Vector)
+            {
+                size += ((Vector)o).size();
+            }
+            else
+            {
+                size++;
+            }
+        }
+
+        return size;
+    }
+
+    public Hashtable toHashtable()
+    {
+        return copyTable(attributes);
+    }
+    
+    public ASN1EncodableVector toASN1EncodableVector()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+        Enumeration          e = attributes.elements();
+        
+        while (e.hasMoreElements())
+        {
+            Object value = e.nextElement();
+            
+            if (value instanceof Vector)
+            {
+                Enumeration en = ((Vector)value).elements();
+                
+                while (en.hasMoreElements())
+                {
+                    v.add(Attribute.getInstance(en.nextElement()));
+                }
+            }
+            else
+            {
+                v.add(Attribute.getInstance(value));
+            }
+        }
+        
+        return v;
+    }
+
+    public Attributes toASN1Structure()
+    {
+        return new Attributes(this.toASN1EncodableVector());
+    }
+
+    private Hashtable copyTable(
+        Hashtable in)
+    {
+        Hashtable   out = new Hashtable();
+        Enumeration e = in.keys();
+        
+        while (e.hasMoreElements())
+        {
+            Object key = e.nextElement();
+            
+            out.put(key, in.get(key));
+        }
+        
+        return out;
+    }
+
+    /**
+     * Return a new table with the passed in attribute added.
+     *
+     * @param attrType the type of the attribute to add.
+     * @param attrValue the value corresponding to the attribute (will be wrapped in a SET).
+     * @return a new table with the extra attribute in it.
+     */
+    public AttributeTable add(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue)
+    {
+        AttributeTable newTable = new AttributeTable(attributes);
+
+        newTable.addAttribute(attrType, new Attribute(attrType, new DERSet(attrValue)));
+
+        return newTable;
+    }
+
+    public AttributeTable remove(ASN1ObjectIdentifier attrType)
+    {
+        AttributeTable newTable = new AttributeTable(attributes);
+
+        newTable.attributes.remove(attrType);
+
+        return newTable;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/Attributes.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/Attributes.java
new file mode 100644
index 0000000..8e76939
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/Attributes.java
@@ -0,0 +1,95 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DLSet;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652">RFC 5652</a> defines
+ * 5 "SET OF Attribute" entities with 5 different names.
+ * This is common implementation for them all:
+ * <pre>
+ *   SignedAttributes      ::= SET SIZE (1..MAX) OF Attribute
+ *   UnsignedAttributes    ::= SET SIZE (1..MAX) OF Attribute
+ *   UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *   AuthAttributes        ::= SET SIZE (1..MAX) OF Attribute
+ *   UnauthAttributes      ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * Attributes ::=
+ *   SET SIZE(1..MAX) OF Attribute
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Attributes
+    extends ASN1Object
+{
+    private ASN1Set attributes;
+
+    private Attributes(ASN1Set set)
+    {
+        attributes = set;
+    }
+
+    public Attributes(ASN1EncodableVector v)
+    {
+        attributes = new DLSet(v);
+    }
+
+    /**
+     * Return an Attribute set object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link Attributes} object
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.ASN1Set#getInstance(java.lang.Object) ASN1Set} input formats with Attributes structure inside
+     * </ul>
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static Attributes getInstance(Object obj)
+    {
+        if (obj instanceof Attributes)
+        {
+            return (Attributes)obj;
+        }
+        else if (obj != null)
+        {
+            return new Attributes(ASN1Set.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static Attributes getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        return getInstance(ASN1Set.getInstance(obj, explicit));
+    }
+
+    public Attribute[] getAttributes()
+    {
+        Attribute[] rv = new Attribute[attributes.size()];
+
+        for (int i = 0; i != rv.length; i++)
+        {
+            rv[i] = Attribute.getInstance(attributes.getObjectAt(i));
+        }
+
+        return rv;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return attributes;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/CMSAlgorithmProtection.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/CMSAlgorithmProtection.java
new file mode 100644
index 0000000..6b85d5b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/CMSAlgorithmProtection.java
@@ -0,0 +1,138 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * From RFC 6211
+ * <pre>
+ * CMSAlgorithmProtection ::= SEQUENCE {
+ *    digestAlgorithm         DigestAlgorithmIdentifier,
+ *    signatureAlgorithm  [1] SignatureAlgorithmIdentifier OPTIONAL,
+ *    macAlgorithm        [2] MessageAuthenticationCodeAlgorithm
+ *                                     OPTIONAL
+ * }
+ * (WITH COMPONENTS { signatureAlgorithm PRESENT,
+ *                    macAlgorithm ABSENT } |
+ *  WITH COMPONENTS { signatureAlgorithm ABSENT,
+ *                    macAlgorithm PRESENT })
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CMSAlgorithmProtection
+    extends ASN1Object
+{
+    public static final int SIGNATURE = 1;
+    public static final int MAC = 2;
+
+    private final AlgorithmIdentifier digestAlgorithm;
+    private final AlgorithmIdentifier signatureAlgorithm;
+    private final AlgorithmIdentifier macAlgorithm;
+
+    public CMSAlgorithmProtection(AlgorithmIdentifier digestAlgorithm, int type, AlgorithmIdentifier algorithmIdentifier)
+    {
+        if (digestAlgorithm == null || algorithmIdentifier == null)
+        {
+            throw new NullPointerException("AlgorithmIdentifiers cannot be null");
+        }
+
+        this.digestAlgorithm = digestAlgorithm;
+
+        if (type == 1)
+        {
+            this.signatureAlgorithm = algorithmIdentifier;
+            this.macAlgorithm = null;
+        }
+        else if (type == 2)
+        {
+            this.signatureAlgorithm = null;
+            this.macAlgorithm = algorithmIdentifier;
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unknown type: " + type);
+        }
+    }
+
+    private CMSAlgorithmProtection(ASN1Sequence sequence)
+    {
+        if (sequence.size() != 2)
+        {
+            throw new IllegalArgumentException("Sequence wrong size: One of signatureAlgorithm or macAlgorithm must be present");
+        }
+
+        this.digestAlgorithm = AlgorithmIdentifier.getInstance(sequence.getObjectAt(0));
+
+        ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(sequence.getObjectAt(1));
+        if (tagged.getTagNo() == 1)
+        {
+            this.signatureAlgorithm = AlgorithmIdentifier.getInstance(tagged, false);
+            this.macAlgorithm = null;
+        }
+        else if (tagged.getTagNo() == 2)
+        {
+            this.signatureAlgorithm = null;
+
+            this.macAlgorithm = AlgorithmIdentifier.getInstance(tagged, false);
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unknown tag found: " + tagged.getTagNo());
+        }
+    }
+
+    public static CMSAlgorithmProtection getInstance(
+        Object obj)
+    {
+        if (obj instanceof CMSAlgorithmProtection)
+        {
+            return (CMSAlgorithmProtection)obj;
+        }
+        else if (obj != null)
+        {
+            return new CMSAlgorithmProtection(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+
+    public AlgorithmIdentifier getDigestAlgorithm()
+    {
+        return digestAlgorithm;
+    }
+
+    public AlgorithmIdentifier getMacAlgorithm()
+    {
+        return macAlgorithm;
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return signatureAlgorithm;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(digestAlgorithm);
+        if (signatureAlgorithm != null)
+        {
+            v.add(new DERTaggedObject(false, 1, signatureAlgorithm));
+        }
+        if (macAlgorithm != null)
+        {
+            v.add(new DERTaggedObject(false, 2, macAlgorithm));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/CMSAttributes.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/CMSAttributes.java
new file mode 100644
index 0000000..641ce37
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/CMSAttributes.java
@@ -0,0 +1,38 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652">RFC 5652</a> CMS attribute OID constants.
+ * and <a href="http://tools.ietf.org/html/rfc6211">RFC 6211</a> Algorithm Identifier Protection Attribute.
+ * <pre>
+ * contentType      ::= 1.2.840.113549.1.9.3
+ * messageDigest    ::= 1.2.840.113549.1.9.4
+ * signingTime      ::= 1.2.840.113549.1.9.5
+ * counterSignature ::= 1.2.840.113549.1.9.6
+ *
+ * contentHint      ::= 1.2.840.113549.1.9.16.2.4
+ * cmsAlgorithmProtect := 1.2.840.113549.1.9.52
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+
+public interface CMSAttributes
+{
+    /** PKCS#9: 1.2.840.113549.1.9.3 */
+    ASN1ObjectIdentifier  contentType = PKCSObjectIdentifiers.pkcs_9_at_contentType;
+    /** PKCS#9: 1.2.840.113549.1.9.4 */
+    ASN1ObjectIdentifier  messageDigest = PKCSObjectIdentifiers.pkcs_9_at_messageDigest;
+    /** PKCS#9: 1.2.840.113549.1.9.5 */
+    ASN1ObjectIdentifier  signingTime = PKCSObjectIdentifiers.pkcs_9_at_signingTime;
+    /** PKCS#9: 1.2.840.113549.1.9.6 */
+    ASN1ObjectIdentifier  counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature;
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.4 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */
+    ASN1ObjectIdentifier  contentHint = PKCSObjectIdentifiers.id_aa_contentHint;
+
+    ASN1ObjectIdentifier  cmsAlgorithmProtect = PKCSObjectIdentifiers.id_aa_cmsAlgorithmProtect;
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
new file mode 100644
index 0000000..38f5a55
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
@@ -0,0 +1,47 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface CMSObjectIdentifiers
+{
+    /** PKCS#7: 1.2.840.113549.1.7.1 */
+    static final ASN1ObjectIdentifier    data = PKCSObjectIdentifiers.data;
+    /** PKCS#7: 1.2.840.113549.1.7.2 */
+    static final ASN1ObjectIdentifier    signedData = PKCSObjectIdentifiers.signedData;
+    /** PKCS#7: 1.2.840.113549.1.7.3 */
+    static final ASN1ObjectIdentifier    envelopedData = PKCSObjectIdentifiers.envelopedData;
+    /** PKCS#7: 1.2.840.113549.1.7.4 */
+    static final ASN1ObjectIdentifier    signedAndEnvelopedData = PKCSObjectIdentifiers.signedAndEnvelopedData;
+    /** PKCS#7: 1.2.840.113549.1.7.5 */
+    static final ASN1ObjectIdentifier    digestedData = PKCSObjectIdentifiers.digestedData;
+    /** PKCS#7: 1.2.840.113549.1.7.6 */
+    static final ASN1ObjectIdentifier    encryptedData = PKCSObjectIdentifiers.encryptedData;
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.2 -- smime ct authData */
+    static final ASN1ObjectIdentifier    authenticatedData = PKCSObjectIdentifiers.id_ct_authData;
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.9 -- smime ct compressedData */
+    static final ASN1ObjectIdentifier    compressedData = PKCSObjectIdentifiers.id_ct_compressedData;
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.23 -- smime ct authEnvelopedData */
+    static final ASN1ObjectIdentifier    authEnvelopedData = PKCSObjectIdentifiers.id_ct_authEnvelopedData;
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.31 -- smime ct timestampedData*/
+    static final ASN1ObjectIdentifier    timestampedData = PKCSObjectIdentifiers.id_ct_timestampedData;
+
+    /**
+     * The other Revocation Info arc
+     * <p>
+     * <pre>
+     * id-ri OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
+     *        dod(6) internet(1) security(5) mechanisms(5) pkix(7) ri(16) }
+     * </pre>
+     */
+    static final ASN1ObjectIdentifier    id_ri = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.16");
+
+    /** 1.3.6.1.5.5.7.16.2 */
+    static final ASN1ObjectIdentifier    id_ri_ocsp_response = id_ri.branch("2");
+    /** 1.3.6.1.5.5.7.16.4 */
+    static final ASN1ObjectIdentifier    id_ri_scvp = id_ri.branch("4");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/ContentInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/ContentInfo.java
new file mode 100644
index 0000000..85bbb28
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/ContentInfo.java
@@ -0,0 +1,132 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.BERSequence;
+import com.android.internal.org.bouncycastle.asn1.BERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-3">RFC 5652</a> ContentInfo, and 
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.2">RFC 5652</a> EncapsulatedContentInfo objects.
+ *
+ * <pre>
+ * ContentInfo ::= SEQUENCE {
+ *     contentType ContentType,
+ *     content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
+ * }
+ *
+ * EncapsulatedContentInfo ::= SEQUENCE {
+ *     eContentType ContentType,
+ *     eContent [0] EXPLICIT OCTET STRING OPTIONAL
+ * }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ContentInfo
+    extends ASN1Object
+    implements CMSObjectIdentifiers
+{
+    private ASN1ObjectIdentifier contentType;
+    private ASN1Encodable        content;
+
+    /**
+     * Return an ContentInfo object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link ContentInfo} object
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with ContentInfo structure inside
+     * </ul>
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static ContentInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof ContentInfo)
+        {
+            return (ContentInfo)obj;
+        }
+        else if (obj != null)
+        {
+            return new ContentInfo(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static ContentInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    /**
+     * @deprecated use getInstance()
+     */
+    public ContentInfo(
+        ASN1Sequence  seq)
+    {
+        if (seq.size() < 1 || seq.size() > 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        contentType = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+
+        if (seq.size() > 1)
+        {
+            ASN1TaggedObject tagged = (ASN1TaggedObject)seq.getObjectAt(1);
+            if (!tagged.isExplicit() || tagged.getTagNo() != 0)
+            {
+                throw new IllegalArgumentException("Bad tag for 'content'");
+            }
+
+            content = tagged.getObject();
+        }
+    }
+
+    public ContentInfo(
+        ASN1ObjectIdentifier contentType,
+        ASN1Encodable        content)
+    {
+        this.contentType = contentType;
+        this.content = content;
+    }
+
+    public ASN1ObjectIdentifier getContentType()
+    {
+        return contentType;
+    }
+
+    public ASN1Encodable getContent()
+    {
+        return content;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(contentType);
+
+        if (content != null)
+        {
+            v.add(new BERTaggedObject(0, content));
+        }
+
+        return new BERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/GCMParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/GCMParameters.java
new file mode 100644
index 0000000..ee12a4b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/GCMParameters.java
@@ -0,0 +1,104 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5084">RFC 5084</a>: GCMParameters object.
+ * <p>
+ * <pre>
+ GCMParameters ::= SEQUENCE {
+   aes-nonce        OCTET STRING, -- recommended size is 12 octets
+   aes-ICVlen       AES-GCM-ICVlen DEFAULT 12 }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class GCMParameters
+    extends ASN1Object
+{
+    private byte[] nonce;
+    private int icvLen;
+
+    /**
+     * Return an GCMParameters object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.cms.GCMParameters} object
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.ASN1Sequence#getInstance(Object) ASN1Sequence} input formats with GCMParameters structure inside
+     * </ul>
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static GCMParameters getInstance(
+        Object  obj)
+    {
+        if (obj instanceof GCMParameters)
+        {
+            return (GCMParameters)obj;
+        }
+        else if (obj != null)
+        {
+            return new GCMParameters(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private GCMParameters(
+        ASN1Sequence seq)
+    {
+        this.nonce = ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets();
+
+        if (seq.size() == 2)
+        {
+            this.icvLen = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue().intValue();
+        }
+        else
+        {
+            this.icvLen = 12;
+        }
+    }
+
+    public GCMParameters(
+        byte[] nonce,
+        int    icvLen)
+    {
+        this.nonce = Arrays.clone(nonce);
+        this.icvLen = icvLen;
+    }
+
+    public byte[] getNonce()
+    {
+        return Arrays.clone(nonce);
+    }
+
+    public int getIcvLen()
+    {
+        return icvLen;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(new DEROctetString(nonce));
+
+        if (icvLen != 12)
+        {
+            v.add(new ASN1Integer(icvLen));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java
new file mode 100644
index 0000000..db92e3f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java
@@ -0,0 +1,140 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x509.Certificate;
+import com.android.internal.org.bouncycastle.asn1.x509.X509CertificateStructure;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Name;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-10.2.4">RFC 5652</a>: IssuerAndSerialNumber object.
+ * <p>
+ * <pre>
+ * IssuerAndSerialNumber ::= SEQUENCE {
+ *     issuer Name,
+ *     serialNumber CertificateSerialNumber
+ * }
+ *
+ * CertificateSerialNumber ::= INTEGER  -- See RFC 5280
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class IssuerAndSerialNumber
+    extends ASN1Object
+{
+    private X500Name    name;
+    private ASN1Integer  serialNumber;
+
+    /**
+     * Return an IssuerAndSerialNumber object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link IssuerAndSerialNumber} object
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with IssuerAndSerialNumber structure inside
+     * </ul>
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static IssuerAndSerialNumber getInstance(
+        Object  obj)
+    {
+        if (obj instanceof IssuerAndSerialNumber)
+        {
+            return (IssuerAndSerialNumber)obj;
+        }
+        else if (obj != null)
+        {
+            return new IssuerAndSerialNumber(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * @deprecated  use getInstance() method.
+     */
+    public IssuerAndSerialNumber(
+        ASN1Sequence    seq)
+    {
+        this.name = X500Name.getInstance(seq.getObjectAt(0));
+        this.serialNumber = (ASN1Integer)seq.getObjectAt(1);
+    }
+
+    public IssuerAndSerialNumber(
+        Certificate certificate)
+    {
+        this.name = certificate.getIssuer();
+        this.serialNumber = certificate.getSerialNumber();
+    }
+
+    /**
+     * @deprecated use constructor taking Certificate
+     */
+    public IssuerAndSerialNumber(
+        X509CertificateStructure certificate)
+    {
+        this.name = certificate.getIssuer();
+        this.serialNumber = certificate.getSerialNumber();
+    }
+
+    public IssuerAndSerialNumber(
+        X500Name name,
+        BigInteger  serialNumber)
+    {
+        this.name = name;
+        this.serialNumber = new ASN1Integer(serialNumber);
+    }
+
+    /**
+     * @deprecated use X500Name constructor
+     */
+    public IssuerAndSerialNumber(
+        X509Name    name,
+        BigInteger  serialNumber)
+    {
+        this.name = X500Name.getInstance(name);
+        this.serialNumber = new ASN1Integer(serialNumber);
+    }
+
+    /**
+     * @deprecated use X500Name constructor
+     */
+    public IssuerAndSerialNumber(
+        X509Name    name,
+        ASN1Integer  serialNumber)
+    {
+        this.name = X500Name.getInstance(name);
+        this.serialNumber = serialNumber;
+    }
+
+    public X500Name getName()
+    {
+        return name;
+    }
+
+    public ASN1Integer getSerialNumber()
+    {
+        return serialNumber;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(name);
+        v.add(serialNumber);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/SignedData.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/SignedData.java
new file mode 100644
index 0000000..18f37eb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/SignedData.java
@@ -0,0 +1,332 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.BERSequence;
+import com.android.internal.org.bouncycastle.asn1.BERSet;
+import com.android.internal.org.bouncycastle.asn1.BERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.1">RFC 5652</a>:
+ * <p>
+ * A signed data object containing multitude of {@link SignerInfo}s.
+ * <pre>
+ * SignedData ::= SEQUENCE {
+ *     version CMSVersion,
+ *     digestAlgorithms DigestAlgorithmIdentifiers,
+ *     encapContentInfo EncapsulatedContentInfo,
+ *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
+ *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ *     signerInfos SignerInfos
+ *   }
+ * 
+ * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
+ * 
+ * SignerInfos ::= SET OF SignerInfo
+ * </pre>
+ * <p>
+ * The version calculation uses following ruleset from RFC 5652 section 5.1:
+ * <pre>
+ * IF ((certificates is present) AND
+ *    (any certificates with a type of other are present)) OR
+ *    ((crls is present) AND
+ *    (any crls with a type of other are present))
+ * THEN version MUST be 5
+ * ELSE
+ *    IF (certificates is present) AND
+ *       (any version 2 attribute certificates are present)
+ *    THEN version MUST be 4
+ *    ELSE
+ *       IF ((certificates is present) AND
+ *          (any version 1 attribute certificates are present)) OR
+ *          (any SignerInfo structures are version 3) OR
+ *          (encapContentInfo eContentType is other than id-data)
+ *       THEN version MUST be 3
+ *       ELSE version MUST be 1
+ * </pre>
+ * <p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SignedData
+    extends ASN1Object
+{
+    private static final ASN1Integer VERSION_1 = new ASN1Integer(1);
+    private static final ASN1Integer VERSION_3 = new ASN1Integer(3);
+    private static final ASN1Integer VERSION_4 = new ASN1Integer(4);
+    private static final ASN1Integer VERSION_5 = new ASN1Integer(5);
+
+    private ASN1Integer version;
+    private ASN1Set     digestAlgorithms;
+    private ContentInfo contentInfo;
+    private ASN1Set     certificates;
+    private ASN1Set     crls;
+    private ASN1Set     signerInfos;
+    private boolean certsBer;
+    private boolean        crlsBer;
+
+    /**
+     * Return a SignedData object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link SignedData} object
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SignedData structure inside
+     * </ul>
+     *
+     * @param o the object we want converted.
+     * @return a reference that can be assigned to SignedData (may be null)
+     * @throws IllegalArgumentException if the object cannot be converted.
+     */
+    public static SignedData getInstance(
+        Object  o)
+    {
+        if (o instanceof SignedData)
+        {
+            return (SignedData)o;
+        }
+        else if (o != null)
+        {
+            return new SignedData(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
+    }
+
+    public SignedData(
+        ASN1Set     digestAlgorithms,
+        ContentInfo contentInfo,
+        ASN1Set     certificates,
+        ASN1Set     crls,
+        ASN1Set     signerInfos)
+    {
+        this.version = calculateVersion(contentInfo.getContentType(), certificates, crls, signerInfos);
+        this.digestAlgorithms = digestAlgorithms;
+        this.contentInfo = contentInfo;
+        this.certificates = certificates;
+        this.crls = crls;
+        this.signerInfos = signerInfos;
+        this.crlsBer = crls instanceof BERSet;
+        this.certsBer = certificates instanceof BERSet;
+    }
+
+
+    private ASN1Integer calculateVersion(
+        ASN1ObjectIdentifier contentOid,
+        ASN1Set certs,
+        ASN1Set crls,
+        ASN1Set signerInfs)
+    {
+        boolean otherCert = false;
+        boolean otherCrl = false;
+        boolean attrCertV1Found = false;
+        boolean attrCertV2Found = false;
+
+        if (certs != null)
+        {
+            for (Enumeration en = certs.getObjects(); en.hasMoreElements();)
+            {
+                Object obj = en.nextElement();
+                if (obj instanceof ASN1TaggedObject)
+                {
+                    ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(obj);
+
+                    if (tagged.getTagNo() == 1)
+                    {
+                        attrCertV1Found = true;
+                    }
+                    else if (tagged.getTagNo() == 2)
+                    {
+                        attrCertV2Found = true;
+                    }
+                    else if (tagged.getTagNo() == 3)
+                    {
+                        otherCert = true;
+                    }
+                }
+            }
+        }
+
+        if (otherCert)
+        {
+            return new ASN1Integer(5);
+        }
+
+        if (crls != null)         // no need to check if otherCert is true
+        {
+            for (Enumeration en = crls.getObjects(); en.hasMoreElements();)
+            {
+                Object obj = en.nextElement();
+                if (obj instanceof ASN1TaggedObject)
+                {
+                    otherCrl = true;
+                }
+            }
+        }
+
+        if (otherCrl)
+        {
+            return VERSION_5;
+        }
+
+        if (attrCertV2Found)
+        {
+            return VERSION_4;
+        }
+
+        if (attrCertV1Found)
+        {
+            return VERSION_3;
+        }
+
+        if (checkForVersion3(signerInfs))
+        {
+            return VERSION_3;
+        }
+
+        if (!CMSObjectIdentifiers.data.equals(contentOid))
+        {
+            return VERSION_3;
+        }
+
+        return VERSION_1;
+    }
+
+    private boolean checkForVersion3(ASN1Set signerInfs)
+    {
+        for (Enumeration e = signerInfs.getObjects(); e.hasMoreElements();)
+        {
+            SignerInfo s = SignerInfo.getInstance(e.nextElement());
+
+            if (s.getVersion().getValue().intValue() == 3)
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private SignedData(
+        ASN1Sequence seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        version = ASN1Integer.getInstance(e.nextElement());
+        digestAlgorithms = ((ASN1Set)e.nextElement());
+        contentInfo = ContentInfo.getInstance(e.nextElement());
+
+        while (e.hasMoreElements())
+        {
+            ASN1Primitive o = (ASN1Primitive)e.nextElement();
+
+            //
+            // an interesting feature of SignedData is that there appear
+            // to be varying implementations...
+            // for the moment we ignore anything which doesn't fit.
+            //
+            if (o instanceof ASN1TaggedObject)
+            {
+                ASN1TaggedObject tagged = (ASN1TaggedObject)o;
+
+                switch (tagged.getTagNo())
+                {
+                case 0:
+                    certsBer = tagged instanceof BERTaggedObject;
+                    certificates = ASN1Set.getInstance(tagged, false);
+                    break;
+                case 1:
+                    crlsBer = tagged instanceof BERTaggedObject;
+                    crls = ASN1Set.getInstance(tagged, false);
+                    break;
+                default:
+                    throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo());
+                }
+            }
+            else
+            {
+                signerInfos = (ASN1Set)o;
+            }
+        }
+    }
+
+    public ASN1Integer getVersion()
+    {
+        return version;
+    }
+
+    public ASN1Set getDigestAlgorithms()
+    {
+        return digestAlgorithms;
+    }
+
+    public ContentInfo getEncapContentInfo()
+    {
+        return contentInfo;
+    }
+
+    public ASN1Set getCertificates()
+    {
+        return certificates;
+    }
+
+    public ASN1Set getCRLs()
+    {
+        return crls;
+    }
+
+    public ASN1Set getSignerInfos()
+    {
+        return signerInfos;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(digestAlgorithms);
+        v.add(contentInfo);
+
+        if (certificates != null)
+        {
+            if (certsBer)
+            {
+                v.add(new BERTaggedObject(false, 0, certificates));
+            }
+            else
+            {
+                v.add(new DERTaggedObject(false, 0, certificates));
+            }
+        }
+
+        if (crls != null)
+        {
+            if (crlsBer)
+            {
+                v.add(new BERTaggedObject(false, 1, crls));
+            }
+            else
+            {
+                v.add(new DERTaggedObject(false, 1, crls));
+            }
+        }
+
+        v.add(signerInfos);
+
+        return new BERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/SignerIdentifier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/SignerIdentifier.java
new file mode 100644
index 0000000..53b66ec
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/SignerIdentifier.java
@@ -0,0 +1,116 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Choice;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.3">RFC 5652</a>:
+ * Identify who signed the containing {@link SignerInfo} object.
+ * <p>
+ * The certificates referred to by this are at containing {@link SignedData} structure.
+ * <p>
+ * <pre>
+ * SignerIdentifier ::= CHOICE {
+ *     issuerAndSerialNumber IssuerAndSerialNumber,
+ *     subjectKeyIdentifier [0] SubjectKeyIdentifier 
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SignerIdentifier
+    extends ASN1Object
+    implements ASN1Choice
+{
+    private ASN1Encodable id;
+    
+    public SignerIdentifier(
+        IssuerAndSerialNumber id)
+    {
+        this.id = id;
+    }
+    
+    public SignerIdentifier(
+        ASN1OctetString id)
+    {
+        this.id = new DERTaggedObject(false, 0, id);
+    }
+    
+    public SignerIdentifier(
+        ASN1Primitive id)
+    {
+        this.id = id;
+    }
+    
+    /**
+     * Return a SignerIdentifier object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link SignerIdentifier} object
+     * <li> {@link IssuerAndSerialNumber} object
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.ASN1OctetString#getInstance(java.lang.Object) ASN1OctetString} input formats with SignerIdentifier structure inside
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.ASN1Primitive ASN1Primitive} for SignerIdentifier constructor.
+     * </ul>
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static SignerIdentifier getInstance(
+        Object o)
+    {
+        if (o == null || o instanceof SignerIdentifier)
+        {
+            return (SignerIdentifier)o;
+        }
+        
+        if (o instanceof IssuerAndSerialNumber)
+        {
+            return new SignerIdentifier((IssuerAndSerialNumber)o);
+        }
+        
+        if (o instanceof ASN1OctetString)
+        {
+            return new SignerIdentifier((ASN1OctetString)o);
+        }
+        
+        if (o instanceof ASN1Primitive)
+        {
+            return new SignerIdentifier((ASN1Primitive)o);
+        }
+        
+        throw new IllegalArgumentException(
+             "Illegal object in SignerIdentifier: " + o.getClass().getName());
+    } 
+
+    public boolean isTagged()
+    {
+        return (id instanceof ASN1TaggedObject);
+    }
+
+    public ASN1Encodable getId()
+    {
+        if (id instanceof ASN1TaggedObject)
+        {
+            return ASN1OctetString.getInstance((ASN1TaggedObject)id, false);
+        }
+
+        return id;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return id.toASN1Primitive();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/SignerInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/SignerInfo.java
new file mode 100644
index 0000000..1b658a2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/SignerInfo.java
@@ -0,0 +1,284 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.3">RFC 5652</a>:
+ * Signature container per Signer, see {@link SignerIdentifier}.
+ * <pre>
+ * PKCS#7:
+ *
+ * SignerInfo ::= SEQUENCE {
+ *     version                   Version,
+ *     sid                       SignerIdentifier,
+ *     digestAlgorithm           DigestAlgorithmIdentifier,
+ *     authenticatedAttributes   [0] IMPLICIT Attributes OPTIONAL,
+ *     digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ *     encryptedDigest           EncryptedDigest,
+ *     unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+ * }
+ *
+ * EncryptedDigest ::= OCTET STRING
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * -----------------------------------------
+ *
+ * RFC 5652:
+ *
+ * SignerInfo ::= SEQUENCE {
+ *     version            CMSVersion,
+ *     sid                SignerIdentifier,
+ *     digestAlgorithm    DigestAlgorithmIdentifier,
+ *     signedAttrs        [0] IMPLICIT SignedAttributes OPTIONAL,
+ *     signatureAlgorithm SignatureAlgorithmIdentifier,
+ *     signature          SignatureValue,
+ *     unsignedAttrs      [1] IMPLICIT UnsignedAttributes OPTIONAL
+ * }
+ *
+ * -- {@link SignerIdentifier} referenced certificates are at containing
+ * -- {@link SignedData} certificates element.
+ *
+ * SignerIdentifier ::= CHOICE {
+ *     issuerAndSerialNumber {@link IssuerAndSerialNumber},
+ *     subjectKeyIdentifier  [0] SubjectKeyIdentifier }
+ *
+ * -- See {@link Attributes} for generalized SET OF {@link Attribute}
+ *
+ * SignedAttributes   ::= SET SIZE (1..MAX) OF Attribute
+ * UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute
+ * 
+ * {@link Attribute} ::= SEQUENCE {
+ *     attrType   OBJECT IDENTIFIER,
+ *     attrValues SET OF AttributeValue }
+ *
+ * AttributeValue ::= ANY
+ * 
+ * SignatureValue ::= OCTET STRING
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SignerInfo
+    extends ASN1Object
+{
+    private ASN1Integer              version;
+    private SignerIdentifier        sid;
+    private AlgorithmIdentifier     digAlgorithm;
+    private ASN1Set                 authenticatedAttributes;
+    private AlgorithmIdentifier     digEncryptionAlgorithm;
+    private ASN1OctetString         encryptedDigest;
+    private ASN1Set                 unauthenticatedAttributes;
+
+    /**
+     * Return a SignerInfo object from the given input
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link SignerInfo} object
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SignerInfo structure inside
+     * </ul>
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static SignerInfo getInstance(
+        Object  o)
+        throws IllegalArgumentException
+    {
+        if (o instanceof SignerInfo)
+        {
+            return (SignerInfo)o;
+        }
+        else if (o != null)
+        {
+            return new SignerInfo(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
+    }
+
+    /**
+     *
+     * @param sid
+     * @param digAlgorithm            CMS knows as 'digestAlgorithm'
+     * @param authenticatedAttributes CMS knows as 'signedAttrs'
+     * @param digEncryptionAlgorithm  CMS knows as 'signatureAlgorithm'
+     * @param encryptedDigest         CMS knows as 'signature'
+     * @param unauthenticatedAttributes CMS knows as 'unsignedAttrs'
+     */
+    public SignerInfo(
+        SignerIdentifier        sid,
+        AlgorithmIdentifier     digAlgorithm,
+        ASN1Set                 authenticatedAttributes,
+        AlgorithmIdentifier     digEncryptionAlgorithm,
+        ASN1OctetString         encryptedDigest,
+        ASN1Set                 unauthenticatedAttributes)
+    {
+        if (sid.isTagged())
+        {
+            this.version = new ASN1Integer(3);
+        }
+        else
+        {
+            this.version = new ASN1Integer(1);
+        }
+
+        this.sid = sid;
+        this.digAlgorithm = digAlgorithm;
+        this.authenticatedAttributes = authenticatedAttributes;
+        this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+        this.encryptedDigest = encryptedDigest;
+        this.unauthenticatedAttributes = unauthenticatedAttributes;
+    }
+
+    /**
+     *
+     * @param sid
+     * @param digAlgorithm            CMS knows as 'digestAlgorithm'
+     * @param authenticatedAttributes CMS knows as 'signedAttrs'
+     * @param digEncryptionAlgorithm  CMS knows as 'signatureAlgorithm'
+     * @param encryptedDigest         CMS knows as 'signature'
+     * @param unauthenticatedAttributes CMS knows as 'unsignedAttrs'
+     */
+    public SignerInfo(
+        SignerIdentifier        sid,
+        AlgorithmIdentifier     digAlgorithm,
+        Attributes              authenticatedAttributes,
+        AlgorithmIdentifier     digEncryptionAlgorithm,
+        ASN1OctetString         encryptedDigest,
+        Attributes              unauthenticatedAttributes)
+    {
+        if (sid.isTagged())
+        {
+            this.version = new ASN1Integer(3);
+        }
+        else
+        {
+            this.version = new ASN1Integer(1);
+        }
+
+        this.sid = sid;
+        this.digAlgorithm = digAlgorithm;
+        this.authenticatedAttributes = ASN1Set.getInstance(authenticatedAttributes);
+        this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+        this.encryptedDigest = encryptedDigest;
+        this.unauthenticatedAttributes = ASN1Set.getInstance(unauthenticatedAttributes);
+    }
+
+    /**
+     * @deprecated use getInstance() method.
+     */
+    public SignerInfo(
+        ASN1Sequence seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        version = (ASN1Integer)e.nextElement();
+        sid = SignerIdentifier.getInstance(e.nextElement());
+        digAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+
+        Object obj = e.nextElement();
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            authenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)obj, false);
+
+            digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+        }
+        else
+        {
+            authenticatedAttributes = null;
+            digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(obj);
+        }
+
+        encryptedDigest = DEROctetString.getInstance(e.nextElement());
+
+        if (e.hasMoreElements())
+        {
+            unauthenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false);
+        }
+        else
+        {
+            unauthenticatedAttributes = null;
+        }
+    }
+
+    public ASN1Integer getVersion()
+    {
+        return version;
+    }
+
+    public SignerIdentifier getSID()
+    {
+        return sid;
+    }
+
+    public ASN1Set getAuthenticatedAttributes()
+    {
+        return authenticatedAttributes;
+    }
+
+    public AlgorithmIdentifier getDigestAlgorithm()
+    {
+        return digAlgorithm;
+    }
+
+    public ASN1OctetString getEncryptedDigest()
+    {
+        return encryptedDigest;
+    }
+
+    public AlgorithmIdentifier getDigestEncryptionAlgorithm()
+    {
+        return digEncryptionAlgorithm;
+    }
+
+    public ASN1Set getUnauthenticatedAttributes()
+    {
+        return unauthenticatedAttributes;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(sid);
+        v.add(digAlgorithm);
+
+        if (authenticatedAttributes != null)
+        {
+            v.add(new DERTaggedObject(false, 0, authenticatedAttributes));
+        }
+
+        v.add(digEncryptionAlgorithm);
+        v.add(encryptedDigest);
+
+        if (unauthenticatedAttributes != null)
+        {
+            v.add(new DERTaggedObject(false, 1, unauthenticatedAttributes));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/Time.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/Time.java
new file mode 100644
index 0000000..1a5f153
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/cms/Time.java
@@ -0,0 +1,208 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.cms;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+// Android-added: Localization support
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.SimpleTimeZone;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Choice;
+import com.android.internal.org.bouncycastle.asn1.ASN1GeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.ASN1UTCTime;
+import com.android.internal.org.bouncycastle.asn1.DERGeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.DERUTCTime;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-11.3">RFC 5652</a>:
+ * Dual-mode timestamp format producing either UTCTIme or GeneralizedTime.
+ * <p>
+ * <pre>
+ * Time ::= CHOICE {
+ *     utcTime        UTCTime,
+ *     generalTime    GeneralizedTime }
+ * </pre>
+ * <p>
+ * This has a constructor using java.util.Date for input which generates
+ * a {@link com.android.internal.org.bouncycastle.asn1.DERUTCTime DERUTCTime} object if the
+ * supplied datetime is in range 1950-01-01-00:00:00 UTC until 2049-12-31-23:59:60 UTC.
+ * If the datetime value is outside that range, the generated object will be
+ * {@link com.android.internal.org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime}.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Time
+    extends ASN1Object
+    implements ASN1Choice
+{
+    ASN1Primitive time;
+
+    public static Time getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    /**
+     * @deprecated use getInstance()
+     */
+    public Time(
+        ASN1Primitive   time)
+    {
+        if (!(time instanceof ASN1UTCTime)
+            && !(time instanceof ASN1GeneralizedTime))
+        {
+            throw new IllegalArgumentException("unknown object passed to Time");
+        }
+
+        this.time = time; 
+    }
+
+    /**
+     * Creates a time object from a given date - if the date is between 1950
+     * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime
+     * is used.
+     *
+     * @param time a date object representing the time of interest.
+     */
+    public Time(
+        Date    time)
+    {
+        SimpleTimeZone      tz = new SimpleTimeZone(0, "Z");
+        // Android-changed: Use localized version
+        // SimpleDateFormat    dateF = new SimpleDateFormat("yyyyMMddHHmmss");
+        SimpleDateFormat    dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
+
+        dateF.setTimeZone(tz);
+
+        String  d = dateF.format(time) + "Z";
+        int     year = Integer.parseInt(d.substring(0, 4));
+
+        if (year < 1950 || year > 2049)
+        {
+            this.time = new DERGeneralizedTime(d);
+        }
+        else
+        {
+            this.time = new DERUTCTime(d.substring(2));
+        }
+    }
+
+    /**
+     * Creates a time object from a given date and locale - if the date is between 1950
+     * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime
+     * is used. You may need to use this constructor if the default locale
+     * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations.
+     *
+     * @param time a date object representing the time of interest.
+     * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value.
+     */
+    public Time(
+        Date    time,
+        Locale locale)
+    {
+        SimpleTimeZone      tz = new SimpleTimeZone(0, "Z");
+        // BEGIN Android-changed: Use localized version
+        // SimpleDateFormat    dateF = new SimpleDateFormat("yyyyMMddHHmmss", locale);
+        SimpleDateFormat    dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
+        dateF.setCalendar(Calendar.getInstance(locale));
+        // END Android-changed: Use localized version
+
+        dateF.setTimeZone(tz);
+
+        String  d = dateF.format(time) + "Z";
+        int     year = Integer.parseInt(d.substring(0, 4));
+
+        if (year < 1950 || year > 2049)
+        {
+            this.time = new DERGeneralizedTime(d);
+        }
+        else
+        {
+            this.time = new DERUTCTime(d.substring(2));
+        }
+    }
+
+    /**
+     * Return a Time object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link Time} object
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.DERUTCTime DERUTCTime} object
+     * <li> {@link com.android.internal.org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime} object
+     * </ul>
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static Time getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof Time)
+        {
+            return (Time)obj;
+        }
+        else if (obj instanceof ASN1UTCTime)
+        {
+            return new Time((ASN1UTCTime)obj);
+        }
+        else if (obj instanceof ASN1GeneralizedTime)
+        {
+            return new Time((ASN1GeneralizedTime)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+    }
+
+    /**
+     * Get the date+tine as a String in full form century format.
+     */
+    public String getTime()
+    {
+        if (time instanceof ASN1UTCTime)
+        {
+            return ((ASN1UTCTime)time).getAdjustedTime();
+        }
+        else
+        {
+            return ((ASN1GeneralizedTime)time).getTime();
+        }
+    }
+
+    /**
+     * Get java.util.Date version of date+time.
+     */
+    public Date getDate()
+    {
+        try
+        {
+            if (time instanceof ASN1UTCTime)
+            {
+                return ((ASN1UTCTime)time).getAdjustedDate();
+            }
+            else
+            {
+                return ((ASN1GeneralizedTime)time).getDate();
+            }
+        }
+        catch (ParseException e)
+        {         // this should never happen
+            throw new IllegalStateException("invalid date string: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return time;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java
new file mode 100644
index 0000000..33a4195
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java
@@ -0,0 +1,112 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.eac;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * German Federal Office for Information Security
+ * (Bundesamt f&uuml;r Sicherheit in der Informationstechnik)
+ * <a href="http://www.bsi.bund.de/">http://www.bsi.bund.de/</a>
+ * <p>
+ * <a href="https://www.bsi.bund.de/EN/Publications/TechnicalGuidelines/TR03110/BSITR03110.html">BSI TR-03110</a>
+ * Technical Guideline Advanced Security Mechanisms for Machine Readable Travel Documents
+ * <p>
+ * <a href="https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TR03110/TR-03110_v2.1_P3pdf.pdf">
+ * Technical Guideline TR-03110-3</a>
+ * Advanced Security Mechanisms for Machine Readable Travel Documents;
+ * Part 3: Common Specifications.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface EACObjectIdentifiers
+{
+    /**
+     * <pre>
+     * bsi-de OBJECT IDENTIFIER ::= {
+     *     itu-t(0) identified-organization(4) etsi(0)
+     *     reserved(127) etsi-identified-organization(0) 7
+     * }
+     * </pre>
+     * OID: 0.4.0.127.0.7
+     */
+    static final ASN1ObjectIdentifier    bsi_de      = new ASN1ObjectIdentifier("0.4.0.127.0.7");
+
+    /**
+     * <pre>
+     * id-PK OBJECT IDENTIFIER ::= {
+     *     bsi-de protocols(2) smartcard(2) 1
+     * }
+     * </pre>
+     * OID: 0.4.0.127.0.7.2.2.1
+     */
+    static final ASN1ObjectIdentifier    id_PK      = bsi_de.branch("2.2.1");
+
+    /** OID: 0.4.0.127.0.7.2.2.1.1 */
+    static final ASN1ObjectIdentifier    id_PK_DH   = id_PK.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.1.2 */
+    static final ASN1ObjectIdentifier    id_PK_ECDH = id_PK.branch("2");
+
+    /**
+     * <pre>
+     * id-CA OBJECT IDENTIFIER ::= {
+     *     bsi-de protocols(2) smartcard(2) 3
+     * }
+     * </pre>
+     * OID: 0.4.0.127.0.7.2.2.3
+     */
+    static final ASN1ObjectIdentifier    id_CA                   = bsi_de.branch("2.2.3");
+    /** OID: 0.4.0.127.0.7.2.2.3.1 */
+    static final ASN1ObjectIdentifier    id_CA_DH                = id_CA.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.3.1.1 */
+    static final ASN1ObjectIdentifier    id_CA_DH_3DES_CBC_CBC   = id_CA_DH.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.3.2 */
+    static final ASN1ObjectIdentifier    id_CA_ECDH              = id_CA.branch("2");
+    /** OID: 0.4.0.127.0.7.2.2.3.2.1 */
+    static final ASN1ObjectIdentifier    id_CA_ECDH_3DES_CBC_CBC = id_CA_ECDH.branch("1");
+
+    /**
+     * <pre>
+     * id-TA OBJECT IDENTIFIER ::= {
+     *     bsi-de protocols(2) smartcard(2) 2
+     * }
+     * </pre>
+     * OID: 0.4.0.127.0.7.2.2.2
+     */
+    static final ASN1ObjectIdentifier    id_TA = bsi_de.branch("2.2.2");
+
+    /** OID: 0.4.0.127.0.7.2.2.2.1 */
+    static final ASN1ObjectIdentifier    id_TA_RSA              = id_TA.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.1 */
+    static final ASN1ObjectIdentifier    id_TA_RSA_v1_5_SHA_1   = id_TA_RSA.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.2 */
+    static final ASN1ObjectIdentifier    id_TA_RSA_v1_5_SHA_256 = id_TA_RSA.branch("2");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.3 */
+    static final ASN1ObjectIdentifier    id_TA_RSA_PSS_SHA_1    = id_TA_RSA.branch("3");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.4 */
+    static final ASN1ObjectIdentifier    id_TA_RSA_PSS_SHA_256  = id_TA_RSA.branch("4");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.5 */
+    static final ASN1ObjectIdentifier    id_TA_RSA_v1_5_SHA_512 = id_TA_RSA.branch("5");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.6 */
+    static final ASN1ObjectIdentifier    id_TA_RSA_PSS_SHA_512  = id_TA_RSA.branch("6");
+    /** OID: 0.4.0.127.0.7.2.2.2.2 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA            = id_TA.branch("2");
+    /** OID: 0.4.0.127.0.7.2.2.2.2.1 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_1      = id_TA_ECDSA.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.2.2.2 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_224    = id_TA_ECDSA.branch("2");
+    /** OID: 0.4.0.127.0.7.2.2.2.2.3 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_256    = id_TA_ECDSA.branch("3");
+    /** OID: 0.4.0.127.0.7.2.2.2.2.4 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_384    = id_TA_ECDSA.branch("4");
+    /** OID: 0.4.0.127.0.7.2.2.2.2.5 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_512    = id_TA_ECDSA.branch("5");
+
+    /**
+     * <pre>
+     * id-EAC-ePassport OBJECT IDENTIFIER ::= {
+     *     bsi-de applications(3) mrtd(1) roles(2) 1
+     * }
+     * </pre>
+     * OID: 0.4.0.127.0.7.3.1.2.1
+     */
+    static final ASN1ObjectIdentifier id_EAC_ePassport = bsi_de.branch("3.1.2.1");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/gm/GMObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/gm/GMObjectIdentifiers.java
new file mode 100644
index 0000000..52ed008
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/gm/GMObjectIdentifiers.java
@@ -0,0 +1,88 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.gm;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface GMObjectIdentifiers
+{
+    ASN1ObjectIdentifier sm_scheme = new ASN1ObjectIdentifier("1.2.156.10197.1");
+
+    ASN1ObjectIdentifier sm6_ecb = sm_scheme.branch("101.1");
+    ASN1ObjectIdentifier sm6_cbc = sm_scheme.branch("101.2");
+    ASN1ObjectIdentifier sm6_ofb128 = sm_scheme.branch("101.3");
+    ASN1ObjectIdentifier sm6_cfb128 = sm_scheme.branch("101.4");
+
+    ASN1ObjectIdentifier sm1_ecb = sm_scheme.branch("102.1");
+    ASN1ObjectIdentifier sm1_cbc = sm_scheme.branch("102.2");
+    ASN1ObjectIdentifier sm1_ofb128 = sm_scheme.branch("102.3");
+    ASN1ObjectIdentifier sm1_cfb128 = sm_scheme.branch("102.4");
+    ASN1ObjectIdentifier sm1_cfb1 = sm_scheme.branch("102.5");
+    ASN1ObjectIdentifier sm1_cfb8 = sm_scheme.branch("102.6");
+
+    ASN1ObjectIdentifier ssf33_ecb = sm_scheme.branch("103.1");
+    ASN1ObjectIdentifier ssf33_cbc = sm_scheme.branch("103.2");
+    ASN1ObjectIdentifier ssf33_ofb128 = sm_scheme.branch("103.3");
+    ASN1ObjectIdentifier ssf33_cfb128 = sm_scheme.branch("103.4");
+    ASN1ObjectIdentifier ssf33_cfb1 = sm_scheme.branch("103.5");
+    ASN1ObjectIdentifier ssf33_cfb8 = sm_scheme.branch("103.6");
+
+    ASN1ObjectIdentifier sms4_ecb = sm_scheme.branch("104.1");
+    ASN1ObjectIdentifier sms4_cbc = sm_scheme.branch("104.2");
+    ASN1ObjectIdentifier sms4_ofb128 = sm_scheme.branch("104.3");
+    ASN1ObjectIdentifier sms4_cfb128 = sm_scheme.branch("104.4");
+    ASN1ObjectIdentifier sms4_cfb1 = sm_scheme.branch("104.5");
+    ASN1ObjectIdentifier sms4_cfb8 = sm_scheme.branch("104.6");
+    ASN1ObjectIdentifier sms4_ctr = sm_scheme.branch("104.7");
+    ASN1ObjectIdentifier sms4_gcm = sm_scheme.branch("104.8");
+    ASN1ObjectIdentifier sms4_ccm = sm_scheme.branch("104.9");
+    ASN1ObjectIdentifier sms4_xts = sm_scheme.branch("104.10");
+    ASN1ObjectIdentifier sms4_wrap = sm_scheme.branch("104.11");
+    ASN1ObjectIdentifier sms4_wrap_pad = sm_scheme.branch("104.12");
+    ASN1ObjectIdentifier sms4_ocb = sm_scheme.branch("104.100");
+
+    ASN1ObjectIdentifier sm5 = sm_scheme.branch("201");
+
+    ASN1ObjectIdentifier sm2p256v1 = sm_scheme.branch("301");
+    ASN1ObjectIdentifier sm2sign = sm_scheme.branch("301.1");
+    ASN1ObjectIdentifier sm2exchange = sm_scheme.branch("301.2");
+    ASN1ObjectIdentifier sm2encrypt = sm_scheme.branch("301.3");
+
+    ASN1ObjectIdentifier wapip192v1 = sm_scheme.branch("301.101");
+
+    ASN1ObjectIdentifier sm2encrypt_recommendedParameters = sm2encrypt.branch("1");
+    ASN1ObjectIdentifier sm2encrypt_specifiedParameters = sm2encrypt.branch("2");
+    ASN1ObjectIdentifier sm2encrypt_with_sm3 = sm2encrypt.branch("2.1");
+    ASN1ObjectIdentifier sm2encrypt_with_sha1 = sm2encrypt.branch("2.2");
+    ASN1ObjectIdentifier sm2encrypt_with_sha224 = sm2encrypt.branch("2.3");
+    ASN1ObjectIdentifier sm2encrypt_with_sha256 = sm2encrypt.branch("2.4");
+    ASN1ObjectIdentifier sm2encrypt_with_sha384 = sm2encrypt.branch("2.5");
+    ASN1ObjectIdentifier sm2encrypt_with_sha512 = sm2encrypt.branch("2.6");
+    ASN1ObjectIdentifier sm2encrypt_with_rmd160 =  sm2encrypt.branch("2.7");
+    ASN1ObjectIdentifier sm2encrypt_with_whirlpool =sm2encrypt.branch("2.8");
+    ASN1ObjectIdentifier sm2encrypt_with_blake2b512 = sm2encrypt.branch("2.9");
+    ASN1ObjectIdentifier sm2encrypt_with_blake2s256 = sm2encrypt.branch("2.10");
+    ASN1ObjectIdentifier sm2encrypt_with_md5 = sm2encrypt.branch("2.11");
+
+    ASN1ObjectIdentifier id_sm9PublicKey = sm_scheme.branch("302");
+    ASN1ObjectIdentifier sm9sign = sm_scheme.branch("302.1");
+    ASN1ObjectIdentifier sm9keyagreement = sm_scheme.branch("302.2");
+    ASN1ObjectIdentifier sm9encrypt = sm_scheme.branch("302.3");
+
+    ASN1ObjectIdentifier sm3 = sm_scheme.branch("401");
+
+    ASN1ObjectIdentifier hmac_sm3 = sm3.branch("2");
+
+    ASN1ObjectIdentifier sm2sign_with_sm3 = sm_scheme.branch("501");
+    ASN1ObjectIdentifier sm2sign_with_sha1 = sm_scheme.branch("502");
+    ASN1ObjectIdentifier sm2sign_with_sha256 = sm_scheme.branch("503");
+    ASN1ObjectIdentifier sm2sign_with_sha512 = sm_scheme.branch("504");
+    ASN1ObjectIdentifier sm2sign_with_sha224 = sm_scheme.branch("505");
+    ASN1ObjectIdentifier sm2sign_with_sha384 = sm_scheme.branch("506");
+    ASN1ObjectIdentifier sm2sign_with_rmd160 = sm_scheme.branch("507");
+    ASN1ObjectIdentifier sm2sign_with_whirlpool = sm_scheme.branch("520");
+    ASN1ObjectIdentifier sm2sign_with_blake2b512 = sm_scheme.branch("521");
+    ASN1ObjectIdentifier sm2sign_with_blake2s256 = sm_scheme.branch("522");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
new file mode 100644
index 0000000..13d7b2d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
@@ -0,0 +1,62 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.iana;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * IANA:
+ *  { iso(1) identifier-organization(3) dod(6) internet(1) } == IETF defined things
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface IANAObjectIdentifiers
+{
+
+    /** { iso(1) identifier-organization(3) dod(6) internet(1) } == IETF defined things */
+    static final ASN1ObjectIdentifier   internet       = new ASN1ObjectIdentifier("1.3.6.1");
+    /** 1.3.6.1.1: Internet directory: X.500 */
+    static final ASN1ObjectIdentifier   directory      = internet.branch("1");
+    /** 1.3.6.1.2: Internet management */
+    static final ASN1ObjectIdentifier   mgmt           = internet.branch("2");
+    /** 1.3.6.1.3: */
+    static final ASN1ObjectIdentifier   experimental   = internet.branch("3");
+    /** 1.3.6.1.4: */
+    static final ASN1ObjectIdentifier   _private       = internet.branch("4");
+    /** 1.3.6.1.5: Security services */
+    static final ASN1ObjectIdentifier   security       = internet.branch("5");
+    /** 1.3.6.1.6: SNMPv2 -- never really used */
+    static final ASN1ObjectIdentifier   SNMPv2         = internet.branch("6");
+    /** 1.3.6.1.7: mail -- never really used */
+    static final ASN1ObjectIdentifier   mail           = internet.branch("7");
+
+
+    // id-SHA1 OBJECT IDENTIFIER ::=    
+    // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)}
+    //
+
+
+    /** IANA security mechanisms; 1.3.6.1.5.5 */
+    static final ASN1ObjectIdentifier    security_mechanisms  = security.branch("5");
+    /** IANA security nametypes;  1.3.6.1.5.6 */
+    static final ASN1ObjectIdentifier    security_nametypes   = security.branch("6");
+
+    /** PKIX base OID:            1.3.6.1.5.6.6 */
+    static final ASN1ObjectIdentifier    pkix                 = security_mechanisms.branch("6");
+
+
+    /** IPSEC base OID:                        1.3.6.1.5.5.8 */
+    static final ASN1ObjectIdentifier    ipsec                = security_mechanisms.branch("8");
+    /** IPSEC ISAKMP-Oakley OID:               1.3.6.1.5.5.8.1 */
+    static final ASN1ObjectIdentifier    isakmpOakley         = ipsec.branch("1");
+
+    /** IPSEC ISAKMP-Oakley hmacMD5 OID:       1.3.6.1.5.5.8.1.1 */
+    static final ASN1ObjectIdentifier    hmacMD5              = isakmpOakley.branch("1");
+    /** IPSEC ISAKMP-Oakley hmacSHA1 OID:      1.3.6.1.5.5.8.1.2 */
+    static final ASN1ObjectIdentifier    hmacSHA1             = isakmpOakley.branch("2");
+    
+    /** IPSEC ISAKMP-Oakley hmacTIGER OID:     1.3.6.1.5.5.8.1.3 */
+    static final ASN1ObjectIdentifier    hmacTIGER            = isakmpOakley.branch("3");
+    
+    /** IPSEC ISAKMP-Oakley hmacRIPEMD160 OID: 1.3.6.1.5.5.8.1.4 */
+    static final ASN1ObjectIdentifier    hmacRIPEMD160        = isakmpOakley.branch("4");
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java
new file mode 100644
index 0000000..9bfcbfc
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java
@@ -0,0 +1,212 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.isismtt;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * ISISMT -- Industrial Signature Interoperability Specification
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ISISMTTObjectIdentifiers
+{
+
+    /** 1.3.36.8 */
+    static final ASN1ObjectIdentifier id_isismtt = new ASN1ObjectIdentifier("1.3.36.8");
+
+    /** 1.3.36.8.1 */
+    static final ASN1ObjectIdentifier id_isismtt_cp = id_isismtt.branch("1");
+
+    /**
+     * The id-isismtt-cp-accredited OID indicates that the certificate is a
+     * qualified certificate according to Directive 1999/93/EC of the European
+     * Parliament and of the Council of 13 December 1999 on a Community
+     * Framework for Electronic Signatures, which additionally conforms the
+     * special requirements of the SigG and has been issued by an accredited CA.
+     * <p>
+     * 1.3.36.8.1.1
+     */
+
+    static final ASN1ObjectIdentifier id_isismtt_cp_accredited = id_isismtt_cp.branch("1");
+
+    /** 1.3.36.8.3 */
+    static final ASN1ObjectIdentifier id_isismtt_at = id_isismtt.branch("3");
+
+    /**
+     * Certificate extensionDate of certificate generation
+     * <pre>
+     *     DateOfCertGenSyntax ::= GeneralizedTime
+     * </pre>
+     * OID: 1.3.36.8.3.1
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_dateOfCertGen = id_isismtt_at.branch("1");
+
+    /**
+     * Attribute to indicate that the certificate holder may sign in the name of
+     * a third person. May also be used as extension in a certificate.
+     * <p>
+     * OID: 1.3.36.8.3.2
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_procuration = id_isismtt_at.branch("2");
+
+    /**
+     * Attribute to indicate admissions to certain professions. May be used as
+     * attribute in attribute certificate or as extension in a certificate
+     * <p>
+     * OID: 1.3.36.8.3.3
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_admission = id_isismtt_at.branch("3");
+
+    /**
+     * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST
+     * be used in new certificates in place of the extension/attribute
+     * MonetaryLimit since January 1, 2004. For the sake of backward
+     * compatibility with certificates already in use, SigG conforming
+     * components MUST support MonetaryLimit (as well as QcEuLimitValue).
+     * <p>
+     * OID: 1.3.36.8.3.4
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_monetaryLimit = id_isismtt_at.branch("4");
+
+    /**
+     * A declaration of majority. May be used as attribute in attribute
+     * certificate or as extension in a certificate
+     * <p>
+     * OID: 1.3.36.8.3.5
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_declarationOfMajority = id_isismtt_at.branch("5");
+
+    /**
+     * Serial number of the smart card containing the corresponding private key
+     * <pre>
+     *    ICCSNSyntax ::= OCTET STRING (SIZE(8..20))
+     * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.6
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_iCCSN = id_isismtt_at.branch("6");
+
+    /**
+     * Reference for a file of a smartcard that stores the public key of this
+     * certificate and that is used as "security anchor".
+     * <pre>
+     *    PKReferenceSyntax ::= OCTET STRING (SIZE(20))
+     * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.7
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_PKReference = id_isismtt_at.branch("7");
+
+    /**
+     * Some other restriction regarding the usage of this certificate. May be
+     * used as attribute in attribute certificate or as extension in a
+     * certificate.
+     * <pre>
+     *    RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+     * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.8
+     * 
+     * @see com.android.internal.org.bouncycastle.asn1.isismtt.x509.Restriction
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_restriction = id_isismtt_at.branch("8");
+
+    /**
+     * (Single)Request extension: Clients may include this extension in a
+     * (single) Request to request the responder to send the certificate in the
+     * response message along with the status information. Besides the LDAP
+     * service, this extension provides another mechanism for the distribution
+     * of certificates, which MAY optionally be provided by certificate
+     * repositories.
+     * <pre>
+     *    RetrieveIfAllowed ::= BOOLEAN
+     * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.9
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_retrieveIfAllowed = id_isismtt_at.branch("9");
+
+    /**
+     * SingleOCSPResponse extension: The certificate requested by the client by
+     * inserting the RetrieveIfAllowed extension in the request, will be
+     * returned in this extension.
+     * <p>
+     * OID: 1.3.36.8.3.10
+     * 
+     * @see com.android.internal.org.bouncycastle.asn1.isismtt.ocsp.RequestedCertificate
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_requestedCertificate = id_isismtt_at.branch("10");
+
+    /**
+     * Base ObjectIdentifier for naming authorities
+     * <p>
+     * OID: 1.3.36.8.3.11
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_namingAuthorities = id_isismtt_at.branch("11");
+
+    /**
+     * SingleOCSPResponse extension: Date, when certificate has been published
+     * in the directory and status information has become available. Currently,
+     * accrediting authorities enforce that SigG-conforming OCSP servers include
+     * this extension in the responses.
+     * 
+     * <pre>
+     *    CertInDirSince ::= GeneralizedTime
+     * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.12
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_certInDirSince = id_isismtt_at.branch("12");
+
+    /**
+     * Hash of a certificate in OCSP.
+     * <p>
+     * OID: 1.3.36.8.3.13
+     * 
+     * @see com.android.internal.org.bouncycastle.asn1.isismtt.ocsp.CertHash
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_certHash = id_isismtt_at.branch("13");
+
+    /**
+     * <pre>
+     *    NameAtBirth ::= DirectoryString(SIZE(1..64)
+     * </pre>
+     * 
+     * Used in
+     * {@link com.android.internal.org.bouncycastle.asn1.x509.SubjectDirectoryAttributes SubjectDirectoryAttributes}
+     * <p>
+     * OID: 1.3.36.8.3.14
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_nameAtBirth = id_isismtt_at.branch("14");
+
+    /**
+     * Some other information of non-restrictive nature regarding the usage of
+     * this certificate. May be used as attribute in atribute certificate or as
+     * extension in a certificate.
+     * 
+     * <pre>
+     *    AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+     * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.15
+     * 
+     * @see com.android.internal.org.bouncycastle.asn1.isismtt.x509.AdditionalInformationSyntax
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_additionalInformation = id_isismtt_at.branch("15");
+
+    /**
+     * Indicates that an attribute certificate exists, which limits the
+     * usability of this public key certificate. Whenever verifying a signature
+     * with the help of this certificate, the content of the corresponding
+     * attribute certificate should be concerned. This extension MUST be
+     * included in a PKC, if a corresponding attribute certificate (having the
+     * PKC as base certificate) contains some attribute that restricts the
+     * usability of the PKC too. Attribute certificates with restricting content
+     * MUST always be included in the signed document.
+     * <pre>
+     *    LiabilityLimitationFlagSyntax ::= BOOLEAN
+     * </pre>
+     * <p>
+     * OID: 0.2.262.1.10.12.0
+     */
+    static final ASN1ObjectIdentifier id_isismtt_at_liabilityLimitationFlag = new ASN1ObjectIdentifier("0.2.262.1.10.12.0");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java
new file mode 100644
index 0000000..370a225
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java
@@ -0,0 +1,33 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.kisa;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * Korea Information Security Agency (KISA)
+ * ({iso(1) member-body(2) kr(410) kisa(200004)})
+ * <p>
+ * See <a href="http://tools.ietf.org/html/rfc4010">RFC 4010</a>
+ * Use of the SEED Encryption Algorithm
+ * in Cryptographic Message Syntax (CMS),
+ * and <a href="http://tools.ietf.org/html/rfc4269">RFC 4269</a>
+ * The SEED Encryption Algorithm
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface KISAObjectIdentifiers
+{
+    /** RFC 4010, 4269: id-seedCBC; OID 1.2.410.200004.1.4 */
+    static final ASN1ObjectIdentifier id_seedCBC = new ASN1ObjectIdentifier("1.2.410.200004.1.4");
+
+    /** RFC 4269: id-seedMAC; OID 1.2.410.200004.1.7 */
+    static final ASN1ObjectIdentifier id_seedMAC = new ASN1ObjectIdentifier("1.2.410.200004.1.7");
+
+    /** RFC 4269: pbeWithSHA1AndSEED-CBC; OID 1.2.410.200004.1.15 */
+    static final ASN1ObjectIdentifier pbeWithSHA1AndSEED_CBC = new ASN1ObjectIdentifier("1.2.410.200004.1.15");
+
+    /** RFC 4010: id-npki-app-cmsSeed-wrap; OID 1.2.410.200004.7.1.1.1 */
+    static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier("1.2.410.200004.7.1.1.1");
+
+    /** RFC 4010: SeedEncryptionAlgorithmInCMS; OID 1.2.840.113549.1.9.16.0.24 */
+    static final ASN1ObjectIdentifier id_mod_cms_seed = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.0.24");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
new file mode 100644
index 0000000..18c020c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
@@ -0,0 +1,142 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.misc;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface MiscObjectIdentifiers
+{
+    //
+    // Netscape
+    //       iso/itu(2) joint-assign(16) us(840) uscompany(1) netscape(113730) cert-extensions(1) }
+    //
+    /**
+     * Netscape cert extensions OID base: 2.16.840.1.113730.1
+     */
+    ASN1ObjectIdentifier netscape = new ASN1ObjectIdentifier("2.16.840.1.113730.1");
+    /**
+     * Netscape cert CertType OID: 2.16.840.1.113730.1.1
+     */
+    ASN1ObjectIdentifier netscapeCertType = netscape.branch("1");
+    /**
+     * Netscape cert BaseURL OID: 2.16.840.1.113730.1.2
+     */
+    ASN1ObjectIdentifier netscapeBaseURL = netscape.branch("2");
+    /**
+     * Netscape cert RevocationURL OID: 2.16.840.1.113730.1.3
+     */
+    ASN1ObjectIdentifier netscapeRevocationURL = netscape.branch("3");
+    /**
+     * Netscape cert CARevocationURL OID: 2.16.840.1.113730.1.4
+     */
+    ASN1ObjectIdentifier netscapeCARevocationURL = netscape.branch("4");
+    /**
+     * Netscape cert RenewalURL OID: 2.16.840.1.113730.1.7
+     */
+    ASN1ObjectIdentifier netscapeRenewalURL = netscape.branch("7");
+    /**
+     * Netscape cert CApolicyURL OID: 2.16.840.1.113730.1.8
+     */
+    ASN1ObjectIdentifier netscapeCApolicyURL = netscape.branch("8");
+    /**
+     * Netscape cert SSLServerName OID: 2.16.840.1.113730.1.12
+     */
+    ASN1ObjectIdentifier netscapeSSLServerName = netscape.branch("12");
+    /**
+     * Netscape cert CertComment OID: 2.16.840.1.113730.1.13
+     */
+    ASN1ObjectIdentifier netscapeCertComment = netscape.branch("13");
+
+    //
+    // Verisign
+    //       iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) }
+    //
+    /**
+     * Verisign OID base: 2.16.840.1.113733.1
+     */
+    ASN1ObjectIdentifier verisign = new ASN1ObjectIdentifier("2.16.840.1.113733.1");
+
+    /**
+     * Verisign CZAG (Country,Zip,Age,Gender) Extension OID: 2.16.840.1.113733.1.6.3
+     */
+    ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3");
+
+    ASN1ObjectIdentifier verisignPrivate_6_9 = verisign.branch("6.9");
+    ASN1ObjectIdentifier verisignOnSiteJurisdictionHash = verisign.branch("6.11");
+    ASN1ObjectIdentifier verisignBitString_6_13 = verisign.branch("6.13");
+
+    /**
+     * Verisign D&amp;B D-U-N-S number Extension OID: 2.16.840.1.113733.1.6.15
+     */
+    ASN1ObjectIdentifier verisignDnbDunsNumber = verisign.branch("6.15");
+
+    ASN1ObjectIdentifier verisignIssStrongCrypto = verisign.branch("8.1");
+
+    //
+    // Novell
+    //       iso/itu(2) country(16) us(840) organization(1) novell(113719)
+    //
+    /**
+     * Novell OID base: 2.16.840.1.113719
+     */
+    ASN1ObjectIdentifier novell = new ASN1ObjectIdentifier("2.16.840.1.113719");
+    /**
+     * Novell SecurityAttribs OID: 2.16.840.1.113719.1.9.4.1
+     */
+    ASN1ObjectIdentifier novellSecurityAttribs = novell.branch("1.9.4.1");
+
+    //
+    // Entrust
+    //       iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7)
+    //
+    /**
+     * NortelNetworks Entrust OID base: 1.2.840.113533.7
+     */
+    ASN1ObjectIdentifier entrust = new ASN1ObjectIdentifier("1.2.840.113533.7");
+    /**
+     * NortelNetworks Entrust VersionExtension OID: 1.2.840.113533.7.65.0
+     */
+    ASN1ObjectIdentifier entrustVersionExtension = entrust.branch("65.0");
+
+    /**
+     * cast5CBC OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) nt(113533) nsn(7) algorithms(66) 10} SEE RFC 2984
+     */
+    ASN1ObjectIdentifier cast5CBC = entrust.branch("66.10");
+
+    //
+    // Ascom
+    //
+    ASN1ObjectIdentifier as_sys_sec_alg_ideaCBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2");
+
+    //
+    // Peter Gutmann's Cryptlib
+    //
+    ASN1ObjectIdentifier cryptlib = new ASN1ObjectIdentifier("1.3.6.1.4.1.3029");
+
+    ASN1ObjectIdentifier cryptlib_algorithm = cryptlib.branch("1");
+    ASN1ObjectIdentifier cryptlib_algorithm_blowfish_ECB = cryptlib_algorithm.branch("1.1");
+    ASN1ObjectIdentifier cryptlib_algorithm_blowfish_CBC = cryptlib_algorithm.branch("1.2");
+    ASN1ObjectIdentifier cryptlib_algorithm_blowfish_CFB = cryptlib_algorithm.branch("1.3");
+    ASN1ObjectIdentifier cryptlib_algorithm_blowfish_OFB = cryptlib_algorithm.branch("1.4");
+
+    //
+    // Blake2b
+    //
+    ASN1ObjectIdentifier blake2 = new ASN1ObjectIdentifier("1.3.6.1.4.1.1722.12.2");
+
+    ASN1ObjectIdentifier id_blake2b160 = blake2.branch("1.5");
+    ASN1ObjectIdentifier id_blake2b256 = blake2.branch("1.8");
+    ASN1ObjectIdentifier id_blake2b384 = blake2.branch("1.12");
+    ASN1ObjectIdentifier id_blake2b512 = blake2.branch("1.16");
+
+    ASN1ObjectIdentifier id_blake2s128 = blake2.branch("2.4");
+    ASN1ObjectIdentifier id_blake2s160 = blake2.branch("2.5");
+    ASN1ObjectIdentifier id_blake2s224 = blake2.branch("2.7");
+    ASN1ObjectIdentifier id_blake2s256 = blake2.branch("2.8");
+
+    //
+    // Scrypt
+    ASN1ObjectIdentifier id_scrypt = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.4.11");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/NetscapeCertType.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/NetscapeCertType.java
new file mode 100644
index 0000000..2fdac51
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/NetscapeCertType.java
@@ -0,0 +1,56 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.misc;
+
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+
+/**
+ * The NetscapeCertType object.
+ * <pre>
+ *    NetscapeCertType ::= BIT STRING {
+ *         SSLClient               (0),
+ *         SSLServer               (1),
+ *         S/MIME                  (2),
+ *         Object Signing          (3),
+ *         Reserved                (4),
+ *         SSL CA                  (5),
+ *         S/MIME CA               (6),
+ *         Object Signing CA       (7) }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class NetscapeCertType
+    extends DERBitString
+{
+    public static final int        sslClient        = (1 << 7); 
+    public static final int        sslServer        = (1 << 6);
+    public static final int        smime            = (1 << 5);
+    public static final int        objectSigning    = (1 << 4);
+    public static final int        reserved         = (1 << 3);
+    public static final int        sslCA            = (1 << 2);
+    public static final int        smimeCA          = (1 << 1);
+    public static final int        objectSigningCA  = (1 << 0);
+
+    /**
+     * Basic constructor.
+     * 
+     * @param usage - the bitwise OR of the Key Usage flags giving the
+     * allowed uses for the key.
+     * e.g. (X509NetscapeCertType.sslCA | X509NetscapeCertType.smimeCA)
+     */
+    public NetscapeCertType(
+        int usage)
+    {
+        super(getBytes(usage), getPadBits(usage));
+    }
+
+    public NetscapeCertType(
+        DERBitString usage)
+    {
+        super(usage.getBytes(), usage.getPadBits());
+    }
+
+    public String toString()
+    {
+        return "NetscapeCertType: 0x" + Integer.toHexString(data[0] & 0xff);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
new file mode 100644
index 0000000..ed0f5e2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
@@ -0,0 +1,22 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.misc;
+
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class NetscapeRevocationURL
+    extends DERIA5String
+{
+    public NetscapeRevocationURL(
+        DERIA5String str)
+    {
+        super(str.getString());
+    }
+
+    public String toString()
+    {
+        return "NetscapeRevocationURL: " + this.getString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/VerisignCzagExtension.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
new file mode 100644
index 0000000..a570d70
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
@@ -0,0 +1,22 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.misc;
+
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class VerisignCzagExtension
+    extends DERIA5String
+{
+    public VerisignCzagExtension(
+        DERIA5String str)
+    {
+        super(str.getString());
+    }
+
+    public String toString()
+    {
+        return "VerisignCzagExtension: " + this.getString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/nist/NISTNamedCurves.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/nist/NISTNamedCurves.java
new file mode 100644
index 0000000..fe9c18b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/nist/NISTNamedCurves.java
@@ -0,0 +1,101 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.nist;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.sec.SECNamedCurves;
+import com.android.internal.org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-3
+ * @hide This class is not part of the Android public SDK API
+ */
+public class NISTNamedCurves
+{
+    static final Hashtable objIds = new Hashtable();
+    static final Hashtable names = new Hashtable();
+
+    static void defineCurve(String name, ASN1ObjectIdentifier oid)
+    {
+        objIds.put(name, oid);
+        names.put(oid, name);
+    }
+
+    static
+    {
+        defineCurve("B-571", SECObjectIdentifiers.sect571r1);
+        defineCurve("B-409", SECObjectIdentifiers.sect409r1);
+        defineCurve("B-283", SECObjectIdentifiers.sect283r1);
+        defineCurve("B-233", SECObjectIdentifiers.sect233r1);
+        defineCurve("B-163", SECObjectIdentifiers.sect163r2);
+        defineCurve("K-571", SECObjectIdentifiers.sect571k1);
+        defineCurve("K-409", SECObjectIdentifiers.sect409k1);
+        defineCurve("K-283", SECObjectIdentifiers.sect283k1);
+        defineCurve("K-233", SECObjectIdentifiers.sect233k1);
+        defineCurve("K-163", SECObjectIdentifiers.sect163k1);
+        defineCurve("P-521", SECObjectIdentifiers.secp521r1);
+        defineCurve("P-384", SECObjectIdentifiers.secp384r1);
+        defineCurve("P-256", SECObjectIdentifiers.secp256r1);
+        defineCurve("P-224", SECObjectIdentifiers.secp224r1);
+        defineCurve("P-192", SECObjectIdentifiers.secp192r1);
+    }
+
+    public static X9ECParameters getByName(
+        String  name)
+    {
+        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name));
+
+        if (oid != null)
+        {
+            return getByOID(oid);
+        }
+
+        return null;
+    }
+
+    /**
+     * return the X9ECParameters object for the named curve represented by
+     * the passed in object identifier. Null if the curve isn't present.
+     *
+     * @param oid an object identifier representing a named curve, if present.
+     */
+    public static X9ECParameters getByOID(
+        ASN1ObjectIdentifier  oid)
+    {
+        return SECNamedCurves.getByOID(oid);
+    }
+
+    /**
+     * return the object identifier signified by the passed in name. Null
+     * if there is no object identifier associated with name.
+     *
+     * @return the object identifier associated with name, if present.
+     */
+    public static ASN1ObjectIdentifier getOID(
+        String  name)
+    {
+        return (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name));
+    }
+
+    /**
+     * return the named curve name represented by the given object identifier.
+     */
+    public static String getName(
+        ASN1ObjectIdentifier  oid)
+    {
+        return (String)names.get(oid);
+    }
+
+    /**
+     * returns an enumeration containing the name strings for curves
+     * contained in this structure.
+     */
+    public static Enumeration getNames()
+    {
+        return objIds.keys();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
new file mode 100644
index 0000000..350ff27
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
@@ -0,0 +1,155 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.nist;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ *
+ * NIST:
+ *     iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3) 
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface NISTObjectIdentifiers
+{
+    //
+    // nistalgorithms(4)
+    //
+    /** 2.16.840.1.101.3.4 -- algorithms */
+    static final ASN1ObjectIdentifier    nistAlgorithm           = new ASN1ObjectIdentifier("2.16.840.1.101.3.4");
+
+    /** 2.16.840.1.101.3.4.2 */
+    static final ASN1ObjectIdentifier    hashAlgs                = nistAlgorithm.branch("2");
+
+    /** 2.16.840.1.101.3.4.2.1 */
+    static final ASN1ObjectIdentifier    id_sha256               = hashAlgs.branch("1");
+    /** 2.16.840.1.101.3.4.2.2 */
+    static final ASN1ObjectIdentifier    id_sha384               = hashAlgs.branch("2");
+    /** 2.16.840.1.101.3.4.2.3 */
+    static final ASN1ObjectIdentifier    id_sha512               = hashAlgs.branch("3");
+    /** 2.16.840.1.101.3.4.2.4 */
+    static final ASN1ObjectIdentifier    id_sha224               = hashAlgs.branch("4");
+    /** 2.16.840.1.101.3.4.2.5 */
+    static final ASN1ObjectIdentifier    id_sha512_224           = hashAlgs.branch("5");
+    /** 2.16.840.1.101.3.4.2.6 */
+    static final ASN1ObjectIdentifier    id_sha512_256           = hashAlgs.branch("6");
+
+    /** 2.16.840.1.101.3.4.2.7 */
+    static final ASN1ObjectIdentifier    id_sha3_224 = hashAlgs.branch("7");
+    /** 2.16.840.1.101.3.4.2.8 */
+    static final ASN1ObjectIdentifier    id_sha3_256 = hashAlgs.branch("8");
+    /** 2.16.840.1.101.3.4.2.9 */
+    static final ASN1ObjectIdentifier    id_sha3_384 = hashAlgs.branch("9");
+    /** 2.16.840.1.101.3.4.2.10 */
+    static final ASN1ObjectIdentifier    id_sha3_512 = hashAlgs.branch("10");
+    /** 2.16.840.1.101.3.4.2.11 */
+    static final ASN1ObjectIdentifier    id_shake128 = hashAlgs.branch("11");
+    /** 2.16.840.1.101.3.4.2.12 */
+    static final ASN1ObjectIdentifier    id_shake256 = hashAlgs.branch("12");
+    /** 2.16.840.1.101.3.4.2.13 */
+    static final ASN1ObjectIdentifier    id_hmacWithSHA3_224 = hashAlgs.branch("13");
+    /** 2.16.840.1.101.3.4.2.14 */
+    static final ASN1ObjectIdentifier    id_hmacWithSHA3_256 = hashAlgs.branch("14");
+    /** 2.16.840.1.101.3.4.2.15 */
+    static final ASN1ObjectIdentifier    id_hmacWithSHA3_384 = hashAlgs.branch("15");
+    /** 2.16.840.1.101.3.4.2.16 */
+    static final ASN1ObjectIdentifier    id_hmacWithSHA3_512 = hashAlgs.branch("16");
+
+    /** 2.16.840.1.101.3.4.1 */
+    static final ASN1ObjectIdentifier    aes                     = nistAlgorithm.branch("1");
+    
+    /** 2.16.840.1.101.3.4.1.1 */
+    static final ASN1ObjectIdentifier    id_aes128_ECB           = aes.branch("1"); 
+    /** 2.16.840.1.101.3.4.1.2 */
+    static final ASN1ObjectIdentifier    id_aes128_CBC           = aes.branch("2");
+    /** 2.16.840.1.101.3.4.1.3 */
+    static final ASN1ObjectIdentifier    id_aes128_OFB           = aes.branch("3"); 
+    /** 2.16.840.1.101.3.4.1.4 */
+    static final ASN1ObjectIdentifier    id_aes128_CFB           = aes.branch("4"); 
+    /** 2.16.840.1.101.3.4.1.5 */
+    static final ASN1ObjectIdentifier    id_aes128_wrap          = aes.branch("5");
+    /** 2.16.840.1.101.3.4.1.6 */
+    static final ASN1ObjectIdentifier    id_aes128_GCM           = aes.branch("6");
+    /** 2.16.840.1.101.3.4.1.7 */
+    static final ASN1ObjectIdentifier    id_aes128_CCM           = aes.branch("7");
+    /** 2.16.840.1.101.3.4.1.28 */
+    static final ASN1ObjectIdentifier    id_aes128_wrap_pad      = aes.branch("8");
+
+    /** 2.16.840.1.101.3.4.1.21 */
+    static final ASN1ObjectIdentifier    id_aes192_ECB           = aes.branch("21"); 
+    /** 2.16.840.1.101.3.4.1.22 */
+    static final ASN1ObjectIdentifier    id_aes192_CBC           = aes.branch("22"); 
+    /** 2.16.840.1.101.3.4.1.23 */
+    static final ASN1ObjectIdentifier    id_aes192_OFB           = aes.branch("23"); 
+    /** 2.16.840.1.101.3.4.1.24 */
+    static final ASN1ObjectIdentifier    id_aes192_CFB           = aes.branch("24"); 
+    /** 2.16.840.1.101.3.4.1.25 */
+    static final ASN1ObjectIdentifier    id_aes192_wrap          = aes.branch("25");
+    /** 2.16.840.1.101.3.4.1.26 */
+    static final ASN1ObjectIdentifier    id_aes192_GCM           = aes.branch("26");
+    /** 2.16.840.1.101.3.4.1.27 */
+    static final ASN1ObjectIdentifier    id_aes192_CCM           = aes.branch("27");
+    /** 2.16.840.1.101.3.4.1.28 */
+    static final ASN1ObjectIdentifier    id_aes192_wrap_pad      = aes.branch("28");
+
+    /** 2.16.840.1.101.3.4.1.41 */
+    static final ASN1ObjectIdentifier    id_aes256_ECB           = aes.branch("41"); 
+    /** 2.16.840.1.101.3.4.1.42 */
+    static final ASN1ObjectIdentifier    id_aes256_CBC           = aes.branch("42");
+    /** 2.16.840.1.101.3.4.1.43 */
+    static final ASN1ObjectIdentifier    id_aes256_OFB           = aes.branch("43"); 
+    /** 2.16.840.1.101.3.4.1.44 */
+    static final ASN1ObjectIdentifier    id_aes256_CFB           = aes.branch("44"); 
+    /** 2.16.840.1.101.3.4.1.45 */
+    static final ASN1ObjectIdentifier    id_aes256_wrap          = aes.branch("45"); 
+    /** 2.16.840.1.101.3.4.1.46 */
+    static final ASN1ObjectIdentifier    id_aes256_GCM           = aes.branch("46");
+    /** 2.16.840.1.101.3.4.1.47 */
+    static final ASN1ObjectIdentifier    id_aes256_CCM           = aes.branch("47");
+    /** 2.16.840.1.101.3.4.1.48 */
+    static final ASN1ObjectIdentifier    id_aes256_wrap_pad      = aes.branch("48");
+
+    //
+    // signatures
+    //
+    /** 2.16.840.1.101.3.4.3 */
+    static final ASN1ObjectIdentifier    sigAlgs        = nistAlgorithm.branch("3");
+
+    static final ASN1ObjectIdentifier    id_dsa_with_sha2        = sigAlgs;
+
+    /** 2.16.840.1.101.3.4.3.1 */
+    static final ASN1ObjectIdentifier    dsa_with_sha224         = sigAlgs.branch("1");
+    /** 2.16.840.1.101.3.4.3.2 */
+    static final ASN1ObjectIdentifier    dsa_with_sha256         = sigAlgs.branch("2");
+    /** 2.16.840.1.101.3.4.3.3 */
+    static final ASN1ObjectIdentifier    dsa_with_sha384         = sigAlgs.branch("3");
+    /** 2.16.840.1.101.3.4.3.4 */
+    static final ASN1ObjectIdentifier    dsa_with_sha512         = sigAlgs.branch("4");
+    /** 2.16.840.1.101.3.4.3.5 */
+    static final ASN1ObjectIdentifier    id_dsa_with_sha3_224       = sigAlgs.branch("5");
+    /** 2.16.840.1.101.3.4.3.6 */
+    static final ASN1ObjectIdentifier    id_dsa_with_sha3_256       = sigAlgs.branch("6");
+    /** 2.16.840.1.101.3.4.3.7 */
+    static final ASN1ObjectIdentifier    id_dsa_with_sha3_384       = sigAlgs.branch("7");
+    /** 2.16.840.1.101.3.4.3.8 */
+    static final ASN1ObjectIdentifier    id_dsa_with_sha3_512       = sigAlgs.branch("8");
+
+    // ECDSA with SHA-3
+    /** 2.16.840.1.101.3.4.3.9 */
+    static final ASN1ObjectIdentifier    id_ecdsa_with_sha3_224       = sigAlgs.branch("9");
+    /** 2.16.840.1.101.3.4.3.10 */
+    static final ASN1ObjectIdentifier    id_ecdsa_with_sha3_256       = sigAlgs.branch("10");
+    /** 2.16.840.1.101.3.4.3.11 */
+    static final ASN1ObjectIdentifier    id_ecdsa_with_sha3_384       = sigAlgs.branch("11");
+    /** 2.16.840.1.101.3.4.3.12 */
+    static final ASN1ObjectIdentifier    id_ecdsa_with_sha3_512       = sigAlgs.branch("12");
+
+    // RSA PKCS #1 v1.5 Signature with SHA-3 family.
+    /** 2.16.840.1.101.3.4.3.9 */
+    static final ASN1ObjectIdentifier    id_rsassa_pkcs1_v1_5_with_sha3_224       = sigAlgs.branch("13");
+    /** 2.16.840.1.101.3.4.3.10 */
+    static final ASN1ObjectIdentifier    id_rsassa_pkcs1_v1_5_with_sha3_256       = sigAlgs.branch("14");
+    /** 2.16.840.1.101.3.4.3.11 */
+    static final ASN1ObjectIdentifier    id_rsassa_pkcs1_v1_5_with_sha3_384       = sigAlgs.branch("15");
+    /** 2.16.840.1.101.3.4.3.12 */
+    static final ASN1ObjectIdentifier    id_rsassa_pkcs1_v1_5_with_sha3_512       = sigAlgs.branch("16");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java
new file mode 100644
index 0000000..51ce8f0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java
@@ -0,0 +1,62 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.nsri;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface NSRIObjectIdentifiers
+{
+    ASN1ObjectIdentifier nsri = new ASN1ObjectIdentifier("1.2.410.200046");
+
+    ASN1ObjectIdentifier id_algorithm = nsri.branch("1");
+
+    ASN1ObjectIdentifier id_sea = id_algorithm.branch("1");
+    ASN1ObjectIdentifier id_pad = id_algorithm.branch("2");
+
+    ASN1ObjectIdentifier id_pad_null = id_algorithm.branch("0");
+    ASN1ObjectIdentifier id_pad_1 = id_algorithm.branch("1");
+
+    ASN1ObjectIdentifier id_aria128_ecb = id_sea.branch("1");
+    ASN1ObjectIdentifier id_aria128_cbc = id_sea.branch("2");
+    ASN1ObjectIdentifier id_aria128_cfb = id_sea.branch("3");
+    ASN1ObjectIdentifier id_aria128_ofb = id_sea.branch("4");
+    ASN1ObjectIdentifier id_aria128_ctr = id_sea.branch("5");
+
+    ASN1ObjectIdentifier id_aria192_ecb = id_sea.branch("6");
+    ASN1ObjectIdentifier id_aria192_cbc = id_sea.branch("7");
+    ASN1ObjectIdentifier id_aria192_cfb = id_sea.branch("8");
+    ASN1ObjectIdentifier id_aria192_ofb = id_sea.branch("9");
+    ASN1ObjectIdentifier id_aria192_ctr = id_sea.branch("10");
+
+    ASN1ObjectIdentifier id_aria256_ecb = id_sea.branch("11");
+    ASN1ObjectIdentifier id_aria256_cbc = id_sea.branch("12");
+    ASN1ObjectIdentifier id_aria256_cfb = id_sea.branch("13");
+    ASN1ObjectIdentifier id_aria256_ofb = id_sea.branch("14");
+    ASN1ObjectIdentifier id_aria256_ctr = id_sea.branch("15");
+
+    ASN1ObjectIdentifier id_aria128_cmac = id_sea.branch("21");
+    ASN1ObjectIdentifier id_aria192_cmac = id_sea.branch("22");
+    ASN1ObjectIdentifier id_aria256_cmac = id_sea.branch("23");
+
+    ASN1ObjectIdentifier id_aria128_ocb2 = id_sea.branch("31");
+    ASN1ObjectIdentifier id_aria192_ocb2 = id_sea.branch("32");
+    ASN1ObjectIdentifier id_aria256_ocb2 = id_sea.branch("33");
+
+    ASN1ObjectIdentifier id_aria128_gcm = id_sea.branch("34");
+    ASN1ObjectIdentifier id_aria192_gcm = id_sea.branch("35");
+    ASN1ObjectIdentifier id_aria256_gcm = id_sea.branch("36");
+
+    ASN1ObjectIdentifier id_aria128_ccm = id_sea.branch("37");
+    ASN1ObjectIdentifier id_aria192_ccm = id_sea.branch("38");
+    ASN1ObjectIdentifier id_aria256_ccm = id_sea.branch("39");
+
+    ASN1ObjectIdentifier id_aria128_kw = id_sea.branch("40");
+    ASN1ObjectIdentifier id_aria192_kw = id_sea.branch("41");
+    ASN1ObjectIdentifier id_aria256_kw = id_sea.branch("42");
+
+    ASN1ObjectIdentifier id_aria128_kwp = id_sea.branch("43");
+    ASN1ObjectIdentifier id_aria192_kwp = id_sea.branch("44");
+    ASN1ObjectIdentifier id_aria256_kwp = id_sea.branch("45");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java
new file mode 100644
index 0000000..244048a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java
@@ -0,0 +1,27 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ntt;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * From <a href="http://tools.ietf.org/html/rfc3657">RFC 3657</a>
+ * Use of the Camellia Encryption Algorithm
+ * in Cryptographic Message Syntax (CMS)
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface NTTObjectIdentifiers
+{
+    /** id-camellia128-cbc; OID 1.2.392.200011.61.1.1.1.2 */
+    static final ASN1ObjectIdentifier id_camellia128_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.2");
+    /** id-camellia192-cbc; OID 1.2.392.200011.61.1.1.1.3 */
+    static final ASN1ObjectIdentifier id_camellia192_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.3");
+    /** id-camellia256-cbc; OID 1.2.392.200011.61.1.1.1.4 */
+    static final ASN1ObjectIdentifier id_camellia256_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.4");
+
+    /** id-camellia128-wrap; OID 1.2.392.200011.61.1.1.3.2 */
+    static final ASN1ObjectIdentifier id_camellia128_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.2");
+    /** id-camellia192-wrap; OID 1.2.392.200011.61.1.1.3.3 */
+    static final ASN1ObjectIdentifier id_camellia192_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.3");
+    /** id-camellia256-wrap; OID 1.2.392.200011.61.1.1.3.4 */
+    static final ASN1ObjectIdentifier id_camellia256_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.4");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java
new file mode 100644
index 0000000..b32a578
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java
@@ -0,0 +1,116 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BasicOCSPResponse
+    extends ASN1Object
+{
+    private ResponseData        tbsResponseData;
+    private AlgorithmIdentifier signatureAlgorithm;
+    private DERBitString        signature;
+    private ASN1Sequence        certs;
+
+    public BasicOCSPResponse(
+        ResponseData        tbsResponseData,
+        AlgorithmIdentifier signatureAlgorithm,
+        DERBitString        signature,
+        ASN1Sequence        certs)
+    {
+        this.tbsResponseData = tbsResponseData;
+        this.signatureAlgorithm = signatureAlgorithm;
+        this.signature = signature;
+        this.certs = certs;
+    }
+
+    private BasicOCSPResponse(
+        ASN1Sequence    seq)
+    {
+        this.tbsResponseData = ResponseData.getInstance(seq.getObjectAt(0));
+        this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+        this.signature = (DERBitString)seq.getObjectAt(2);
+
+        if (seq.size() > 3)
+        {
+            this.certs = ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(3), true);
+        }
+    }
+
+    public static BasicOCSPResponse getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static BasicOCSPResponse getInstance(
+        Object  obj)
+    {
+        if (obj instanceof BasicOCSPResponse)
+        {
+            return (BasicOCSPResponse)obj;
+        }
+        else if (obj != null)
+        {
+            return new BasicOCSPResponse(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public ResponseData getTbsResponseData()
+    {
+        return tbsResponseData;
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return signatureAlgorithm;
+    }
+
+    public DERBitString getSignature()
+    {
+        return signature;
+    }
+
+    public ASN1Sequence getCerts()
+    {
+        return certs;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * BasicOCSPResponse       ::= SEQUENCE {
+     *      tbsResponseData      ResponseData,
+     *      signatureAlgorithm   AlgorithmIdentifier,
+     *      signature            BIT STRING,
+     *      certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(tbsResponseData);
+        v.add(signatureAlgorithm);
+        v.add(signature);
+        if (certs != null)
+        {
+            v.add(new DERTaggedObject(true, 0, certs));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/CertID.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/CertID.java
new file mode 100644
index 0000000..06b1b03
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/CertID.java
@@ -0,0 +1,109 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CertID
+    extends ASN1Object
+{
+    AlgorithmIdentifier    hashAlgorithm;
+    ASN1OctetString        issuerNameHash;
+    ASN1OctetString        issuerKeyHash;
+    ASN1Integer             serialNumber;
+
+    public CertID(
+        AlgorithmIdentifier hashAlgorithm,
+        ASN1OctetString     issuerNameHash,
+        ASN1OctetString     issuerKeyHash,
+        ASN1Integer         serialNumber)
+    {
+        this.hashAlgorithm = hashAlgorithm;
+        this.issuerNameHash = issuerNameHash;
+        this.issuerKeyHash = issuerKeyHash;
+        this.serialNumber = serialNumber;
+    }
+
+    private CertID(
+        ASN1Sequence    seq)
+    {
+        hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
+        issuerNameHash = (ASN1OctetString)seq.getObjectAt(1);
+        issuerKeyHash = (ASN1OctetString)seq.getObjectAt(2);
+        serialNumber = (ASN1Integer)seq.getObjectAt(3);
+    }
+
+    public static CertID getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static CertID getInstance(
+        Object  obj)
+    {
+        if (obj instanceof CertID)
+        {
+            return (CertID)obj;
+        }
+        else if (obj != null)
+        {
+            return new CertID(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public AlgorithmIdentifier getHashAlgorithm()
+    {
+        return hashAlgorithm;
+    }
+
+    public ASN1OctetString getIssuerNameHash()
+    {
+        return issuerNameHash;
+    }
+
+    public ASN1OctetString getIssuerKeyHash()
+    {
+        return issuerKeyHash;
+    }
+
+    public ASN1Integer getSerialNumber()
+    {
+        return serialNumber;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * CertID          ::=     SEQUENCE {
+     *     hashAlgorithm       AlgorithmIdentifier,
+     *     issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
+     *     issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
+     *     serialNumber        CertificateSerialNumber }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(hashAlgorithm);
+        v.add(issuerNameHash);
+        v.add(issuerKeyHash);
+        v.add(serialNumber);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/CertStatus.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/CertStatus.java
new file mode 100644
index 0000000..25ba415
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/CertStatus.java
@@ -0,0 +1,112 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Choice;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CertStatus
+    extends ASN1Object
+    implements ASN1Choice
+{
+    private int             tagNo;
+    private ASN1Encodable    value;
+
+    /**
+     * create a CertStatus object with a tag of zero.
+     */
+    public CertStatus()
+    {
+        tagNo = 0;
+        value = DERNull.INSTANCE;
+    }
+
+    public CertStatus(
+        RevokedInfo info)
+    {
+        tagNo = 1;
+        value = info;
+    }
+
+    public CertStatus(
+        int tagNo,
+        ASN1Encodable    value)
+    {
+        this.tagNo = tagNo;
+        this.value = value;
+    }
+
+    private CertStatus(
+        ASN1TaggedObject    choice)
+    {
+        this.tagNo = choice.getTagNo();
+
+        switch (choice.getTagNo())
+        {
+        case 0:
+            value = DERNull.INSTANCE;
+            break;
+        case 1:
+            value = RevokedInfo.getInstance(choice, false);
+            break;
+        case 2:
+            value = DERNull.INSTANCE;
+            break;
+        default:
+            throw new IllegalArgumentException("Unknown tag encountered: " + choice.getTagNo());
+        }
+    }
+
+    public static CertStatus getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof CertStatus)
+        {
+            return (CertStatus)obj;
+        }
+        else if (obj instanceof ASN1TaggedObject)
+        {
+            return new CertStatus((ASN1TaggedObject)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+    }
+
+    public static CertStatus getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject()); // must be explicitly tagged
+    }
+    
+    public int getTagNo()
+    {
+        return tagNo;
+    }
+
+    public ASN1Encodable getStatus()
+    {
+        return value;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  CertStatus ::= CHOICE {
+     *                  good        [0]     IMPLICIT NULL,
+     *                  revoked     [1]     IMPLICIT RevokedInfo,
+     *                  unknown     [2]     IMPLICIT UnknownInfo }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return new DERTaggedObject(false, tagNo, value);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/CrlID.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/CrlID.java
new file mode 100644
index 0000000..d9ac95b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/CrlID.java
@@ -0,0 +1,114 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1GeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CrlID
+    extends ASN1Object
+{
+    private DERIA5String         crlUrl;
+    private ASN1Integer          crlNum;
+    private ASN1GeneralizedTime  crlTime;
+
+    private CrlID(
+        ASN1Sequence    seq)
+    {
+        Enumeration    e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)e.nextElement();
+
+            switch (o.getTagNo())
+            {
+            case 0:
+                crlUrl = DERIA5String.getInstance(o, true);
+                break;
+            case 1:
+                crlNum = ASN1Integer.getInstance(o, true);
+                break;
+            case 2:
+                crlTime = ASN1GeneralizedTime.getInstance(o, true);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "unknown tag number: " + o.getTagNo());
+            }
+        }
+    }
+
+    public static CrlID getInstance(
+        Object  obj)
+    {
+        if (obj instanceof CrlID)
+        {
+            return (CrlID)obj;
+        }
+        else if (obj != null)
+        {
+            return new CrlID(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public DERIA5String getCrlUrl()
+    {
+        return crlUrl;
+    }
+
+    public ASN1Integer getCrlNum()
+    {
+        return crlNum;
+    }
+
+    public ASN1GeneralizedTime getCrlTime()
+    {
+        return crlTime;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * CrlID ::= SEQUENCE {
+     *     crlUrl               [0]     EXPLICIT IA5String OPTIONAL,
+     *     crlNum               [1]     EXPLICIT INTEGER OPTIONAL,
+     *     crlTime              [2]     EXPLICIT GeneralizedTime OPTIONAL }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        if (crlUrl != null)
+        {
+            v.add(new DERTaggedObject(true, 0, crlUrl));
+        }
+
+        if (crlNum != null)
+        {
+            v.add(new DERTaggedObject(true, 1, crlNum));
+        }
+
+        if (crlTime != null)
+        {
+            v.add(new DERTaggedObject(true, 2, crlTime));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java
new file mode 100644
index 0000000..1698ec1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java
@@ -0,0 +1,36 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * OIDs for <a href="http://tools.ietf.org/html/rfc2560">RFC 2560</a> and <a href="http://tools.ietf.org/html/rfc6960">RFC 6960</a>
+ * Online Certificate Status Protocol - OCSP.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface OCSPObjectIdentifiers
+{
+    /** OID: 1.3.6.1.5.5.7.48.1 */
+    static final ASN1ObjectIdentifier id_pkix_ocsp       = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1");
+    /** OID: 1.3.6.1.5.5.7.48.1.1 */
+    static final ASN1ObjectIdentifier id_pkix_ocsp_basic = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.1");
+    
+    /** OID: 1.3.6.1.5.5.7.48.1.2 */
+    static final ASN1ObjectIdentifier id_pkix_ocsp_nonce = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.2");
+    /** OID: 1.3.6.1.5.5.7.48.1.3 */
+    static final ASN1ObjectIdentifier id_pkix_ocsp_crl   = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.3");
+    
+    /** OID: 1.3.6.1.5.5.7.48.1.4 */
+    static final ASN1ObjectIdentifier id_pkix_ocsp_response        = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.4");
+    /** OID: 1.3.6.1.5.5.7.48.1.5 */
+    static final ASN1ObjectIdentifier id_pkix_ocsp_nocheck         = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.5");
+    /** OID: 1.3.6.1.5.5.7.48.1.6 */
+    static final ASN1ObjectIdentifier id_pkix_ocsp_archive_cutoff  = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.6");
+    /** OID: 1.3.6.1.5.5.7.48.1.7 */
+    static final ASN1ObjectIdentifier id_pkix_ocsp_service_locator = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.7");
+
+
+    static final ASN1ObjectIdentifier id_pkix_ocsp_pref_sig_algs = id_pkix_ocsp.branch("8");
+
+    static final ASN1ObjectIdentifier id_pkix_ocsp_extended_revoke = id_pkix_ocsp.branch("9");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPRequest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPRequest.java
new file mode 100644
index 0000000..38c4ab1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPRequest.java
@@ -0,0 +1,94 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OCSPRequest
+    extends ASN1Object
+{
+    TBSRequest      tbsRequest;
+    Signature       optionalSignature;
+
+    public OCSPRequest(
+        TBSRequest  tbsRequest,
+        Signature   optionalSignature)
+    {
+        this.tbsRequest = tbsRequest;
+        this.optionalSignature = optionalSignature;
+    }
+
+    private OCSPRequest(
+        ASN1Sequence    seq)
+    {
+        tbsRequest = TBSRequest.getInstance(seq.getObjectAt(0));
+
+        if (seq.size() == 2)
+        {
+            optionalSignature = Signature.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(1), true);
+        }
+    }
+    
+    public static OCSPRequest getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static OCSPRequest getInstance(
+        Object  obj)
+    {
+        if (obj instanceof OCSPRequest)
+        {
+            return (OCSPRequest)obj;
+        }
+        else if (obj != null)
+        {
+            return new OCSPRequest(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+    
+    public TBSRequest getTbsRequest()
+    {
+        return tbsRequest;
+    }
+
+    public Signature getOptionalSignature()
+    {
+        return optionalSignature;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * OCSPRequest     ::=     SEQUENCE {
+     *     tbsRequest                  TBSRequest,
+     *     optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(tbsRequest);
+
+        if (optionalSignature != null)
+        {
+            v.add(new DERTaggedObject(true, 0, optionalSignature));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPResponse.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPResponse.java
new file mode 100644
index 0000000..a1d5173
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPResponse.java
@@ -0,0 +1,94 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OCSPResponse
+    extends ASN1Object
+{
+    OCSPResponseStatus    responseStatus;
+    ResponseBytes        responseBytes;
+
+    public OCSPResponse(
+        OCSPResponseStatus  responseStatus,
+        ResponseBytes       responseBytes)
+    {
+        this.responseStatus = responseStatus;
+        this.responseBytes = responseBytes;
+    }
+
+    private OCSPResponse(
+        ASN1Sequence    seq)
+    {
+        responseStatus = OCSPResponseStatus.getInstance(seq.getObjectAt(0));
+
+        if (seq.size() == 2)
+        {
+            responseBytes = ResponseBytes.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(1), true);
+        }
+    }
+
+    public static OCSPResponse getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static OCSPResponse getInstance(
+        Object  obj)
+    {
+        if (obj instanceof OCSPResponse)
+        {
+            return (OCSPResponse)obj;
+        }
+        else if (obj != null)
+        {
+            return new OCSPResponse(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public OCSPResponseStatus getResponseStatus()
+    {
+        return responseStatus;
+    }
+
+    public ResponseBytes getResponseBytes()
+    {
+        return responseBytes;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * OCSPResponse ::= SEQUENCE {
+     *     responseStatus         OCSPResponseStatus,
+     *     responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(responseStatus);
+
+        if (responseBytes != null)
+        {
+            v.add(new DERTaggedObject(true, 0, responseBytes));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java
new file mode 100644
index 0000000..aa301e5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java
@@ -0,0 +1,75 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OCSPResponseStatus
+    extends ASN1Object
+{
+    public static final int SUCCESSFUL = 0;
+    public static final int MALFORMED_REQUEST = 1;
+    public static final int INTERNAL_ERROR = 2;
+    public static final int TRY_LATER = 3;
+    public static final int SIG_REQUIRED = 5;
+    public static final int UNAUTHORIZED = 6;
+
+    private ASN1Enumerated value;
+
+    /**
+     * The OCSPResponseStatus enumeration.
+     * <pre>
+     * OCSPResponseStatus ::= ENUMERATED {
+     *     successful            (0),  --Response has valid confirmations
+     *     malformedRequest      (1),  --Illegal confirmation request
+     *     internalError         (2),  --Internal error in issuer
+     *     tryLater              (3),  --Try again later
+     *                                 --(4) is not used
+     *     sigRequired           (5),  --Must sign the request
+     *     unauthorized          (6)   --Request unauthorized
+     * }
+     * </pre>
+     */
+    public OCSPResponseStatus(
+        int value)
+    {
+        this(new ASN1Enumerated(value));
+    }
+
+    private OCSPResponseStatus(
+        ASN1Enumerated value)
+    {
+        this.value = value;
+    }
+
+    public static OCSPResponseStatus getInstance(
+        Object  obj)
+    {
+        if (obj instanceof OCSPResponseStatus)
+        {
+            return (OCSPResponseStatus)obj;
+        }
+        else if (obj != null)
+        {
+            return new OCSPResponseStatus(ASN1Enumerated.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public BigInteger getValue()
+    {
+        return value.getValue();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return value;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/Request.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/Request.java
new file mode 100644
index 0000000..df83665
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/Request.java
@@ -0,0 +1,95 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x509.Extensions;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Request
+    extends ASN1Object
+{
+    CertID            reqCert;
+    Extensions    singleRequestExtensions;
+
+    public Request(
+        CertID          reqCert,
+        Extensions singleRequestExtensions)
+    {
+        this.reqCert = reqCert;
+        this.singleRequestExtensions = singleRequestExtensions;
+    }
+
+    private Request(
+        ASN1Sequence    seq)
+    {
+        reqCert = CertID.getInstance(seq.getObjectAt(0));
+
+        if (seq.size() == 2)
+        {
+            singleRequestExtensions = Extensions.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(1), true);
+        }
+    }
+
+    public static Request getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static Request getInstance(
+        Object  obj)
+    {
+        if (obj instanceof Request)
+        {
+            return (Request)obj;
+        }
+        else if (obj != null)
+        {
+            return new Request(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public CertID getReqCert()
+    {
+        return reqCert;
+    }
+
+    public Extensions getSingleRequestExtensions()
+    {
+        return singleRequestExtensions;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Request         ::=     SEQUENCE {
+     *     reqCert                     CertID,
+     *     singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(reqCert);
+
+        if (singleRequestExtensions != null)
+        {
+            v.add(new DERTaggedObject(true, 0, singleRequestExtensions));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/ResponderID.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/ResponderID.java
new file mode 100644
index 0000000..ad42120
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/ResponderID.java
@@ -0,0 +1,108 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Choice;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ResponderID
+    extends ASN1Object
+    implements ASN1Choice
+{
+    private ASN1Encodable    value;
+
+    public ResponderID(
+        ASN1OctetString    value)
+    {
+        this.value = value;
+    }
+
+    public ResponderID(
+        X500Name value)
+    {
+        this.value = value;
+    }
+
+    public static ResponderID getInstance(
+        Object  obj)
+    {
+        if (obj instanceof ResponderID)
+        {
+            return (ResponderID)obj;
+        }
+        else if (obj instanceof DEROctetString)
+        {
+            return new ResponderID((DEROctetString)obj);
+        }
+        else if (obj instanceof ASN1TaggedObject)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)obj;
+
+            if (o.getTagNo() == 1)
+            {
+                return new ResponderID(X500Name.getInstance(o, true));
+            }
+            else
+            {
+                return new ResponderID(ASN1OctetString.getInstance(o, true));
+            }
+        }
+
+        return new ResponderID(X500Name.getInstance(obj));
+    }
+
+    public static ResponderID getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject()); // must be explicitly tagged
+    }
+
+    public byte[] getKeyHash()
+    {
+        if (this.value instanceof ASN1OctetString)
+        {
+            ASN1OctetString octetString = (ASN1OctetString)this.value;
+            return octetString.getOctets();
+        }
+
+        return null;
+    }
+
+    public X500Name getName()
+    {
+        if (this.value instanceof ASN1OctetString)
+        {
+            return null;
+        }
+
+        return X500Name.getInstance(value);
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * ResponderID ::= CHOICE {
+     *      byName          [1] Name,
+     *      byKey           [2] KeyHash }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        if (value instanceof ASN1OctetString)
+        {
+            return new DERTaggedObject(true, 2, value);
+        }
+
+        return new DERTaggedObject(true, 1, value);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/ResponseBytes.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/ResponseBytes.java
new file mode 100644
index 0000000..1f5eccf
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/ResponseBytes.java
@@ -0,0 +1,89 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ResponseBytes
+    extends ASN1Object
+{
+    ASN1ObjectIdentifier    responseType;
+    ASN1OctetString        response;
+
+    public ResponseBytes(
+        ASN1ObjectIdentifier responseType,
+        ASN1OctetString     response)
+    {
+        this.responseType = responseType;
+        this.response = response;
+    }
+
+    /**
+     * @deprecated use getInstance()
+     */
+    public ResponseBytes(
+        ASN1Sequence    seq)
+    {
+        responseType = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+        response = (ASN1OctetString)seq.getObjectAt(1);
+    }
+
+    public static ResponseBytes getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static ResponseBytes getInstance(
+        Object  obj)
+    {
+        if (obj instanceof ResponseBytes)
+        {
+            return (ResponseBytes)obj;
+        }
+        else if (obj != null)
+        {
+            return new ResponseBytes(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public ASN1ObjectIdentifier getResponseType()
+    {
+        return responseType;
+    }
+
+    public ASN1OctetString getResponse()
+    {
+        return response;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * ResponseBytes ::=       SEQUENCE {
+     *     responseType   OBJECT IDENTIFIER,
+     *     response       OCTET STRING }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(responseType);
+        v.add(response);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/ResponseData.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/ResponseData.java
new file mode 100644
index 0000000..9aae08b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/ResponseData.java
@@ -0,0 +1,185 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1GeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x509.Extensions;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Extensions;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ResponseData
+    extends ASN1Object
+{
+    private static final ASN1Integer V1 = new ASN1Integer(0);
+    
+    private boolean             versionPresent;
+    
+    private ASN1Integer          version;
+    private ResponderID         responderID;
+    private ASN1GeneralizedTime  producedAt;
+    private ASN1Sequence        responses;
+    private Extensions      responseExtensions;
+
+    public ResponseData(
+        ASN1Integer          version,
+        ResponderID         responderID,
+        ASN1GeneralizedTime  producedAt,
+        ASN1Sequence        responses,
+        Extensions      responseExtensions)
+    {
+        this.version = version;
+        this.responderID = responderID;
+        this.producedAt = producedAt;
+        this.responses = responses;
+        this.responseExtensions = responseExtensions;
+    }
+
+    /**
+     * @deprecated use method taking Extensions
+     * @param responderID
+     * @param producedAt
+     * @param responses
+     * @param responseExtensions
+     */
+    public ResponseData(
+        ResponderID         responderID,
+        ASN1GeneralizedTime  producedAt,
+        ASN1Sequence        responses,
+        X509Extensions responseExtensions)
+    {
+        this(V1, responderID, ASN1GeneralizedTime.getInstance(producedAt), responses, Extensions.getInstance(responseExtensions));
+    }
+
+    public ResponseData(
+        ResponderID         responderID,
+        ASN1GeneralizedTime  producedAt,
+        ASN1Sequence        responses,
+        Extensions      responseExtensions)
+    {
+        this(V1, responderID, producedAt, responses, responseExtensions);
+    }
+    
+    private ResponseData(
+        ASN1Sequence    seq)
+    {
+        int index = 0;
+
+        if (seq.getObjectAt(0) instanceof ASN1TaggedObject)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)seq.getObjectAt(0);
+
+            if (o.getTagNo() == 0)
+            {
+                this.versionPresent = true;
+                this.version = ASN1Integer.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(0), true);
+                index++;
+            }
+            else
+            {
+                this.version = V1;
+            }
+        }
+        else
+        {
+            this.version = V1;
+        }
+
+        this.responderID = ResponderID.getInstance(seq.getObjectAt(index++));
+        this.producedAt = ASN1GeneralizedTime.getInstance(seq.getObjectAt(index++));
+        this.responses = (ASN1Sequence)seq.getObjectAt(index++);
+
+        if (seq.size() > index)
+        {
+            this.responseExtensions = Extensions.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(index), true);
+        }
+    }
+
+    public static ResponseData getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static ResponseData getInstance(
+        Object  obj)
+    {
+        if (obj instanceof ResponseData)
+        {
+            return (ResponseData)obj;
+        }
+        else if (obj != null)
+        {
+            return new ResponseData(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public ASN1Integer getVersion()
+    {
+        return version;
+    }
+
+    public ResponderID getResponderID()
+    {
+        return responderID;
+    }
+
+    public ASN1GeneralizedTime getProducedAt()
+    {
+        return producedAt;
+    }
+
+    public ASN1Sequence getResponses()
+    {
+        return responses;
+    }
+
+    public Extensions getResponseExtensions()
+    {
+        return responseExtensions;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * ResponseData ::= SEQUENCE {
+     *     version              [0] EXPLICIT Version DEFAULT v1,
+     *     responderID              ResponderID,
+     *     producedAt               GeneralizedTime,
+     *     responses                SEQUENCE OF SingleResponse,
+     *     responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        if (versionPresent || !version.equals(V1))
+        {
+            v.add(new DERTaggedObject(true, 0, version));
+        }
+
+        v.add(responderID);
+        v.add(producedAt);
+        v.add(responses);
+        if (responseExtensions != null)
+        {
+            v.add(new DERTaggedObject(true, 1, responseExtensions));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/RevokedInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/RevokedInfo.java
new file mode 100644
index 0000000..c75b9d8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/RevokedInfo.java
@@ -0,0 +1,96 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated;
+import com.android.internal.org.bouncycastle.asn1.ASN1GeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x509.CRLReason;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RevokedInfo
+    extends ASN1Object
+{
+    private ASN1GeneralizedTime  revocationTime;
+    private CRLReason           revocationReason;
+
+    public RevokedInfo(
+        ASN1GeneralizedTime  revocationTime,
+        CRLReason           revocationReason)
+    {
+        this.revocationTime = revocationTime;
+        this.revocationReason = revocationReason;
+    }
+
+    private RevokedInfo(
+        ASN1Sequence    seq)
+    {
+        this.revocationTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(0));
+
+        if (seq.size() > 1)
+        {
+            this.revocationReason = CRLReason.getInstance(ASN1Enumerated.getInstance(
+                (ASN1TaggedObject)seq.getObjectAt(1), true));
+        }
+    }
+
+    public static RevokedInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static RevokedInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof RevokedInfo)
+        {
+            return (RevokedInfo)obj;
+        }
+        else if (obj != null)
+        {
+            return new RevokedInfo(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public ASN1GeneralizedTime getRevocationTime()
+    {
+        return revocationTime;
+    }
+
+    public CRLReason getRevocationReason()
+    {
+        return revocationReason;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * RevokedInfo ::= SEQUENCE {
+     *      revocationTime              GeneralizedTime,
+     *      revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(revocationTime);
+        if (revocationReason != null)
+        {
+            v.add(new DERTaggedObject(true, 0, revocationReason));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/Signature.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/Signature.java
new file mode 100644
index 0000000..d1fc0ad
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/Signature.java
@@ -0,0 +1,115 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Signature
+    extends ASN1Object
+{
+    AlgorithmIdentifier signatureAlgorithm;
+    DERBitString        signature;
+    ASN1Sequence        certs;
+
+    public Signature(
+        AlgorithmIdentifier signatureAlgorithm,
+        DERBitString        signature)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+        this.signature = signature;
+    }
+
+    public Signature(
+        AlgorithmIdentifier signatureAlgorithm,
+        DERBitString        signature,
+        ASN1Sequence        certs)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+        this.signature = signature;
+        this.certs = certs;
+    }
+
+    private Signature(
+        ASN1Sequence    seq)
+    {
+        signatureAlgorithm  = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
+        signature = (DERBitString)seq.getObjectAt(1);
+
+        if (seq.size() == 3)
+        {
+            certs = ASN1Sequence.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(2), true);
+        }
+    }
+
+    public static Signature getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static Signature getInstance(
+        Object  obj)
+    {
+        if (obj instanceof Signature)
+        {
+            return (Signature)obj;
+        }
+        else if (obj != null)
+        {
+            return new Signature(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return signatureAlgorithm;
+    }
+
+    public DERBitString getSignature()
+    {
+        return signature;
+    }
+
+    public ASN1Sequence getCerts()
+    {
+        return certs;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Signature       ::=     SEQUENCE {
+     *     signatureAlgorithm      AlgorithmIdentifier,
+     *     signature               BIT STRING,
+     *     certs               [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(signatureAlgorithm);
+        v.add(signature);
+
+        if (certs != null)
+        {
+            v.add(new DERTaggedObject(true, 0, certs));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/SingleResponse.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/SingleResponse.java
new file mode 100644
index 0000000..74e3730
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/SingleResponse.java
@@ -0,0 +1,166 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1GeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x509.Extensions;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Extensions;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SingleResponse
+    extends ASN1Object
+{
+    private CertID              certID;
+    private CertStatus          certStatus;
+    private ASN1GeneralizedTime  thisUpdate;
+    private ASN1GeneralizedTime  nextUpdate;
+    private Extensions      singleExtensions;
+
+    /**
+     * @deprecated use method taking ASN1GeneralizedTime and Extensions
+     * @param certID
+     * @param certStatus
+     * @param thisUpdate
+     * @param nextUpdate
+     * @param singleExtensions
+     */
+    public SingleResponse(
+        CertID              certID,
+        CertStatus          certStatus,
+        ASN1GeneralizedTime thisUpdate,
+        ASN1GeneralizedTime nextUpdate,
+        X509Extensions singleExtensions)
+    {
+        this(certID, certStatus, thisUpdate, nextUpdate, Extensions.getInstance(singleExtensions));
+    }
+
+    public SingleResponse(
+        CertID              certID,
+        CertStatus          certStatus,
+        ASN1GeneralizedTime thisUpdate,
+        ASN1GeneralizedTime nextUpdate,
+        Extensions          singleExtensions)
+    {
+        this.certID = certID;
+        this.certStatus = certStatus;
+        this.thisUpdate = thisUpdate;
+        this.nextUpdate = nextUpdate;
+        this.singleExtensions = singleExtensions;
+    }
+
+    private SingleResponse(
+        ASN1Sequence    seq)
+    {
+        this.certID = CertID.getInstance(seq.getObjectAt(0));
+        this.certStatus = CertStatus.getInstance(seq.getObjectAt(1));
+        this.thisUpdate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(2));
+
+        if (seq.size() > 4)
+        {
+            this.nextUpdate = ASN1GeneralizedTime.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(3), true);
+            this.singleExtensions = Extensions.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(4), true);
+        }
+        else if (seq.size() > 3)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)seq.getObjectAt(3);
+
+            if (o.getTagNo() == 0)
+            {
+                this.nextUpdate = ASN1GeneralizedTime.getInstance(o, true);
+            }
+            else
+            {
+                this.singleExtensions = Extensions.getInstance(o, true);
+            }
+        }
+    }
+
+    public static SingleResponse getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static SingleResponse getInstance(
+        Object  obj)
+    {
+        if (obj instanceof SingleResponse)
+        {
+            return (SingleResponse)obj;
+        }
+        else if (obj != null)
+        {
+            return new SingleResponse(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public CertID getCertID()
+    {
+        return certID;
+    }
+
+    public CertStatus getCertStatus()
+    {
+        return certStatus;
+    }
+
+    public ASN1GeneralizedTime getThisUpdate()
+    {
+        return thisUpdate;
+    }
+
+    public ASN1GeneralizedTime getNextUpdate()
+    {
+        return nextUpdate;
+    }
+
+    public Extensions getSingleExtensions()
+    {
+        return singleExtensions;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  SingleResponse ::= SEQUENCE {
+     *          certID                       CertID,
+     *          certStatus                   CertStatus,
+     *          thisUpdate                   GeneralizedTime,
+     *          nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
+     *          singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(certID);
+        v.add(certStatus);
+        v.add(thisUpdate);
+
+        if (nextUpdate != null)
+        {
+            v.add(new DERTaggedObject(true, 0, nextUpdate));
+        }
+
+        if (singleExtensions != null)
+        {
+            v.add(new DERTaggedObject(true, 1, singleExtensions));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/TBSRequest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/TBSRequest.java
new file mode 100644
index 0000000..4787da3
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/ocsp/TBSRequest.java
@@ -0,0 +1,176 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.ocsp;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x509.Extensions;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Extensions;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TBSRequest
+    extends ASN1Object
+{
+    private static final ASN1Integer V1 = new ASN1Integer(0);
+    
+    ASN1Integer      version;
+    GeneralName     requestorName;
+    ASN1Sequence    requestList;
+    Extensions  requestExtensions;
+
+    boolean         versionSet;
+
+    /**
+     * @deprecated use method taking Extensions
+     * @param requestorName
+     * @param requestList
+     * @param requestExtensions
+     */
+    public TBSRequest(
+        GeneralName     requestorName,
+        ASN1Sequence    requestList,
+        X509Extensions requestExtensions)
+    {
+        this.version = V1;
+        this.requestorName = requestorName;
+        this.requestList = requestList;
+        this.requestExtensions = Extensions.getInstance(requestExtensions);
+    }
+
+    public TBSRequest(
+        GeneralName     requestorName,
+        ASN1Sequence    requestList,
+        Extensions  requestExtensions)
+    {
+        this.version = V1;
+        this.requestorName = requestorName;
+        this.requestList = requestList;
+        this.requestExtensions = requestExtensions;
+    }
+
+    private TBSRequest(
+        ASN1Sequence    seq)
+    {
+        int    index = 0;
+
+        if (seq.getObjectAt(0) instanceof ASN1TaggedObject)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)seq.getObjectAt(0);
+
+            if (o.getTagNo() == 0)
+            {
+                versionSet = true;
+                version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);
+                index++;
+            }
+            else
+            {
+                version = V1;
+            }
+        }
+        else
+        {
+            version = V1;
+        }
+
+        if (seq.getObjectAt(index) instanceof ASN1TaggedObject)
+        {
+            requestorName = GeneralName.getInstance((ASN1TaggedObject)seq.getObjectAt(index++), true);
+        }
+        
+        requestList = (ASN1Sequence)seq.getObjectAt(index++);
+
+        if (seq.size() == (index + 1))
+        {
+            requestExtensions = Extensions.getInstance((ASN1TaggedObject)seq.getObjectAt(index), true);
+        }
+    }
+
+    public static TBSRequest getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static TBSRequest getInstance(
+        Object  obj)
+    {
+        if (obj instanceof TBSRequest)
+        {
+            return (TBSRequest)obj;
+        }
+        else if (obj != null)
+        {
+            return new TBSRequest(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public ASN1Integer getVersion()
+    {
+        return version;
+    }
+
+    public GeneralName getRequestorName()
+    {
+        return requestorName;
+    }
+
+    public ASN1Sequence getRequestList()
+    {
+        return requestList;
+    }
+
+    public Extensions getRequestExtensions()
+    {
+        return requestExtensions;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * TBSRequest      ::=     SEQUENCE {
+     *     version             [0]     EXPLICIT Version DEFAULT v1,
+     *     requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
+     *     requestList                 SEQUENCE OF Request,
+     *     requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        //
+        // if default don't include - unless explicitly provided. Not strictly correct
+        // but required for some requests
+        //
+        if (!version.equals(V1) || versionSet)
+        {
+            v.add(new DERTaggedObject(true, 0, version));
+        }
+        
+        if (requestorName != null)
+        {
+            v.add(new DERTaggedObject(true, 1, requestorName));
+        }
+
+        v.add(requestList);
+
+        if (requestExtensions != null)
+        {
+            v.add(new DERTaggedObject(true, 2, requestExtensions));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
new file mode 100644
index 0000000..5aa8826
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
@@ -0,0 +1,52 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.oiw;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * OIW organization's OIDs:
+ * <p>
+ * id-SHA1 OBJECT IDENTIFIER ::=    
+ *   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface OIWObjectIdentifiers
+{
+    /** OID: 1.3.14.3.2.2 */
+    static final ASN1ObjectIdentifier    md4WithRSA              = new ASN1ObjectIdentifier("1.3.14.3.2.2");
+    /** OID: 1.3.14.3.2.3 */
+    static final ASN1ObjectIdentifier    md5WithRSA              = new ASN1ObjectIdentifier("1.3.14.3.2.3");
+    /** OID: 1.3.14.3.2.4 */
+    static final ASN1ObjectIdentifier    md4WithRSAEncryption    = new ASN1ObjectIdentifier("1.3.14.3.2.4");
+    
+    /** OID: 1.3.14.3.2.6 */
+    static final ASN1ObjectIdentifier    desECB                  = new ASN1ObjectIdentifier("1.3.14.3.2.6");
+    /** OID: 1.3.14.3.2.7 */
+    static final ASN1ObjectIdentifier    desCBC                  = new ASN1ObjectIdentifier("1.3.14.3.2.7");
+    /** OID: 1.3.14.3.2.8 */
+    static final ASN1ObjectIdentifier    desOFB                  = new ASN1ObjectIdentifier("1.3.14.3.2.8");
+    /** OID: 1.3.14.3.2.9 */
+    static final ASN1ObjectIdentifier    desCFB                  = new ASN1ObjectIdentifier("1.3.14.3.2.9");
+
+    /** OID: 1.3.14.3.2.17 */
+    static final ASN1ObjectIdentifier    desEDE                  = new ASN1ObjectIdentifier("1.3.14.3.2.17");
+    
+    /** OID: 1.3.14.3.2.26 */
+    static final ASN1ObjectIdentifier    idSHA1                  = new ASN1ObjectIdentifier("1.3.14.3.2.26");
+
+    /** OID: 1.3.14.3.2.27 */
+    static final ASN1ObjectIdentifier    dsaWithSHA1             = new ASN1ObjectIdentifier("1.3.14.3.2.27");
+
+    /** OID: 1.3.14.3.2.29 */
+    static final ASN1ObjectIdentifier    sha1WithRSA             = new ASN1ObjectIdentifier("1.3.14.3.2.29");
+    
+    /**
+     * <pre>
+     * ElGamal Algorithm OBJECT IDENTIFIER ::=    
+     *   {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }
+     * </pre>
+     * OID: 1.3.14.7.2.1.1
+     */
+    static final ASN1ObjectIdentifier    elGamalAlgorithm        = new ASN1ObjectIdentifier("1.3.14.7.2.1.1");
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/Attribute.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/Attribute.java
new file mode 100644
index 0000000..c3b80d2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/Attribute.java
@@ -0,0 +1,92 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Attribute
+    extends ASN1Object
+{
+    private ASN1ObjectIdentifier attrType;
+    private ASN1Set              attrValues;
+
+    /**
+     * return an Attribute object from the given object.
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static Attribute getInstance(
+        Object o)
+    {
+        if (o == null || o instanceof Attribute)
+        {
+            return (Attribute)o;
+        }
+        
+        if (o instanceof ASN1Sequence)
+        {
+            return new Attribute((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName());
+    }
+    
+    public Attribute(
+        ASN1Sequence seq)
+    {
+        attrType = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+        attrValues = (ASN1Set)seq.getObjectAt(1);
+    }
+
+    public Attribute(
+        ASN1ObjectIdentifier attrType,
+        ASN1Set             attrValues)
+    {
+        this.attrType = attrType;
+        this.attrValues = attrValues;
+    }
+
+    public ASN1ObjectIdentifier getAttrType()
+    {
+        return attrType;
+    }
+    
+    public ASN1Set getAttrValues()
+    {
+        return attrValues;
+    }
+
+    public ASN1Encodable[] getAttributeValues()
+    {
+        return attrValues.toArray();
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Attribute ::= SEQUENCE {
+     *     attrType OBJECT IDENTIFIER,
+     *     attrValues SET OF AttributeValue
+     * }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(attrType);
+        v.add(attrValues);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java
new file mode 100644
index 0000000..0df396c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java
@@ -0,0 +1,87 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.BERSequence;
+import com.android.internal.org.bouncycastle.asn1.DLSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AuthenticatedSafe
+    extends ASN1Object
+{
+    private ContentInfo[]    info;
+    private boolean  isBer = true;
+
+    private AuthenticatedSafe(
+        ASN1Sequence  seq)
+    {
+        info = new ContentInfo[seq.size()];
+
+        for (int i = 0; i != info.length; i++)
+        {
+            info[i] = ContentInfo.getInstance(seq.getObjectAt(i));
+        }
+
+        isBer = seq instanceof BERSequence;
+    }
+
+    public static AuthenticatedSafe getInstance(
+        Object o)
+    {
+        if (o instanceof AuthenticatedSafe)
+        {
+            return (AuthenticatedSafe)o;
+        }
+
+        if (o != null)
+        {
+            return new AuthenticatedSafe(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
+    }
+
+    public AuthenticatedSafe(
+        ContentInfo[]       info)
+    {
+        this.info = copy(info);
+    }
+
+    public ContentInfo[] getContentInfo()
+    {
+        return copy(info);
+    }
+
+    private ContentInfo[] copy(ContentInfo[] infos)
+    {
+        ContentInfo[] tmp = new ContentInfo[infos.length];
+
+        System.arraycopy(infos, 0, tmp, 0, tmp.length);
+
+        return tmp;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        for (int i = 0; i != info.length; i++)
+        {
+            v.add(info[i]);
+        }
+
+        if (isBer)
+        {
+            return new BERSequence(v);
+        }
+        else
+        {
+            return new DLSequence(v);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CRLBag.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CRLBag.java
new file mode 100644
index 0000000..68d6f48
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CRLBag.java
@@ -0,0 +1,88 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * CRL Bag for PKCS#12
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CRLBag
+    extends ASN1Object
+{
+    private ASN1ObjectIdentifier crlId;
+    private ASN1Encodable crlValue;
+
+    private CRLBag(
+        ASN1Sequence seq)
+    {
+        this.crlId = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+        this.crlValue = ((ASN1TaggedObject)seq.getObjectAt(1)).getObject();
+    }
+
+    public static CRLBag getInstance(Object o)
+    {
+        if (o instanceof CRLBag)
+        {
+            return (CRLBag)o;
+        }
+        else if (o != null)
+        {
+            return new CRLBag(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
+    }
+
+    public CRLBag(
+        ASN1ObjectIdentifier crlId,
+        ASN1Encodable crlValue)
+    {
+        this.crlId = crlId;
+        this.crlValue = crlValue;
+    }
+
+    public ASN1ObjectIdentifier getCrlId()
+    {
+        return crlId;
+    }
+
+    public ASN1Encodable getCrlValue()
+    {
+        return crlValue;
+    }
+
+    /**
+     * <pre>
+     * CRLBag ::= SEQUENCE {
+     * crlId  BAG-TYPE.&amp;id ({CRLTypes}),
+     * crlValue  [0] EXPLICIT BAG-TYPE.&amp;Type ({CRLTypes}{&#64;crlId})
+     * }
+     *
+     * x509CRL BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1}
+     * -- DER-encoded X.509 CRL stored in OCTET STRING
+	 *
+     * CRLTypes BAG-TYPE ::= {
+     * x509CRL,
+     * ... -- For future extensions
+     * }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(crlId);
+        v.add(new DERTaggedObject(0, crlValue));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CertBag.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CertBag.java
new file mode 100644
index 0000000..70ba105
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CertBag.java
@@ -0,0 +1,70 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CertBag
+    extends ASN1Object
+{
+    private ASN1ObjectIdentifier certId;
+    private ASN1Encodable certValue;
+
+    private CertBag(
+        ASN1Sequence    seq)
+    {
+        this.certId = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+        this.certValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject();
+    }
+
+    public static CertBag getInstance(Object o)
+    {
+        if (o instanceof CertBag)
+        {
+            return (CertBag)o;
+        }
+        else if (o != null)
+        {
+            return new CertBag(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
+    }
+
+    public CertBag(
+        ASN1ObjectIdentifier certId,
+        ASN1Encodable        certValue)
+    {
+        this.certId = certId;
+        this.certValue = certValue;
+    }
+
+    public ASN1ObjectIdentifier getCertId()
+    {
+        return certId;
+    }
+
+    public ASN1Encodable getCertValue()
+    {
+        return certValue;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(certId);
+        v.add(new DERTaggedObject(0, certValue));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CertificationRequest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CertificationRequest.java
new file mode 100644
index 0000000..8f1db49
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CertificationRequest.java
@@ -0,0 +1,96 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * PKCS10 Certification request object.
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ *   certificationRequestInfo  CertificationRequestInfo,
+ *   signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+ *   signature                 BIT STRING
+ * }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CertificationRequest
+    extends ASN1Object
+{
+    protected CertificationRequestInfo reqInfo = null;
+    protected AlgorithmIdentifier sigAlgId = null;
+    protected DERBitString sigBits = null;
+
+    public static CertificationRequest getInstance(Object o)
+    {
+        if (o instanceof CertificationRequest)
+        {
+            return (CertificationRequest)o;
+        }
+
+        if (o != null)
+        {
+            return new CertificationRequest(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
+    }
+
+    protected CertificationRequest()
+    {
+    }
+
+    public CertificationRequest(
+        CertificationRequestInfo requestInfo,
+        AlgorithmIdentifier     algorithm,
+        DERBitString            signature)
+    {
+        this.reqInfo = requestInfo;
+        this.sigAlgId = algorithm;
+        this.sigBits = signature;
+    }
+
+    /**
+     * @deprecated use getInstance()
+     */
+    public CertificationRequest(
+        ASN1Sequence seq)
+    {
+        reqInfo = CertificationRequestInfo.getInstance(seq.getObjectAt(0));
+        sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+        sigBits = (DERBitString)seq.getObjectAt(2);
+    }
+
+    public CertificationRequestInfo getCertificationRequestInfo()
+    {
+        return reqInfo;
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return sigAlgId;
+    }
+
+    public DERBitString getSignature()
+    {
+        return sigBits;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        // Construct the CertificateRequest
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(reqInfo);
+        v.add(sigAlgId);
+        v.add(sigBits);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
new file mode 100644
index 0000000..20f206c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
@@ -0,0 +1,186 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Name;
+
+/**
+ * PKCS10 CertificationRequestInfo object.
+ * <pre>
+ *  CertificationRequestInfo ::= SEQUENCE {
+ *   version             INTEGER { v1(0) } (v1,...),
+ *   subject             Name,
+ *   subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ *   attributes          [0] Attributes{{ CRIAttributes }}
+ *  }
+ *
+ *  Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
+ *
+ *  Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
+ *    type    ATTRIBUTE.&amp;id({IOSet}),
+ *    values  SET SIZE(1..MAX) OF ATTRIBUTE.&amp;Type({IOSet}{\@type})
+ *  }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CertificationRequestInfo
+    extends ASN1Object
+{
+    ASN1Integer              version = new ASN1Integer(0);
+    X500Name                subject;
+    SubjectPublicKeyInfo    subjectPKInfo;
+    ASN1Set                 attributes = null;
+
+    public static CertificationRequestInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof CertificationRequestInfo)
+        {
+            return (CertificationRequestInfo)obj;
+        }
+        else if (obj != null)
+        {
+            return new CertificationRequestInfo(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * Basic constructor.
+     * <p>
+     * Note: Early on a lot of CAs would only accept messages with attributes missing. As the ASN.1 def shows
+     * the attributes field is not optional so should always at least contain an empty set. If a fully compliant
+     * request is required, pass in an empty set, the class will otherwise interpret a null as it should
+     * encode the request with the field missing.
+     * </p>
+     *
+     * @param subject subject to be associated with the public key
+     * @param pkInfo public key to be associated with subject
+     * @param attributes any attributes to be associated with the request.
+     */
+    public CertificationRequestInfo(
+        X500Name                subject,
+        SubjectPublicKeyInfo    pkInfo,
+        ASN1Set                 attributes)
+    {
+        if ((subject == null) || (pkInfo == null))
+        {
+            throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator.");
+        }
+
+        validateAttributes(attributes);
+
+        this.subject = subject;
+        this.subjectPKInfo = pkInfo;
+        this.attributes = attributes;
+    }
+
+    /**
+     * @deprecated use X500Name method.
+     */
+    public CertificationRequestInfo(
+        X509Name                subject,
+        SubjectPublicKeyInfo    pkInfo,
+        ASN1Set                 attributes)
+    {
+        this(X500Name.getInstance(subject.toASN1Primitive()), pkInfo, attributes);
+    }
+
+    /**
+     * @deprecated use getInstance().
+     */
+    public CertificationRequestInfo(
+        ASN1Sequence  seq)
+    {
+        version = (ASN1Integer)seq.getObjectAt(0);
+
+        subject = X500Name.getInstance(seq.getObjectAt(1));
+        subjectPKInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(2));
+
+        //
+        // some CertificationRequestInfo objects seem to treat this field
+        // as optional.
+        //
+        if (seq.size() > 3)
+        {
+            ASN1TaggedObject tagobj = (ASN1TaggedObject)seq.getObjectAt(3);
+            attributes = ASN1Set.getInstance(tagobj, false);
+        }
+
+        validateAttributes(attributes);
+
+        if ((subject == null) || (version == null) || (subjectPKInfo == null))
+        {
+            throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator.");
+        }
+    }
+
+    public ASN1Integer getVersion()
+    {
+        return version;
+    }
+
+    public X500Name getSubject()
+    {
+        return subject;
+    }
+
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+    {
+        return subjectPKInfo;
+    }
+
+    public ASN1Set getAttributes()
+    {
+        return attributes;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(subject);
+        v.add(subjectPKInfo);
+
+        if (attributes != null)
+        {
+            v.add(new DERTaggedObject(false, 0, attributes));
+        }
+
+        return new DERSequence(v);
+    }
+
+    private static void validateAttributes(ASN1Set attributes)
+    {
+        if (attributes == null)
+        {
+            return;
+        }
+
+        for (Enumeration en = attributes.getObjects(); en.hasMoreElements();)
+        {
+            Attribute attr = Attribute.getInstance(en.nextElement());
+            if (attr.getAttrType().equals(PKCSObjectIdentifiers.pkcs_9_at_challengePassword))
+            {
+                if (attr.getAttrValues().size() != 1)
+                {
+                    throw new IllegalArgumentException("challengePassword attribute must have one value");
+                }
+            }
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/ContentInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/ContentInfo.java
new file mode 100644
index 0000000..0ee82e0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/ContentInfo.java
@@ -0,0 +1,106 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.BERSequence;
+import com.android.internal.org.bouncycastle.asn1.BERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DLSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ContentInfo
+    extends ASN1Object
+    implements PKCSObjectIdentifiers
+{
+    private ASN1ObjectIdentifier contentType;
+    private ASN1Encodable content;
+    private boolean       isBer = true;
+
+    public static ContentInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof ContentInfo)
+        {
+            return (ContentInfo)obj;
+        }
+
+        if (obj != null)
+        {
+            return new ContentInfo(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private ContentInfo(
+        ASN1Sequence  seq)
+    {
+        Enumeration   e = seq.getObjects();
+
+        contentType = (ASN1ObjectIdentifier)e.nextElement();
+
+        if (e.hasMoreElements())
+        {
+            content = ((ASN1TaggedObject)e.nextElement()).getObject();
+        }
+
+        isBer = seq instanceof BERSequence;
+    }
+
+    public ContentInfo(
+        ASN1ObjectIdentifier contentType,
+        ASN1Encodable content)
+    {
+        this.contentType = contentType;
+        this.content = content;
+    }
+
+    public ASN1ObjectIdentifier getContentType()
+    {
+        return contentType;
+    }
+
+    public ASN1Encodable getContent()
+    {
+        return content;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * ContentInfo ::= SEQUENCE {
+     *          contentType ContentType,
+     *          content
+     *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(contentType);
+
+        if (content != null)
+        {
+            v.add(new BERTaggedObject(true, 0, content));
+        }
+
+        if (isBer)
+        {
+            return new BERSequence(v);
+        }
+        else
+        {
+            return new DLSequence(v);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/DHParameter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/DHParameter.java
new file mode 100644
index 0000000..196c5a9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/DHParameter.java
@@ -0,0 +1,108 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHParameter
+    extends ASN1Object
+{
+    ASN1Integer      p, g, l;
+
+    public DHParameter(
+        BigInteger  p,
+        BigInteger  g,
+        int         l)
+    {
+        this.p = new ASN1Integer(p);
+        this.g = new ASN1Integer(g);
+
+        if (l != 0)
+        {
+            this.l = new ASN1Integer(l);
+        }
+        else
+        {
+            this.l = null;
+        }
+    }
+
+    public static DHParameter getInstance(
+        Object  obj)
+    {
+        if (obj instanceof DHParameter)
+        {
+            return (DHParameter)obj;
+        }
+
+        if (obj != null)
+        {
+            return new DHParameter(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private DHParameter(
+        ASN1Sequence  seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        p = ASN1Integer.getInstance(e.nextElement());
+        g = ASN1Integer.getInstance(e.nextElement());
+
+        if (e.hasMoreElements())
+        {
+            l = (ASN1Integer)e.nextElement();
+        }
+        else
+        {
+            l = null;
+        }
+    }
+
+    public BigInteger getP()
+    {
+        return p.getPositiveValue();
+    }
+
+    public BigInteger getG()
+    {
+        return g.getPositiveValue();
+    }
+
+    public BigInteger getL()
+    {
+        if (l == null)
+        {
+            return null;
+        }
+
+        return l.getPositiveValue();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(p);
+        v.add(g);
+
+        if (this.getL() != null)
+        {
+            v.add(l);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/EncryptedData.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/EncryptedData.java
new file mode 100644
index 0000000..d9eb025
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/EncryptedData.java
@@ -0,0 +1,115 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.BERSequence;
+import com.android.internal.org.bouncycastle.asn1.BERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * The EncryptedData object.
+ * <pre>
+ *      EncryptedData ::= SEQUENCE {
+ *           version Version,
+ *           encryptedContentInfo EncryptedContentInfo
+ *      }
+ *
+ *
+ *      EncryptedContentInfo ::= SEQUENCE {
+ *          contentType ContentType,
+ *          contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier,
+ *          encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ *    }
+ *
+ *    EncryptedContent ::= OCTET STRING
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class EncryptedData
+    extends ASN1Object
+{
+    ASN1Sequence                data;
+
+    public static EncryptedData getInstance(
+         Object  obj)
+    {
+         if (obj instanceof EncryptedData)
+         {
+             return (EncryptedData)obj;
+         }
+
+         if (obj != null)
+         {
+             return new EncryptedData(ASN1Sequence.getInstance(obj));
+         }
+
+         return null;
+    }
+     
+    private EncryptedData(
+        ASN1Sequence seq)
+    {
+        int version = ((ASN1Integer)seq.getObjectAt(0)).getValue().intValue();
+
+        if (version != 0)
+        {
+            throw new IllegalArgumentException("sequence not version 0");
+        }
+
+        this.data = ASN1Sequence.getInstance(seq.getObjectAt(1));
+    }
+
+    public EncryptedData(
+        ASN1ObjectIdentifier contentType,
+        AlgorithmIdentifier     encryptionAlgorithm,
+        ASN1Encodable content)
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(contentType);
+        v.add(encryptionAlgorithm.toASN1Primitive());
+        v.add(new BERTaggedObject(false, 0, content));
+
+        data = new BERSequence(v);
+    }
+        
+    public ASN1ObjectIdentifier getContentType()
+    {
+        return ASN1ObjectIdentifier.getInstance(data.getObjectAt(0));
+    }
+
+    public AlgorithmIdentifier getEncryptionAlgorithm()
+    {
+        return AlgorithmIdentifier.getInstance(data.getObjectAt(1));
+    }
+
+    public ASN1OctetString getContent()
+    {
+        if (data.size() == 3)
+        {
+            ASN1TaggedObject o = ASN1TaggedObject.getInstance(data.getObjectAt(2));
+
+            return ASN1OctetString.getInstance(o, false);
+        }
+
+        return null;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(0));
+        v.add(data);
+
+        return new BERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
new file mode 100644
index 0000000..ec73cbe
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
@@ -0,0 +1,90 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class EncryptedPrivateKeyInfo
+    extends ASN1Object
+{
+    private AlgorithmIdentifier algId;
+    private ASN1OctetString     data;
+
+    private EncryptedPrivateKeyInfo(
+        ASN1Sequence  seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        algId = AlgorithmIdentifier.getInstance(e.nextElement());
+        data = ASN1OctetString.getInstance(e.nextElement());
+    }
+
+    public EncryptedPrivateKeyInfo(
+        AlgorithmIdentifier algId,
+        byte[]              encoding)
+    {
+        this.algId = algId;
+        this.data = new DEROctetString(encoding);
+    }
+
+    public static EncryptedPrivateKeyInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof EncryptedPrivateKeyInfo)
+        {
+            return (EncryptedPrivateKeyInfo)obj;
+        }
+        else if (obj != null)
+        { 
+            return new EncryptedPrivateKeyInfo(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+    
+    public AlgorithmIdentifier getEncryptionAlgorithm()
+    {
+        return algId;
+    }
+
+    public byte[] getEncryptedData()
+    {
+        return data.getOctets();
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * EncryptedPrivateKeyInfo ::= SEQUENCE {
+     *      encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}},
+     *      encryptedData EncryptedData
+     * }
+     *
+     * EncryptedData ::= OCTET STRING
+     *
+     * KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= {
+     *          ... -- For local profiles
+     * }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(algId);
+        v.add(data);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/EncryptionScheme.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
new file mode 100644
index 0000000..4ebcb91
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
@@ -0,0 +1,66 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class EncryptionScheme
+    extends ASN1Object
+{
+    private AlgorithmIdentifier algId;
+
+    public EncryptionScheme(
+        ASN1ObjectIdentifier objectId)
+    {
+        this.algId = new AlgorithmIdentifier(objectId);
+    }
+
+    public EncryptionScheme(
+        ASN1ObjectIdentifier objectId,
+        ASN1Encodable parameters)
+    {
+        this.algId = new AlgorithmIdentifier(objectId, parameters);
+    }
+
+    private EncryptionScheme(
+        ASN1Sequence  seq)
+    {   
+        this.algId = AlgorithmIdentifier.getInstance(seq);
+    }
+
+    public static EncryptionScheme getInstance(Object obj)
+    {
+        if (obj instanceof EncryptionScheme)
+        {
+            return (EncryptionScheme)obj;
+        }
+        else if (obj != null)
+        {
+            return new EncryptionScheme(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public ASN1ObjectIdentifier getAlgorithm()
+    {
+        return algId.getAlgorithm();
+    }
+
+    public ASN1Encodable getParameters()
+    {
+        return algId.getParameters();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return algId.toASN1Primitive();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java
new file mode 100644
index 0000000..00e9880
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java
@@ -0,0 +1,89 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Name;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class IssuerAndSerialNumber
+    extends ASN1Object
+{
+    X500Name name;
+    ASN1Integer  certSerialNumber;
+
+    public static IssuerAndSerialNumber getInstance(
+        Object  obj)
+    {
+        if (obj instanceof IssuerAndSerialNumber)
+        {
+            return (IssuerAndSerialNumber)obj;
+        }
+        else if (obj != null)
+        {
+            return new IssuerAndSerialNumber(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private IssuerAndSerialNumber(
+        ASN1Sequence    seq)
+    {
+        this.name = X500Name.getInstance(seq.getObjectAt(0));
+        this.certSerialNumber = (ASN1Integer)seq.getObjectAt(1);
+    }
+
+    public IssuerAndSerialNumber(
+        X509Name    name,
+        BigInteger  certSerialNumber)
+    {
+        this.name = X500Name.getInstance(name.toASN1Primitive());
+        this.certSerialNumber = new ASN1Integer(certSerialNumber);
+    }
+
+    public IssuerAndSerialNumber(
+        X509Name    name,
+        ASN1Integer  certSerialNumber)
+    {
+        this.name = X500Name.getInstance(name.toASN1Primitive());
+        this.certSerialNumber = certSerialNumber;
+    }
+
+    public IssuerAndSerialNumber(
+        X500Name    name,
+        BigInteger  certSerialNumber)
+    {
+        this.name = name;
+        this.certSerialNumber = new ASN1Integer(certSerialNumber);
+    }
+
+    public X500Name getName()
+    {
+        return name;
+    }
+
+    public ASN1Integer getCertificateSerialNumber()
+    {
+        return certSerialNumber;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(name);
+        v.add(certSerialNumber);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
new file mode 100644
index 0000000..3e5fe90
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyDerivationFunc
+    extends ASN1Object
+{
+    private AlgorithmIdentifier algId;
+
+    public KeyDerivationFunc(
+        ASN1ObjectIdentifier objectId,
+        ASN1Encodable parameters)
+    {
+        this.algId = new AlgorithmIdentifier(objectId, parameters);
+    }
+
+    private KeyDerivationFunc(
+        ASN1Sequence seq)
+    {
+        this.algId = AlgorithmIdentifier.getInstance(seq);
+    }
+
+    public static KeyDerivationFunc getInstance(Object obj)
+    {
+        if (obj instanceof KeyDerivationFunc)
+        {
+            return (KeyDerivationFunc)obj;
+        }
+        else if (obj != null)
+        {
+            return new KeyDerivationFunc(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public ASN1ObjectIdentifier getAlgorithm()
+    {
+        return algId.getAlgorithm();
+    }
+
+    public ASN1Encodable getParameters()
+    {
+        return algId.getParameters();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return algId.toASN1Primitive();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/MacData.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/MacData.java
new file mode 100644
index 0000000..6850543
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/MacData.java
@@ -0,0 +1,111 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x509.DigestInfo;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class MacData
+    extends ASN1Object
+{
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+
+    DigestInfo                  digInfo;
+    byte[]                      salt;
+    BigInteger                  iterationCount;
+
+    public static MacData getInstance(
+        Object  obj)
+    {
+        if (obj instanceof MacData)
+        {
+            return (MacData)obj;
+        }
+        else if (obj != null)
+        {
+            return new MacData(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private MacData(
+        ASN1Sequence seq)
+    {
+        this.digInfo = DigestInfo.getInstance(seq.getObjectAt(0));
+
+        this.salt = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets());
+
+        if (seq.size() == 3)
+        {
+            this.iterationCount = ASN1Integer.getInstance(seq.getObjectAt(2)).getValue();
+        }
+        else
+        {
+            this.iterationCount = ONE;
+        }
+    }
+
+    public MacData(
+        DigestInfo  digInfo,
+        byte[]      salt,
+        int         iterationCount)
+    {
+        this.digInfo = digInfo;
+        this.salt = Arrays.clone(salt);
+        this.iterationCount = BigInteger.valueOf(iterationCount);
+    }
+
+    public DigestInfo getMac()
+    {
+        return digInfo;
+    }
+
+    public byte[] getSalt()
+    {
+        return Arrays.clone(salt);
+    }
+
+    public BigInteger getIterationCount()
+    {
+        return iterationCount;
+    }
+
+    /**
+     * <pre>
+     * MacData ::= SEQUENCE {
+     *     mac      DigestInfo,
+     *     macSalt  OCTET STRING,
+     *     iterations INTEGER DEFAULT 1
+     *     -- Note: The default is for historic reasons and its use is deprecated. A
+     *     -- higher value, like 1024 is recommended.
+     * </pre>
+     * @return the basic ASN1Primitive construction.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(digInfo);
+        v.add(new DEROctetString(salt));
+        
+        if (!iterationCount.equals(ONE))
+        {
+            v.add(new ASN1Integer(iterationCount));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PBEParameter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PBEParameter.java
new file mode 100644
index 0000000..9cfd35d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PBEParameter.java
@@ -0,0 +1,77 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PBEParameter
+    extends ASN1Object
+{
+    ASN1Integer      iterations;
+    ASN1OctetString salt;
+
+    public PBEParameter(
+        byte[]      salt,
+        int         iterations)
+    {
+        if (salt.length != 8)
+        {
+            throw new IllegalArgumentException("salt length must be 8");
+        }
+        this.salt = new DEROctetString(salt);
+        this.iterations = new ASN1Integer(iterations);
+    }
+
+    private PBEParameter(
+        ASN1Sequence  seq)
+    {
+        salt = (ASN1OctetString)seq.getObjectAt(0);
+        iterations = (ASN1Integer)seq.getObjectAt(1);
+    }
+
+    public static PBEParameter getInstance(
+        Object  obj)
+    {
+        if (obj instanceof PBEParameter)
+        {
+            return (PBEParameter)obj;
+        }
+        else if (obj != null)
+        {
+            return new PBEParameter(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public BigInteger getIterationCount()
+    {
+        return iterations.getValue();
+    }
+
+    public byte[] getSalt()
+    {
+        return salt.getOctets();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(salt);
+        v.add(iterations);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PBES2Parameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
new file mode 100644
index 0000000..5be343a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
@@ -0,0 +1,81 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PBES2Parameters
+    extends ASN1Object
+    implements PKCSObjectIdentifiers
+{
+    private KeyDerivationFunc func;
+    private EncryptionScheme scheme;
+
+    public static PBES2Parameters getInstance(
+        Object  obj)
+    {
+        if (obj instanceof PBES2Parameters)
+        {
+            return (PBES2Parameters)obj;
+        }
+        if (obj != null)
+        {
+            return new PBES2Parameters(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public PBES2Parameters(KeyDerivationFunc keyDevFunc, EncryptionScheme encScheme)
+    {
+        this.func = keyDevFunc;
+        this.scheme = encScheme;
+    }
+
+    private PBES2Parameters(
+        ASN1Sequence  obj)
+    {
+        Enumeration e = obj.getObjects();
+        ASN1Sequence  funcSeq = ASN1Sequence.getInstance(((ASN1Encodable)e.nextElement()).toASN1Primitive());
+
+        if (funcSeq.getObjectAt(0).equals(id_PBKDF2))
+        {
+            func = new KeyDerivationFunc(id_PBKDF2, PBKDF2Params.getInstance(funcSeq.getObjectAt(1)));
+        }
+        else
+        {
+            func = KeyDerivationFunc.getInstance(funcSeq);
+        }
+
+        scheme = EncryptionScheme.getInstance(e.nextElement());
+    }
+
+    public KeyDerivationFunc getKeyDerivationFunc()
+    {
+        return func;
+    }
+
+    public EncryptionScheme getEncryptionScheme()
+    {
+        return scheme;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(func);
+        v.add(scheme);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PBKDF2Params.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
new file mode 100644
index 0000000..ce632e7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
@@ -0,0 +1,265 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * <pre>
+ *     PBKDF2-params ::= SEQUENCE {
+ *               salt CHOICE {
+ *                      specified OCTET STRING,
+ *                      otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+ *               },
+ *              iterationCount INTEGER (1..MAX),
+ *              keyLength INTEGER (1..MAX) OPTIONAL,
+ *              prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PBKDF2Params
+    extends ASN1Object
+{
+    private static final AlgorithmIdentifier algid_hmacWithSHA1 = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA1, DERNull.INSTANCE);
+
+    private final ASN1OctetString octStr;
+    private final ASN1Integer iterationCount;
+    private final ASN1Integer keyLength;
+    private final AlgorithmIdentifier prf;
+
+    /**
+     * Create PBKDF2Params from the passed in object,
+     *
+     * @param obj either PBKDF2Params or an ASN1Sequence.
+     * @return a PBKDF2Params instance.
+     */
+    public static PBKDF2Params getInstance(
+        Object obj)
+    {
+        if (obj instanceof PBKDF2Params)
+        {
+            return (PBKDF2Params)obj;
+        }
+
+        if (obj != null)
+        {
+            return new PBKDF2Params(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * Create a PBKDF2Params with the specified salt, iteration count, and algid-hmacWithSHA1 for the prf.
+     *
+     * @param salt           input salt.
+     * @param iterationCount input iteration count.
+     */
+    public PBKDF2Params(
+        byte[] salt,
+        int iterationCount)
+    {
+        this(salt, iterationCount, 0);
+    }
+
+    /**
+     * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and algid-hmacWithSHA1 for the prf.
+     *
+     * @param salt           input salt.
+     * @param iterationCount input iteration count.
+     * @param keyLength      intended key length to be produced.
+     */
+    public PBKDF2Params(
+        byte[] salt,
+        int iterationCount,
+        int keyLength)
+    {
+        this(salt, iterationCount, keyLength, null);
+    }
+
+    /**
+     * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and a defined prf.
+     *
+     * @param salt           input salt.
+     * @param iterationCount input iteration count.
+     * @param keyLength      intended key length to be produced.
+     * @param prf            the pseudo-random function to use.
+     */
+    public PBKDF2Params(
+        byte[] salt,
+        int iterationCount,
+        int keyLength,
+        AlgorithmIdentifier prf)
+    {
+        this.octStr = new DEROctetString(Arrays.clone(salt));
+        this.iterationCount = new ASN1Integer(iterationCount);
+
+        if (keyLength > 0)
+        {
+            this.keyLength = new ASN1Integer(keyLength);
+        }
+        else
+        {
+            this.keyLength = null;
+        }
+
+        this.prf = prf;
+    }
+
+    /**
+     * Create a PBKDF2Params with the specified salt, iteration count, and a defined prf.
+     *
+     * @param salt           input salt.
+     * @param iterationCount input iteration count.
+     * @param prf            the pseudo-random function to use.
+     */
+    public PBKDF2Params(
+        byte[] salt,
+        int iterationCount,
+        AlgorithmIdentifier prf)
+    {
+        this(salt, iterationCount, 0, prf);
+    }
+
+    private PBKDF2Params(
+        ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        octStr = (ASN1OctetString)e.nextElement();
+        iterationCount = (ASN1Integer)e.nextElement();
+
+        if (e.hasMoreElements())
+        {
+            Object o = e.nextElement();
+
+            if (o instanceof ASN1Integer)
+            {
+                keyLength = ASN1Integer.getInstance(o);
+                if (e.hasMoreElements())
+                {
+                    o = e.nextElement();
+                }
+                else
+                {
+                    o = null;
+                }
+            }
+            else
+            {
+                keyLength = null;
+            }
+
+            if (o != null)
+            {
+                prf = AlgorithmIdentifier.getInstance(o);
+            }
+            else
+            {
+                prf = null;
+            }
+        }
+        else
+        {
+            keyLength = null;
+            prf = null;
+        }
+    }
+
+    /**
+     * Return the salt to use.
+     *
+     * @return the input salt.
+     */
+    public byte[] getSalt()
+    {
+        return octStr.getOctets();
+    }
+
+    /**
+     * Return the iteration count to use.
+     *
+     * @return the input iteration count.
+     */
+    public BigInteger getIterationCount()
+    {
+        return iterationCount.getValue();
+    }
+
+    /**
+     * Return the intended length in octets of the derived key.
+     *
+     * @return length in octets for derived key, if specified.
+     */
+    public BigInteger getKeyLength()
+    {
+        if (keyLength != null)
+        {
+            return keyLength.getValue();
+        }
+
+        return null;
+    }
+
+    /**
+     * Return true if the PRF is the default (hmacWithSHA1)
+     *
+     * @return true if PRF is default, false otherwise.
+     */
+    public boolean isDefaultPrf()
+    {
+        return prf == null || prf.equals(algid_hmacWithSHA1);
+    }
+
+    /**
+     * Return the algId of the underlying pseudo random function to use.
+     *
+     * @return the prf algorithm identifier.
+     */
+    public AlgorithmIdentifier getPrf()
+    {
+        if (prf != null)
+        {
+            return prf;
+        }
+
+        return algid_hmacWithSHA1;
+    }
+
+    /**
+     * Return an ASN.1 structure suitable for encoding.
+     *
+     * @return the object as an ASN.1 encodable structure.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(octStr);
+        v.add(iterationCount);
+
+        if (keyLength != null)
+        {
+            v.add(keyLength);
+        }
+
+        if (prf != null && !prf.equals(algid_hmacWithSHA1))
+        {
+            v.add(prf);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java
new file mode 100644
index 0000000..21ccc37
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java
@@ -0,0 +1,73 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS12PBEParams
+    extends ASN1Object
+{
+    ASN1Integer      iterations;
+    ASN1OctetString iv;
+
+    public PKCS12PBEParams(
+        byte[]      salt,
+        int         iterations)
+    {
+        this.iv = new DEROctetString(salt);
+        this.iterations = new ASN1Integer(iterations);
+    }
+
+    private PKCS12PBEParams(
+        ASN1Sequence  seq)
+    {
+        iv = (ASN1OctetString)seq.getObjectAt(0);
+        iterations = ASN1Integer.getInstance(seq.getObjectAt(1));
+    }
+
+    public static PKCS12PBEParams getInstance(
+        Object  obj)
+    {
+        if (obj instanceof PKCS12PBEParams)
+        {
+            return (PKCS12PBEParams)obj;
+        }
+        else if (obj != null)
+        {
+            return new PKCS12PBEParams(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public BigInteger getIterations()
+    {
+        return iterations.getValue();
+    }
+
+    public byte[] getIV()
+    {
+        return iv.getOctets();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(iv);
+        v.add(iterations);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
new file mode 100644
index 0000000..af8a630
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
@@ -0,0 +1,438 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * pkcs-1 OBJECT IDENTIFIER ::=<p>
+ *   { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+ * @hide This class is not part of the Android public SDK API
+ *
+ */
+public interface PKCSObjectIdentifiers
+{
+    /** PKCS#1: 1.2.840.113549.1.1 */
+    ASN1ObjectIdentifier    pkcs_1                    = new ASN1ObjectIdentifier("1.2.840.113549.1.1");
+    /** PKCS#1: 1.2.840.113549.1.1.1 */
+    ASN1ObjectIdentifier    rsaEncryption             = pkcs_1.branch("1");
+    // BEGIN Android-removed: MD2 and MD4 are unsupported
+    /*
+    /** PKCS#1: 1.2.840.113549.1.1.2 *
+    ASN1ObjectIdentifier    md2WithRSAEncryption      = pkcs_1.branch("2");
+    /** PKCS#1: 1.2.840.113549.1.1.3 *
+    ASN1ObjectIdentifier    md4WithRSAEncryption      = pkcs_1.branch("3");
+    */
+    // END Android-removed: MD2 and MD4 are unsupported
+    /** PKCS#1: 1.2.840.113549.1.1.4 */
+    ASN1ObjectIdentifier    md5WithRSAEncryption      = pkcs_1.branch("4");
+    /** PKCS#1: 1.2.840.113549.1.1.5 */
+    ASN1ObjectIdentifier    sha1WithRSAEncryption     = pkcs_1.branch("5");
+    /** PKCS#1: 1.2.840.113549.1.1.6 */
+    ASN1ObjectIdentifier    srsaOAEPEncryptionSET     = pkcs_1.branch("6");
+    /** PKCS#1: 1.2.840.113549.1.1.7 */
+    ASN1ObjectIdentifier    id_RSAES_OAEP             = pkcs_1.branch("7");
+    /** PKCS#1: 1.2.840.113549.1.1.8 */
+    ASN1ObjectIdentifier    id_mgf1                   = pkcs_1.branch("8");
+    /** PKCS#1: 1.2.840.113549.1.1.9 */
+    ASN1ObjectIdentifier    id_pSpecified             = pkcs_1.branch("9");
+    /** PKCS#1: 1.2.840.113549.1.1.10 */
+    ASN1ObjectIdentifier    id_RSASSA_PSS             = pkcs_1.branch("10");
+    /** PKCS#1: 1.2.840.113549.1.1.11 */
+    ASN1ObjectIdentifier    sha256WithRSAEncryption   = pkcs_1.branch("11");
+    /** PKCS#1: 1.2.840.113549.1.1.12 */
+    ASN1ObjectIdentifier    sha384WithRSAEncryption   = pkcs_1.branch("12");
+    /** PKCS#1: 1.2.840.113549.1.1.13 */
+    ASN1ObjectIdentifier    sha512WithRSAEncryption   = pkcs_1.branch("13");
+    /** PKCS#1: 1.2.840.113549.1.1.14 */
+    ASN1ObjectIdentifier    sha224WithRSAEncryption   = pkcs_1.branch("14");
+    /** PKCS#1: 1.2.840.113549.1.1.15 */
+    ASN1ObjectIdentifier    sha512_224WithRSAEncryption   = pkcs_1.branch("15");
+    /** PKCS#1: 1.2.840.113549.1.1.16 */
+    ASN1ObjectIdentifier    sha512_256WithRSAEncryption   = pkcs_1.branch("16");
+
+    //
+    // pkcs-3 OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 }
+    //
+    /** PKCS#3: 1.2.840.113549.1.3 */
+    ASN1ObjectIdentifier    pkcs_3                  = new ASN1ObjectIdentifier("1.2.840.113549.1.3");
+    /** PKCS#3: 1.2.840.113549.1.3.1 */
+    ASN1ObjectIdentifier    dhKeyAgreement          = pkcs_3.branch("1");
+
+    //
+    // pkcs-5 OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 }
+    //
+    /** PKCS#5: 1.2.840.113549.1.5 */
+    ASN1ObjectIdentifier    pkcs_5                  = new ASN1ObjectIdentifier("1.2.840.113549.1.5");
+
+    /** PKCS#5: 1.2.840.113549.1.5.1 */
+    ASN1ObjectIdentifier    pbeWithMD2AndDES_CBC    = pkcs_5.branch("1");
+    /** PKCS#5: 1.2.840.113549.1.5.4 */
+    ASN1ObjectIdentifier    pbeWithMD2AndRC2_CBC    = pkcs_5.branch("4");
+    /** PKCS#5: 1.2.840.113549.1.5.3 */
+    ASN1ObjectIdentifier    pbeWithMD5AndDES_CBC    = pkcs_5.branch("3");
+    /** PKCS#5: 1.2.840.113549.1.5.6 */
+    ASN1ObjectIdentifier    pbeWithMD5AndRC2_CBC    = pkcs_5.branch("6");
+    /** PKCS#5: 1.2.840.113549.1.5.10 */
+    ASN1ObjectIdentifier    pbeWithSHA1AndDES_CBC   = pkcs_5.branch("10");
+    /** PKCS#5: 1.2.840.113549.1.5.11 */
+    ASN1ObjectIdentifier    pbeWithSHA1AndRC2_CBC   = pkcs_5.branch("11");
+    /** PKCS#5: 1.2.840.113549.1.5.13 */
+    ASN1ObjectIdentifier    id_PBES2                = pkcs_5.branch("13");
+    /** PKCS#5: 1.2.840.113549.1.5.12 */
+    ASN1ObjectIdentifier    id_PBKDF2               = pkcs_5.branch("12");
+
+    //
+    // encryptionAlgorithm OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) 3 }
+    //
+    /**  1.2.840.113549.3 */
+    ASN1ObjectIdentifier    encryptionAlgorithm     = new ASN1ObjectIdentifier("1.2.840.113549.3");
+
+    /**  1.2.840.113549.3.7 */
+    ASN1ObjectIdentifier    des_EDE3_CBC            = encryptionAlgorithm.branch("7");
+    /**  1.2.840.113549.3.2 */
+    ASN1ObjectIdentifier    RC2_CBC                 = encryptionAlgorithm.branch("2");
+    /**  1.2.840.113549.3.4 */
+    ASN1ObjectIdentifier    rc4                     = encryptionAlgorithm.branch("4");
+
+    //
+    // object identifiers for digests
+    //
+    /**  1.2.840.113549.2 */
+    ASN1ObjectIdentifier    digestAlgorithm        = new ASN1ObjectIdentifier("1.2.840.113549.2");
+    //
+    // md2 OBJECT IDENTIFIER ::=
+    //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2}
+    //
+    // BEGIN android-removed
+    // /**  1.2.840.113549.2.2 */
+    // ASN1ObjectIdentifier    md2                    = digestAlgorithm.branch("2");
+    // END android-removed
+
+    //
+    // md4 OBJECT IDENTIFIER ::=
+    //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4}
+    //
+    // BEGIN android-removed
+    // /**  1.2.840.113549.2.4 */
+    // ASN1ObjectIdentifier    md4                    = digestAlgorithm.branch("4");
+    // END android-removed
+
+    //
+    // md5 OBJECT IDENTIFIER ::=
+    //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}
+    //
+    /**  1.2.840.113549.2.5 */
+    ASN1ObjectIdentifier    md5                    = digestAlgorithm.branch("5");
+
+    /**  1.2.840.113549.2.7 */
+    ASN1ObjectIdentifier    id_hmacWithSHA1        = digestAlgorithm.branch("7").intern();
+    /**  1.2.840.113549.2.8 */
+    ASN1ObjectIdentifier    id_hmacWithSHA224      = digestAlgorithm.branch("8").intern();
+    /**  1.2.840.113549.2.9 */
+    ASN1ObjectIdentifier    id_hmacWithSHA256      = digestAlgorithm.branch("9").intern();
+    /**  1.2.840.113549.2.10 */
+    ASN1ObjectIdentifier    id_hmacWithSHA384      = digestAlgorithm.branch("10").intern();
+    /**  1.2.840.113549.2.11 */
+    ASN1ObjectIdentifier    id_hmacWithSHA512      = digestAlgorithm.branch("11").intern();
+
+    //
+    // pkcs-7 OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 }
+    //
+    /** pkcs#7: 1.2.840.113549.1.7 */
+    ASN1ObjectIdentifier    pkcs_7                  = new ASN1ObjectIdentifier("1.2.840.113549.1.7").intern();
+    /** PKCS#7: 1.2.840.113549.1.7.1 */
+    ASN1ObjectIdentifier    data                    = new ASN1ObjectIdentifier("1.2.840.113549.1.7.1").intern();
+    /** PKCS#7: 1.2.840.113549.1.7.2 */
+    ASN1ObjectIdentifier    signedData              = new ASN1ObjectIdentifier("1.2.840.113549.1.7.2").intern();
+    /** PKCS#7: 1.2.840.113549.1.7.3 */
+    ASN1ObjectIdentifier    envelopedData           = new ASN1ObjectIdentifier("1.2.840.113549.1.7.3").intern();
+    /** PKCS#7: 1.2.840.113549.1.7.4 */
+    ASN1ObjectIdentifier    signedAndEnvelopedData  = new ASN1ObjectIdentifier("1.2.840.113549.1.7.4").intern();
+    /** PKCS#7: 1.2.840.113549.1.7.5 */
+    ASN1ObjectIdentifier    digestedData            = new ASN1ObjectIdentifier("1.2.840.113549.1.7.5").intern();
+    /** PKCS#7: 1.2.840.113549.1.7.76 */
+    ASN1ObjectIdentifier    encryptedData           = new ASN1ObjectIdentifier("1.2.840.113549.1.7.6").intern();
+
+    //
+    // pkcs-9 OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
+    //
+    /** PKCS#9: 1.2.840.113549.1.9 */
+    ASN1ObjectIdentifier    pkcs_9                  = new ASN1ObjectIdentifier("1.2.840.113549.1.9");
+
+    /** PKCS#9: 1.2.840.113549.1.9.1 */
+    ASN1ObjectIdentifier    pkcs_9_at_emailAddress        = pkcs_9.branch("1").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.2 */
+    ASN1ObjectIdentifier    pkcs_9_at_unstructuredName    = pkcs_9.branch("2").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.3 */
+    ASN1ObjectIdentifier    pkcs_9_at_contentType         = pkcs_9.branch("3").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.4 */
+    ASN1ObjectIdentifier    pkcs_9_at_messageDigest       = pkcs_9.branch("4").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.5 */
+    ASN1ObjectIdentifier    pkcs_9_at_signingTime         = pkcs_9.branch("5").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.6 */
+    ASN1ObjectIdentifier    pkcs_9_at_counterSignature    = pkcs_9.branch("6").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.7 */
+    ASN1ObjectIdentifier    pkcs_9_at_challengePassword   = pkcs_9.branch("7").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.8 */
+    ASN1ObjectIdentifier    pkcs_9_at_unstructuredAddress = pkcs_9.branch("8").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.9 */
+    ASN1ObjectIdentifier    pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9").intern();
+
+    /** PKCS#9: 1.2.840.113549.1.9.13 */
+    ASN1ObjectIdentifier    pkcs_9_at_signingDescription = pkcs_9.branch("13").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.14 */
+    ASN1ObjectIdentifier    pkcs_9_at_extensionRequest   = pkcs_9.branch("14").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.15 */
+    ASN1ObjectIdentifier    pkcs_9_at_smimeCapabilities  = pkcs_9.branch("15").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.16 */
+    ASN1ObjectIdentifier    id_smime                     = pkcs_9.branch("16").intern();
+
+    /** PKCS#9: 1.2.840.113549.1.9.20 */
+    ASN1ObjectIdentifier    pkcs_9_at_friendlyName  = pkcs_9.branch("20").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.21 */
+    ASN1ObjectIdentifier    pkcs_9_at_localKeyId    = pkcs_9.branch("21").intern();
+
+    /** PKCS#9: 1.2.840.113549.1.9.22.1
+     * @deprecated use x509Certificate instead */
+    ASN1ObjectIdentifier    x509certType            = pkcs_9.branch("22.1");
+
+    /** PKCS#9: 1.2.840.113549.1.9.22 */
+    ASN1ObjectIdentifier    certTypes               = pkcs_9.branch("22");
+    /** PKCS#9: 1.2.840.113549.1.9.22.1 */
+    ASN1ObjectIdentifier    x509Certificate         = certTypes.branch("1").intern();
+    /** PKCS#9: 1.2.840.113549.1.9.22.2 */
+    ASN1ObjectIdentifier    sdsiCertificate         = certTypes.branch("2").intern();
+
+    /** PKCS#9: 1.2.840.113549.1.9.23 */
+    ASN1ObjectIdentifier    crlTypes                = pkcs_9.branch("23");
+    /** PKCS#9: 1.2.840.113549.1.9.23.1 */
+    ASN1ObjectIdentifier    x509Crl                 = crlTypes.branch("1").intern();
+
+    /** RFC 6211 -  id-aa-cmsAlgorithmProtect OBJECT IDENTIFIER ::= {
+            iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
+            pkcs9(9) 52 }  */
+    ASN1ObjectIdentifier   id_aa_cmsAlgorithmProtect = pkcs_9.branch("52").intern();
+
+    //
+    // SMIME capability sub oids.
+    //
+    /** PKCS#9: 1.2.840.113549.1.9.15.1 -- smime capability */
+    ASN1ObjectIdentifier    preferSignedData        = pkcs_9.branch("15.1");
+    /** PKCS#9: 1.2.840.113549.1.9.15.2 -- smime capability  */
+    ASN1ObjectIdentifier    canNotDecryptAny        = pkcs_9.branch("15.2");
+    /** PKCS#9: 1.2.840.113549.1.9.15.3 -- smime capability  */
+    ASN1ObjectIdentifier    sMIMECapabilitiesVersions = pkcs_9.branch("15.3");
+
+    //
+    // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+    // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)}
+    //
+    /** PKCS#9: 1.2.840.113549.1.9.16.1 -- smime ct */
+    ASN1ObjectIdentifier    id_ct = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1");
+
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.2 -- smime ct authData */
+    ASN1ObjectIdentifier    id_ct_authData          = id_ct.branch("2");
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.4 -- smime ct TSTInfo*/
+    ASN1ObjectIdentifier    id_ct_TSTInfo           = id_ct.branch("4");
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.9 -- smime ct compressedData */
+    ASN1ObjectIdentifier    id_ct_compressedData    = id_ct.branch("9");
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.23 -- smime ct authEnvelopedData */
+    ASN1ObjectIdentifier    id_ct_authEnvelopedData = id_ct.branch("23");
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.31 -- smime ct timestampedData*/
+    ASN1ObjectIdentifier    id_ct_timestampedData   = id_ct.branch("31");
+
+
+    /** S/MIME: Algorithm Identifiers ; 1.2.840.113549.1.9.16.3 */
+    ASN1ObjectIdentifier id_alg                  = id_smime.branch("3");
+    /** PKCS#9: 1.2.840.113549.1.9.16.3.9 */
+    ASN1ObjectIdentifier id_alg_PWRI_KEK         = id_alg.branch("9");
+    /**
+     * <pre>
+     * -- RSA-KEM Key Transport Algorithm  RFC 5990
+     *
+     * id-rsa-kem OID ::= {
+     *      iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
+     *      pkcs-9(9) smime(16) alg(3) 14
+     *   }
+     * </pre>
+     */
+    ASN1ObjectIdentifier id_rsa_KEM              = id_alg.branch("14");
+
+    //
+    // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+    // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)}
+    //
+    /** PKCS#9: 1.2.840.113549.1.9.16.6 -- smime cti */
+    ASN1ObjectIdentifier    id_cti = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.6");
+    
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.1 -- smime cti proofOfOrigin */
+    ASN1ObjectIdentifier    id_cti_ets_proofOfOrigin   = id_cti.branch("1");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2 -- smime cti proofOfReceipt*/
+    ASN1ObjectIdentifier    id_cti_ets_proofOfReceipt  = id_cti.branch("2");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.3 -- smime cti proofOfDelivery */
+    ASN1ObjectIdentifier    id_cti_ets_proofOfDelivery = id_cti.branch("3");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.4 -- smime cti proofOfSender */
+    ASN1ObjectIdentifier    id_cti_ets_proofOfSender   = id_cti.branch("4");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.5 -- smime cti proofOfApproval */
+    ASN1ObjectIdentifier    id_cti_ets_proofOfApproval = id_cti.branch("5");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.6 -- smime cti proofOfCreation */
+    ASN1ObjectIdentifier    id_cti_ets_proofOfCreation = id_cti.branch("6");
+    
+    //
+    // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+    // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)}
+    //
+    /** PKCS#9: 1.2.840.113549.1.9.16.2 - smime attributes */
+    ASN1ObjectIdentifier    id_aa = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.2");
+
+
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.1 -- smime attribute receiptRequest */
+    ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch("1");
+    
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.4 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */
+    ASN1ObjectIdentifier id_aa_contentHint      = id_aa.branch("4"); // See RFC 2634
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.5 */
+    ASN1ObjectIdentifier id_aa_msgSigDigest     = id_aa.branch("5");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.10 */
+    ASN1ObjectIdentifier id_aa_contentReference = id_aa.branch("10");
+    /*
+     * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11}
+     * 
+     */
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.11 */
+    ASN1ObjectIdentifier id_aa_encrypKeyPref        = id_aa.branch("11");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.12 */
+    ASN1ObjectIdentifier id_aa_signingCertificate   = id_aa.branch("12");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.47 */
+    ASN1ObjectIdentifier id_aa_signingCertificateV2 = id_aa.branch("47");
+
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.7 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */
+    ASN1ObjectIdentifier id_aa_contentIdentifier = id_aa.branch("7"); // See RFC 2634
+
+    /*
+     * RFC 3126
+     */
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.14 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_signatureTimeStampToken = id_aa.branch("14");
+    
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.15 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_sigPolicyId = id_aa.branch("15");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.16 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_commitmentType = id_aa.branch("16");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.17 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_signerLocation = id_aa.branch("17");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.18 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_signerAttr = id_aa.branch("18");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.19 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_otherSigCert = id_aa.branch("19");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.20 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_contentTimestamp = id_aa.branch("20");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.21 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_certificateRefs = id_aa.branch("21");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.22 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_revocationRefs = id_aa.branch("22");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.23 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_certValues = id_aa.branch("23");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.24 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_revocationValues = id_aa.branch("24");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.25 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_escTimeStamp = id_aa.branch("25");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.26 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_certCRLTimestamp = id_aa.branch("26");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.27 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
+    ASN1ObjectIdentifier id_aa_ets_archiveTimestamp = id_aa.branch("27");
+
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.37 - <a href="https://tools.ietf.org/html/rfc4108#section-2.2.5">RFC 4108</a> */
+    ASN1ObjectIdentifier id_aa_decryptKeyID = id_aa.branch("37");
+
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.38 - <a href="https://tools.ietf.org/html/rfc4108#section-2.2.6">RFC 4108</a> */
+    ASN1ObjectIdentifier id_aa_implCryptoAlgs = id_aa.branch("38");
+
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.54 <a href="https://tools.ietf.org/html/rfc7030">RFC7030</a>*/
+    ASN1ObjectIdentifier id_aa_asymmDecryptKeyID = id_aa.branch("54");
+
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.43   <a href="https://tools.ietf.org/html/rfc7030">RFC7030</a>*/
+    ASN1ObjectIdentifier id_aa_implCompressAlgs = id_aa.branch("43");
+    /** PKCS#9: 1.2.840.113549.1.9.16.2.40   <a href="https://tools.ietf.org/html/rfc7030">RFC7030</a>*/
+    ASN1ObjectIdentifier id_aa_communityIdentifiers = id_aa.branch("40");
+
+    /** @deprecated use id_aa_ets_sigPolicyId instead */
+    ASN1ObjectIdentifier id_aa_sigPolicyId    = id_aa_ets_sigPolicyId;
+    /** @deprecated use id_aa_ets_commitmentType instead */
+    ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType;
+    /** @deprecated use id_aa_ets_signerLocation instead */
+    ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation;
+    /** @deprecated use id_aa_ets_otherSigCert instead */
+    ASN1ObjectIdentifier id_aa_otherSigCert   = id_aa_ets_otherSigCert;
+    
+    /**
+     * id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+     * rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)}; <p>
+     * 1.2.840.113549.1.9.16.5
+     */
+    final String id_spq = "1.2.840.113549.1.9.16.5";
+
+    /** SMIME SPQ URI:     1.2.840.113549.1.9.16.5.1 */
+    ASN1ObjectIdentifier id_spq_ets_uri     = new ASN1ObjectIdentifier(id_spq + ".1");
+    /** SMIME SPQ UNOTICE: 1.2.840.113549.1.9.16.5.2 */
+    ASN1ObjectIdentifier id_spq_ets_unotice = new ASN1ObjectIdentifier(id_spq + ".2");
+
+    //
+    // pkcs-12 OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 }
+    //
+    /** PKCS#12: 1.2.840.113549.1.12 */
+    ASN1ObjectIdentifier   pkcs_12                  = new ASN1ObjectIdentifier("1.2.840.113549.1.12");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1 */
+    ASN1ObjectIdentifier   bagtypes                 = pkcs_12.branch("10.1");
+
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.1 */
+    ASN1ObjectIdentifier    keyBag                  = bagtypes.branch("1");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.2 */
+    ASN1ObjectIdentifier    pkcs8ShroudedKeyBag     = bagtypes.branch("2");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.3 */
+    ASN1ObjectIdentifier    certBag                 = bagtypes.branch("3");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.4 */
+    ASN1ObjectIdentifier    crlBag                  = bagtypes.branch("4");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.5 */
+    ASN1ObjectIdentifier    secretBag               = bagtypes.branch("5");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.6 */
+    ASN1ObjectIdentifier    safeContentsBag         = bagtypes.branch("6");
+
+    /** PKCS#12: 1.2.840.113549.1.12.1 */
+    ASN1ObjectIdentifier    pkcs_12PbeIds           = pkcs_12.branch("1");
+
+    /** PKCS#12: 1.2.840.113549.1.12.1.1 */
+    ASN1ObjectIdentifier    pbeWithSHAAnd128BitRC4          = pkcs_12PbeIds.branch("1");
+    /** PKCS#12: 1.2.840.113549.1.12.1.2 */
+    ASN1ObjectIdentifier    pbeWithSHAAnd40BitRC4           = pkcs_12PbeIds.branch("2");
+    /** PKCS#12: 1.2.840.113549.1.12.1.3 */
+    ASN1ObjectIdentifier    pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch("3");
+    /** PKCS#12: 1.2.840.113549.1.12.1.4 */
+    ASN1ObjectIdentifier    pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch("4");
+    /** PKCS#12: 1.2.840.113549.1.12.1.5 */
+    ASN1ObjectIdentifier    pbeWithSHAAnd128BitRC2_CBC      = pkcs_12PbeIds.branch("5");
+    /** PKCS#12: 1.2.840.113549.1.12.1.6 */
+    ASN1ObjectIdentifier    pbeWithSHAAnd40BitRC2_CBC       = pkcs_12PbeIds.branch("6");
+
+    /**
+     * PKCS#12: 1.2.840.113549.1.12.1.6
+     * @deprecated use pbeWithSHAAnd40BitRC2_CBC
+     */
+    ASN1ObjectIdentifier    pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6");
+
+    /** PKCS#9: 1.2.840.113549.1.9.16.3.6 */
+    ASN1ObjectIdentifier    id_alg_CMS3DESwrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6");
+    /** PKCS#9: 1.2.840.113549.1.9.16.3.7 */
+    ASN1ObjectIdentifier    id_alg_CMSRC2wrap  = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7");
+    /** PKCS#9: 1.2.840.113549.1.9.16.3.5 */
+    ASN1ObjectIdentifier    id_alg_ESDH  = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.5");
+    /** PKCS#9: 1.2.840.113549.1.9.16.3.10 */
+    ASN1ObjectIdentifier    id_alg_SSDH  = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.10");
+}
+
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/Pfx.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/Pfx.java
new file mode 100644
index 0000000..c88c34d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/Pfx.java
@@ -0,0 +1,89 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.BERSequence;
+
+/**
+ * the infamous Pfx from PKCS12
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Pfx
+    extends ASN1Object
+    implements PKCSObjectIdentifiers
+{
+    private ContentInfo             contentInfo;
+    private MacData                 macData = null;
+
+    private Pfx(
+        ASN1Sequence   seq)
+    {
+        BigInteger  version = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue();
+        if (version.intValue() != 3)
+        {
+            throw new IllegalArgumentException("wrong version for PFX PDU");
+        }
+
+        contentInfo = ContentInfo.getInstance(seq.getObjectAt(1));
+
+        if (seq.size() == 3)
+        {
+            macData = MacData.getInstance(seq.getObjectAt(2));
+        }
+    }
+
+    public static Pfx getInstance(
+        Object  obj)
+    {
+        if (obj instanceof Pfx)
+        {
+            return (Pfx)obj;
+        }
+
+        if (obj != null)
+        {
+            return new Pfx(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public Pfx(
+        ContentInfo     contentInfo,
+        MacData         macData)
+    {
+        this.contentInfo = contentInfo;
+        this.macData = macData;
+    }
+
+    public ContentInfo getAuthSafe()
+    {
+        return contentInfo;
+    }
+
+    public MacData getMacData()
+    {
+        return macData;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(3));
+        v.add(contentInfo);
+
+        if (macData != null)
+        {
+            v.add(macData);
+        }
+
+        return new BERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
new file mode 100644
index 0000000..5a226bb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
@@ -0,0 +1,251 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1BitString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * RFC 5958
+ *
+ * <pre>
+ *  [IMPLICIT TAGS]
+ *
+ *  OneAsymmetricKey ::= SEQUENCE {
+ *      version                   Version,
+ *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
+ *      privateKey                PrivateKey,
+ *      attributes            [0] Attributes OPTIONAL,
+ *      ...,
+ *      [[2: publicKey        [1] PublicKey OPTIONAL ]],
+ *      ...
+ *  }
+ *
+ *  PrivateKeyInfo ::= OneAsymmetricKey
+ *
+ *  Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2)
+ *
+ *  PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+ *                                     { PUBLIC-KEY,
+ *                                       { PrivateKeyAlgorithms } }
+ *
+ *  PrivateKey ::= OCTET STRING
+ *                     -- Content varies based on type of key.  The
+ *                     -- algorithm identifier dictates the format of
+ *                     -- the key.
+ *
+ *  PublicKey ::= BIT STRING
+ *                     -- Content varies based on type of key.  The
+ *                     -- algorithm identifier dictates the format of
+ *                     -- the key.
+ *
+ *  Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
+ *  </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PrivateKeyInfo
+    extends ASN1Object
+{
+    private ASN1Integer version;
+    private AlgorithmIdentifier privateKeyAlgorithm;
+    private ASN1OctetString privateKey;
+    private ASN1Set attributes;
+    private ASN1BitString publicKey;
+
+    public static PrivateKeyInfo getInstance(ASN1TaggedObject obj, boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static PrivateKeyInfo getInstance(Object obj)
+    {
+        if (obj instanceof PrivateKeyInfo)
+        {
+            return (PrivateKeyInfo)obj;
+        }
+        else if (obj != null)
+        {
+            return new PrivateKeyInfo(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private static int getVersionValue(ASN1Integer version)
+    {
+        BigInteger bigValue = version.getValue();
+        if (bigValue.compareTo(BigIntegers.ZERO) < 0 || bigValue.compareTo(BigIntegers.ONE) > 0)
+        {
+            throw new IllegalArgumentException("invalid version for private key info");
+        }
+        return bigValue.intValue();
+    }
+
+    public PrivateKeyInfo(
+        AlgorithmIdentifier privateKeyAlgorithm,
+        ASN1Encodable privateKey)
+        throws IOException
+    {
+        this(privateKeyAlgorithm, privateKey, null, null);
+    }
+
+    public PrivateKeyInfo(
+        AlgorithmIdentifier privateKeyAlgorithm,
+        ASN1Encodable privateKey,
+        ASN1Set attributes)
+        throws IOException
+    {
+        this(privateKeyAlgorithm, privateKey, attributes, null);
+    }
+
+    public PrivateKeyInfo(
+        AlgorithmIdentifier privateKeyAlgorithm,
+        ASN1Encodable privateKey,
+        ASN1Set attributes,
+        byte[] publicKey)
+        throws IOException
+    {
+        this.version = new ASN1Integer(publicKey != null ? BigIntegers.ONE : BigIntegers.ZERO);
+        this.privateKeyAlgorithm = privateKeyAlgorithm;
+        this.privateKey = new DEROctetString(privateKey);
+        this.attributes = attributes;
+        this.publicKey = publicKey == null ? null : new DERBitString(publicKey);
+    }
+
+    private PrivateKeyInfo(ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        this.version = ASN1Integer.getInstance(e.nextElement());
+
+        int versionValue = getVersionValue(version);
+
+        this.privateKeyAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+        this.privateKey = ASN1OctetString.getInstance(e.nextElement());
+
+        int lastTag = -1;
+        while (e.hasMoreElements())
+        {
+            ASN1TaggedObject tagged = (ASN1TaggedObject)e.nextElement();
+
+            int tag = tagged.getTagNo();
+            if (tag <= lastTag)
+            {
+                throw new IllegalArgumentException("invalid optional field in private key info");
+            }
+
+            lastTag = tag;
+
+            switch (tag)
+            {
+            case 0:
+            {
+                this.attributes = ASN1Set.getInstance(tagged, false);
+                break;
+            }
+            case 1:
+            {
+                if (versionValue < 1)
+                {
+                    throw new IllegalArgumentException("'publicKey' requires version v2(1) or later");
+                }
+
+                this.publicKey = DERBitString.getInstance(tagged, false);
+                break;
+            }
+            default:
+            {
+                throw new IllegalArgumentException("unknown optional field in private key info");
+            }
+            }
+        }
+    }
+
+    public ASN1Set getAttributes()
+    {
+        return attributes;
+    }
+
+    public AlgorithmIdentifier getPrivateKeyAlgorithm()
+    {
+        return privateKeyAlgorithm;
+    }
+
+    public ASN1Encodable parsePrivateKey()
+        throws IOException
+    {
+        return ASN1Primitive.fromByteArray(privateKey.getOctets());
+    }
+
+    /**
+     * Return true if a public key is present, false otherwise.
+     *
+     * @return true if public included, otherwise false.
+     */
+    public boolean hasPublicKey()
+    {
+        return publicKey != null;
+    }
+
+    /**
+     * for when the public key is an encoded object - if the bitstring
+     * can't be decoded this routine throws an IOException.
+     *
+     * @return the public key as an ASN.1 primitive.
+     * @throws IOException - if the bit string doesn't represent a DER
+     * encoded object.
+     */
+    public ASN1Encodable parsePublicKey()
+        throws IOException
+    {
+        return publicKey == null ? null : ASN1Primitive.fromByteArray(publicKey.getOctets());
+    }
+
+    /**
+     * for when the public key is raw bits.
+     *
+     * @return the public key as the raw bit string...
+     */
+    public ASN1BitString getPublicKeyData()
+    {
+        return publicKey;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(privateKeyAlgorithm);
+        v.add(privateKey);
+
+        if (attributes != null)
+        {
+            v.add(new DERTaggedObject(false, 0, attributes));
+        }
+
+        if (publicKey != null)
+        {
+            v.add(new DERTaggedObject(false, 1, publicKey));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
new file mode 100644
index 0000000..25d3170
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
@@ -0,0 +1,159 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSAESOAEPparams
+    extends ASN1Object
+{
+    private AlgorithmIdentifier hashAlgorithm;
+    private AlgorithmIdentifier maskGenAlgorithm;
+    private AlgorithmIdentifier pSourceAlgorithm;
+    
+    public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+    public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);
+    public final static AlgorithmIdentifier DEFAULT_P_SOURCE_ALGORITHM = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0]));
+    
+    public static RSAESOAEPparams getInstance(
+        Object  obj)
+    {
+        if (obj instanceof RSAESOAEPparams)
+        {
+            return (RSAESOAEPparams)obj;
+        }
+        else if (obj != null)
+        {
+            return new RSAESOAEPparams(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+    
+    /**
+     * The default version
+     */
+    public RSAESOAEPparams()
+    {
+        hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+        maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+        pSourceAlgorithm = DEFAULT_P_SOURCE_ALGORITHM;
+    }
+    
+    public RSAESOAEPparams(
+        AlgorithmIdentifier hashAlgorithm,
+        AlgorithmIdentifier maskGenAlgorithm,
+        AlgorithmIdentifier pSourceAlgorithm)
+    {
+        this.hashAlgorithm = hashAlgorithm;
+        this.maskGenAlgorithm = maskGenAlgorithm;
+        this.pSourceAlgorithm = pSourceAlgorithm;
+    }
+
+    /**
+     * @deprecated use getInstance()
+     * @param seq
+     */
+    public RSAESOAEPparams(
+        ASN1Sequence seq)
+    {
+        hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+        maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+        pSourceAlgorithm = DEFAULT_P_SOURCE_ALGORITHM;
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)seq.getObjectAt(i);
+            
+            switch (o.getTagNo())
+            {
+            case 0:
+                hashAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+                break;
+            case 1:
+                maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+                break;
+            case 2:
+                pSourceAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+                break;
+            default:
+                throw new IllegalArgumentException("unknown tag");
+            }
+        }
+    }
+    
+    public AlgorithmIdentifier getHashAlgorithm()
+    {
+        return hashAlgorithm;
+    }
+    
+    public AlgorithmIdentifier getMaskGenAlgorithm()
+    {
+        return maskGenAlgorithm;
+    }
+    
+    public AlgorithmIdentifier getPSourceAlgorithm()
+    {
+        return pSourceAlgorithm;
+    }
+    
+    /**
+     * <pre>
+     *  RSAES-OAEP-params ::= SEQUENCE {
+     *     hashAlgorithm      [0] OAEP-PSSDigestAlgorithms     DEFAULT sha1,
+     *     maskGenAlgorithm   [1] PKCS1MGFAlgorithms  DEFAULT mgf1SHA1,
+     *     pSourceAlgorithm   [2] PKCS1PSourceAlgorithms  DEFAULT pSpecifiedEmpty
+     *   }
+     *  
+     *   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>
+     * @return the asn1 primitive representing the parameters.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM))
+        {
+            v.add(new DERTaggedObject(true, 0, hashAlgorithm));
+        }
+        
+        if (!maskGenAlgorithm.equals(DEFAULT_MASK_GEN_FUNCTION))
+        {
+            v.add(new DERTaggedObject(true, 1, maskGenAlgorithm));
+        }
+        
+        if (!pSourceAlgorithm.equals(DEFAULT_P_SOURCE_ALGORITHM))
+        {
+            v.add(new DERTaggedObject(true, 2, pSourceAlgorithm));
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java
new file mode 100644
index 0000000..f173206
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java
@@ -0,0 +1,191 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSAPrivateKey
+    extends ASN1Object
+{
+    private BigInteger version;
+    private BigInteger modulus;
+    private BigInteger publicExponent;
+    private BigInteger privateExponent;
+    private BigInteger prime1;
+    private BigInteger prime2;
+    private BigInteger exponent1;
+    private BigInteger exponent2;
+    private BigInteger coefficient;
+    private ASN1Sequence otherPrimeInfos = null;
+
+    public static RSAPrivateKey getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static RSAPrivateKey getInstance(
+        Object obj)
+    {
+        if (obj instanceof RSAPrivateKey)
+        {
+            return (RSAPrivateKey)obj;
+        }
+
+        if (obj != null)
+        {
+            return new RSAPrivateKey(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+    
+    public RSAPrivateKey(
+        BigInteger modulus,
+        BigInteger publicExponent,
+        BigInteger privateExponent,
+        BigInteger prime1,
+        BigInteger prime2,
+        BigInteger exponent1,
+        BigInteger exponent2,
+        BigInteger coefficient)
+    {
+        this.version = BigInteger.valueOf(0);
+        this.modulus = modulus;
+        this.publicExponent = publicExponent;
+        this.privateExponent = privateExponent;
+        this.prime1 = prime1;
+        this.prime2 = prime2;
+        this.exponent1 = exponent1;
+        this.exponent2 = exponent2;
+        this.coefficient = coefficient;
+    }
+
+    private RSAPrivateKey(
+        ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        BigInteger v = ((ASN1Integer)e.nextElement()).getValue();
+        if (v.intValue() != 0 && v.intValue() != 1)
+        {
+            throw new IllegalArgumentException("wrong version for RSA private key");
+        }
+
+        version = v;
+        modulus = ((ASN1Integer)e.nextElement()).getValue();
+        publicExponent = ((ASN1Integer)e.nextElement()).getValue();
+        privateExponent = ((ASN1Integer)e.nextElement()).getValue();
+        prime1 = ((ASN1Integer)e.nextElement()).getValue();
+        prime2 = ((ASN1Integer)e.nextElement()).getValue();
+        exponent1 = ((ASN1Integer)e.nextElement()).getValue();
+        exponent2 = ((ASN1Integer)e.nextElement()).getValue();
+        coefficient = ((ASN1Integer)e.nextElement()).getValue();
+        
+        if (e.hasMoreElements())
+        {
+            otherPrimeInfos = (ASN1Sequence)e.nextElement();
+        }
+    }
+
+    public BigInteger getVersion()
+    {
+        return version;
+    }
+    
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    public BigInteger getPrivateExponent()
+    {
+        return privateExponent;
+    }
+
+    public BigInteger getPrime1()
+    {
+        return prime1;
+    }
+
+    public BigInteger getPrime2()
+    {
+        return prime2;
+    }
+
+    public BigInteger getExponent1()
+    {
+        return exponent1;
+    }
+
+    public BigInteger getExponent2()
+    {
+        return exponent2;
+    }
+
+    public BigInteger getCoefficient()
+    {
+        return coefficient;
+    }
+
+    /**
+     * This outputs the key in PKCS1v2 format.
+     * <pre>
+     *      RSAPrivateKey ::= SEQUENCE {
+     *                          version Version,
+     *                          modulus INTEGER, -- n
+     *                          publicExponent INTEGER, -- e
+     *                          privateExponent INTEGER, -- d
+     *                          prime1 INTEGER, -- p
+     *                          prime2 INTEGER, -- q
+     *                          exponent1 INTEGER, -- d mod (p-1)
+     *                          exponent2 INTEGER, -- d mod (q-1)
+     *                          coefficient INTEGER, -- (inverse of q) mod p
+     *                          otherPrimeInfos OtherPrimeInfos OPTIONAL
+     *                      }
+     *
+     *      Version ::= INTEGER { two-prime(0), multi(1) }
+     *        (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --})
+     * </pre>
+     * <p>
+     * This routine is written to output PKCS1 version 2.1, private keys.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(version));                       // version
+        v.add(new ASN1Integer(getModulus()));
+        v.add(new ASN1Integer(getPublicExponent()));
+        v.add(new ASN1Integer(getPrivateExponent()));
+        v.add(new ASN1Integer(getPrime1()));
+        v.add(new ASN1Integer(getPrime2()));
+        v.add(new ASN1Integer(getExponent1()));
+        v.add(new ASN1Integer(getExponent2()));
+        v.add(new ASN1Integer(getCoefficient()));
+
+        if (otherPrimeInfos != null)
+        {
+            v.add(otherPrimeInfos);
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
new file mode 100644
index 0000000..6ff89d8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
@@ -0,0 +1,191 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @deprecated use RSAPrivateKey
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSAPrivateKeyStructure
+    extends ASN1Object
+{
+    private int         version;
+    private BigInteger  modulus;
+    private BigInteger  publicExponent;
+    private BigInteger  privateExponent;
+    private BigInteger  prime1;
+    private BigInteger  prime2;
+    private BigInteger  exponent1;
+    private BigInteger  exponent2;
+    private BigInteger  coefficient;
+    private ASN1Sequence otherPrimeInfos = null;
+
+    public static RSAPrivateKeyStructure getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static RSAPrivateKeyStructure getInstance(
+        Object  obj)
+    {
+        if (obj instanceof RSAPrivateKeyStructure)
+        {
+            return (RSAPrivateKeyStructure)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new RSAPrivateKeyStructure((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+    }
+    
+    public RSAPrivateKeyStructure(
+        BigInteger  modulus,
+        BigInteger  publicExponent,
+        BigInteger  privateExponent,
+        BigInteger  prime1,
+        BigInteger  prime2,
+        BigInteger  exponent1,
+        BigInteger  exponent2,
+        BigInteger  coefficient)
+    {
+        this.version = 0;
+        this.modulus = modulus;
+        this.publicExponent = publicExponent;
+        this.privateExponent = privateExponent;
+        this.prime1 = prime1;
+        this.prime2 = prime2;
+        this.exponent1 = exponent1;
+        this.exponent2 = exponent2;
+        this.coefficient = coefficient;
+    }
+
+    public RSAPrivateKeyStructure(
+        ASN1Sequence  seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        BigInteger  v = ((ASN1Integer)e.nextElement()).getValue();
+        if (v.intValue() != 0 && v.intValue() != 1)
+        {
+            throw new IllegalArgumentException("wrong version for RSA private key");
+        }
+
+        version = v.intValue();
+        modulus = ((ASN1Integer)e.nextElement()).getValue();
+        publicExponent = ((ASN1Integer)e.nextElement()).getValue();
+        privateExponent = ((ASN1Integer)e.nextElement()).getValue();
+        prime1 = ((ASN1Integer)e.nextElement()).getValue();
+        prime2 = ((ASN1Integer)e.nextElement()).getValue();
+        exponent1 = ((ASN1Integer)e.nextElement()).getValue();
+        exponent2 = ((ASN1Integer)e.nextElement()).getValue();
+        coefficient = ((ASN1Integer)e.nextElement()).getValue();
+        
+        if (e.hasMoreElements())
+        {
+            otherPrimeInfos = (ASN1Sequence)e.nextElement();
+        }
+    }
+
+    public int getVersion()
+    {
+        return version;
+    }
+    
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    public BigInteger getPrivateExponent()
+    {
+        return privateExponent;
+    }
+
+    public BigInteger getPrime1()
+    {
+        return prime1;
+    }
+
+    public BigInteger getPrime2()
+    {
+        return prime2;
+    }
+
+    public BigInteger getExponent1()
+    {
+        return exponent1;
+    }
+
+    public BigInteger getExponent2()
+    {
+        return exponent2;
+    }
+
+    public BigInteger getCoefficient()
+    {
+        return coefficient;
+    }
+
+    /**
+     * This outputs the key in PKCS1v2 format.
+     * <pre>
+     *      RSAPrivateKey ::= SEQUENCE {
+     *                          version Version,
+     *                          modulus INTEGER, -- n
+     *                          publicExponent INTEGER, -- e
+     *                          privateExponent INTEGER, -- d
+     *                          prime1 INTEGER, -- p
+     *                          prime2 INTEGER, -- q
+     *                          exponent1 INTEGER, -- d mod (p-1)
+     *                          exponent2 INTEGER, -- d mod (q-1)
+     *                          coefficient INTEGER, -- (inverse of q) mod p
+     *                          otherPrimeInfos OtherPrimeInfos OPTIONAL
+     *                      }
+     *
+     *      Version ::= INTEGER { two-prime(0), multi(1) }
+     *        (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --})
+     * </pre>
+     * <p>
+     * This routine is written to output PKCS1 version 2.1, private keys.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(version));                       // version
+        v.add(new ASN1Integer(getModulus()));
+        v.add(new ASN1Integer(getPublicExponent()));
+        v.add(new ASN1Integer(getPrivateExponent()));
+        v.add(new ASN1Integer(getPrime1()));
+        v.add(new ASN1Integer(getPrime2()));
+        v.add(new ASN1Integer(getExponent1()));
+        v.add(new ASN1Integer(getExponent2()));
+        v.add(new ASN1Integer(getCoefficient()));
+
+        if (otherPrimeInfos != null)
+        {
+            v.add(otherPrimeInfos);
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAPublicKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAPublicKey.java
new file mode 100644
index 0000000..b5abf91
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSAPublicKey.java
@@ -0,0 +1,99 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSAPublicKey
+    extends ASN1Object
+{
+    private BigInteger modulus;
+    private BigInteger publicExponent;
+
+    public static RSAPublicKey getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static RSAPublicKey getInstance(
+        Object obj)
+    {
+        if (obj instanceof RSAPublicKey)
+        {
+            return (RSAPublicKey)obj;
+        }
+
+        if (obj != null)
+        {
+            return new RSAPublicKey(ASN1Sequence.getInstance(obj));
+        }
+        
+        return null;
+    }
+    
+    public RSAPublicKey(
+        BigInteger modulus,
+        BigInteger publicExponent)
+    {
+        this.modulus = modulus;
+        this.publicExponent = publicExponent;
+    }
+
+    private RSAPublicKey(
+        ASN1Sequence seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        Enumeration e = seq.getObjects();
+
+        modulus = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
+        publicExponent = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
+    }
+
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    /**
+     * This outputs the key in PKCS1v2 format.
+     * <pre>
+     *      RSAPublicKey ::= SEQUENCE {
+     *                          modulus INTEGER, -- n
+     *                          publicExponent INTEGER, -- e
+     *                      }
+     * </pre>
+     * <p>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(getModulus()));
+        v.add(new ASN1Integer(getPublicExponent()));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
new file mode 100644
index 0000000..bbea15d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
@@ -0,0 +1,176 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSASSAPSSparams
+    extends ASN1Object
+{
+    private AlgorithmIdentifier hashAlgorithm;
+    private AlgorithmIdentifier maskGenAlgorithm;
+    private ASN1Integer          saltLength;
+    private ASN1Integer          trailerField;
+    
+    public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+    public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);
+    public final static ASN1Integer          DEFAULT_SALT_LENGTH = new ASN1Integer(20);
+    public final static ASN1Integer          DEFAULT_TRAILER_FIELD = new ASN1Integer(1);
+    
+    public static RSASSAPSSparams getInstance(
+        Object  obj)
+    {
+        if (obj instanceof RSASSAPSSparams)
+        {
+            return (RSASSAPSSparams)obj;
+        }
+        else if (obj != null)
+        {
+            return new RSASSAPSSparams(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+    
+    /**
+     * The default version
+     */
+    public RSASSAPSSparams()
+    {
+        hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+        maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+        saltLength = DEFAULT_SALT_LENGTH;
+        trailerField = DEFAULT_TRAILER_FIELD;
+    }
+    
+    public RSASSAPSSparams(
+        AlgorithmIdentifier hashAlgorithm,
+        AlgorithmIdentifier maskGenAlgorithm,
+        ASN1Integer          saltLength,
+        ASN1Integer          trailerField)
+    {
+        this.hashAlgorithm = hashAlgorithm;
+        this.maskGenAlgorithm = maskGenAlgorithm;
+        this.saltLength = saltLength;
+        this.trailerField = trailerField;
+    }
+    
+    private RSASSAPSSparams(
+        ASN1Sequence seq)
+    {
+        hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+        maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+        saltLength = DEFAULT_SALT_LENGTH;
+        trailerField = DEFAULT_TRAILER_FIELD;
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)seq.getObjectAt(i);
+            
+            switch (o.getTagNo())
+            {
+            case 0:
+                hashAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+                break;
+            case 1:
+                maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+                break;
+            case 2:
+                saltLength = ASN1Integer.getInstance(o, true);
+                break;
+            case 3:
+                trailerField = ASN1Integer.getInstance(o, true);
+                break;
+            default:
+                throw new IllegalArgumentException("unknown tag");
+            }
+        }
+    }
+    
+    public AlgorithmIdentifier getHashAlgorithm()
+    {
+        return hashAlgorithm;
+    }
+    
+    public AlgorithmIdentifier getMaskGenAlgorithm()
+    {
+        return maskGenAlgorithm;
+    }
+    
+    public BigInteger getSaltLength()
+    {
+        return saltLength.getValue();
+    }
+    
+    public BigInteger getTrailerField()
+    {
+        return trailerField.getValue();
+    }
+    
+    /**
+     * <pre>
+     * RSASSA-PSS-params ::= SEQUENCE {
+     *   hashAlgorithm      [0] OAEP-PSSDigestAlgorithms  DEFAULT sha1,
+     *    maskGenAlgorithm   [1] PKCS1MGFAlgorithms  DEFAULT mgf1SHA1,
+     *    saltLength         [2] INTEGER  DEFAULT 20,
+     *    trailerField       [3] TrailerField  DEFAULT trailerFieldBC
+     *  }
+     *
+     * 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 --
+     * }
+     * 
+     * TrailerField ::= INTEGER { trailerFieldBC(1) }
+     * </pre>
+     * @return the asn1 primitive representing the parameters.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM))
+        {
+            v.add(new DERTaggedObject(true, 0, hashAlgorithm));
+        }
+        
+        if (!maskGenAlgorithm.equals(DEFAULT_MASK_GEN_FUNCTION))
+        {
+            v.add(new DERTaggedObject(true, 1, maskGenAlgorithm));
+        }
+        
+        if (!saltLength.equals(DEFAULT_SALT_LENGTH))
+        {
+            v.add(new DERTaggedObject(true, 2, saltLength));
+        }
+        
+        if (!trailerField.equals(DEFAULT_TRAILER_FIELD))
+        {
+            v.add(new DERTaggedObject(true, 3, trailerField));
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/SafeBag.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/SafeBag.java
new file mode 100644
index 0000000..3b34333
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/SafeBag.java
@@ -0,0 +1,100 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DLSequence;
+import com.android.internal.org.bouncycastle.asn1.DLTaggedObject;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SafeBag
+    extends ASN1Object
+{
+    private ASN1ObjectIdentifier bagId;
+    private ASN1Encodable bagValue;
+    private ASN1Set                     bagAttributes;
+
+    public SafeBag(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable obj)
+    {
+        this.bagId = oid;
+        this.bagValue = obj;
+        this.bagAttributes = null;
+    }
+
+    public SafeBag(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable obj,
+        ASN1Set                 bagAttributes)
+    {
+        this.bagId = oid;
+        this.bagValue = obj;
+        this.bagAttributes = bagAttributes;
+    }
+
+    public static SafeBag getInstance(
+        Object  obj)
+    {
+        if (obj instanceof SafeBag)
+        {
+            return (SafeBag)obj;
+        }
+
+        if (obj != null)
+        {
+            return new SafeBag(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private SafeBag(
+        ASN1Sequence    seq)
+    {
+        this.bagId = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+        this.bagValue = ((ASN1TaggedObject)seq.getObjectAt(1)).getObject();
+        if (seq.size() == 3)
+        {
+            this.bagAttributes = (ASN1Set)seq.getObjectAt(2);
+        }
+    }
+
+    public ASN1ObjectIdentifier getBagId()
+    {
+        return bagId;
+    }
+
+    public ASN1Encodable getBagValue()
+    {
+        return bagValue;
+    }
+
+    public ASN1Set getBagAttributes()
+    {
+        return bagAttributes;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(bagId);
+        v.add(new DLTaggedObject(true, 0, bagValue));
+
+        if (bagAttributes != null)
+        {
+            v.add(bagAttributes);
+        }
+
+        return new DLSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/SignedData.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/SignedData.java
new file mode 100644
index 0000000..9ff835d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/pkcs/SignedData.java
@@ -0,0 +1,169 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.BERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * a PKCS#7 signed data object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SignedData
+    extends ASN1Object
+    implements PKCSObjectIdentifiers
+{
+    private ASN1Integer              version;
+    private ASN1Set                 digestAlgorithms;
+    private ContentInfo             contentInfo;
+    private ASN1Set                 certificates;
+    private ASN1Set                 crls;
+    private ASN1Set                 signerInfos;
+
+    public static SignedData getInstance(
+        Object  o)
+    {
+        if (o instanceof SignedData)
+        {
+            return (SignedData)o;
+        }
+        else if (o != null)
+        {
+            return new SignedData(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
+    }
+
+    public SignedData(
+        ASN1Integer        _version,
+        ASN1Set           _digestAlgorithms,
+        ContentInfo       _contentInfo,
+        ASN1Set           _certificates,
+        ASN1Set           _crls,
+        ASN1Set           _signerInfos)
+    {
+        version          = _version;
+        digestAlgorithms = _digestAlgorithms;
+        contentInfo      = _contentInfo;
+        certificates     = _certificates;
+        crls             = _crls;
+        signerInfos      = _signerInfos;
+    }
+
+    public SignedData(
+        ASN1Sequence seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        version = (ASN1Integer)e.nextElement();
+        digestAlgorithms = ((ASN1Set)e.nextElement());
+        contentInfo = ContentInfo.getInstance(e.nextElement());
+
+        while (e.hasMoreElements())
+        {
+            ASN1Primitive o = (ASN1Primitive)e.nextElement();
+
+            //
+            // an interesting feature of SignedData is that there appear to be varying implementations...
+            // for the moment we ignore anything which doesn't fit.
+            //
+            if (o instanceof ASN1TaggedObject)
+            {
+                ASN1TaggedObject tagged = (ASN1TaggedObject)o;
+
+                switch (tagged.getTagNo())
+                {
+                case 0:
+                    certificates = ASN1Set.getInstance(tagged, false);
+                    break;
+                case 1:
+                    crls = ASN1Set.getInstance(tagged, false);
+                    break;
+                default:
+                    throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo());
+                }
+            }
+            else
+            {
+                signerInfos = (ASN1Set)o;
+            }
+        }
+    }
+
+    public ASN1Integer getVersion()
+    {
+        return version;
+    }
+
+    public ASN1Set getDigestAlgorithms()
+    {
+        return digestAlgorithms;
+    }
+
+    public ContentInfo getContentInfo()
+    {
+        return contentInfo;
+    }
+
+    public ASN1Set getCertificates()
+    {
+        return certificates;
+    }
+
+    public ASN1Set getCRLs()
+    {
+        return crls;
+    }
+
+    public ASN1Set getSignerInfos()
+    {
+        return signerInfos;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  SignedData ::= SEQUENCE {
+     *      version Version,
+     *      digestAlgorithms DigestAlgorithmIdentifiers,
+     *      contentInfo ContentInfo,
+     *      certificates
+     *          [0] IMPLICIT ExtendedCertificatesAndCertificates
+     *                   OPTIONAL,
+     *      crls
+     *          [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+     *      signerInfos SignerInfos }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(digestAlgorithms);
+        v.add(contentInfo);
+
+        if (certificates != null)
+        {
+            v.add(new DERTaggedObject(false, 0, certificates));
+        }
+
+        if (crls != null)
+        {
+            v.add(new DERTaggedObject(false, 1, crls));
+        }
+
+        v.add(signerInfos);
+
+        return new BERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/ECPrivateKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/ECPrivateKey.java
new file mode 100644
index 0000000..640393a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/ECPrivateKey.java
@@ -0,0 +1,184 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.sec;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * the elliptic curve private key object from SEC 1
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECPrivateKey
+    extends ASN1Object
+{
+    private ASN1Sequence seq;
+
+    private ECPrivateKey(
+        ASN1Sequence seq)
+    {
+        this.seq = seq;
+    }
+
+    public static ECPrivateKey getInstance(
+        Object obj)
+    {
+        if (obj instanceof ECPrivateKey)
+        {
+            return (ECPrivateKey)obj;
+        }
+
+        if (obj != null)
+        {
+            return new ECPrivateKey(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * @deprecated use constructor which takes orderBitLength to guarantee correct encoding.
+     */
+    public ECPrivateKey(
+        BigInteger key)
+    {
+        this(key.bitLength(), key);
+    }
+
+    /**
+     * Base constructor.
+     *
+     * @param orderBitLength the bitLength of the order of the curve.
+     * @param key the private key value.
+     */
+    public ECPrivateKey(
+        int        orderBitLength,
+        BigInteger key)
+    {
+        byte[] bytes = BigIntegers.asUnsignedByteArray((orderBitLength + 7) / 8, key);
+
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(1));
+        v.add(new DEROctetString(bytes));
+
+        seq = new DERSequence(v);
+    }
+
+    /**
+     * @deprecated use constructor which takes orderBitLength to guarantee correct encoding.
+     */
+    public ECPrivateKey(
+        BigInteger key,
+        ASN1Encodable parameters)
+    {
+        this(key, null, parameters);
+    }
+
+    /**
+     * @deprecated use constructor which takes orderBitLength to guarantee correct encoding.
+     */
+    public ECPrivateKey(
+        BigInteger key,
+        DERBitString publicKey,
+        ASN1Encodable parameters)
+    {
+        this(key.bitLength(), key, publicKey, parameters);
+    }
+
+    public ECPrivateKey(
+        int orderBitLength,
+        BigInteger key,
+        ASN1Encodable parameters)
+    {
+        this(orderBitLength, key, null, parameters);
+    }
+
+    public ECPrivateKey(
+        int orderBitLength,
+        BigInteger key,
+        DERBitString publicKey,
+        ASN1Encodable parameters)
+    {
+        byte[] bytes = BigIntegers.asUnsignedByteArray((orderBitLength + 7) / 8, key);
+
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(1));
+        v.add(new DEROctetString(bytes));
+
+        if (parameters != null)
+        {
+            v.add(new DERTaggedObject(true, 0, parameters));
+        }
+
+        if (publicKey != null)
+        {
+            v.add(new DERTaggedObject(true, 1, publicKey));
+        }
+
+        seq = new DERSequence(v);
+    }
+
+    public BigInteger getKey()
+    {
+        ASN1OctetString octs = (ASN1OctetString)seq.getObjectAt(1);
+
+        return new BigInteger(1, octs.getOctets());
+    }
+
+    public DERBitString getPublicKey()
+    {
+        return (DERBitString)getObjectInTag(1);
+    }
+
+    public ASN1Primitive getParameters()
+    {
+        return getObjectInTag(0);
+    }
+
+    private ASN1Primitive getObjectInTag(int tagNo)
+    {
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1Encodable obj = (ASN1Encodable)e.nextElement();
+
+            if (obj instanceof ASN1TaggedObject)
+            {
+                ASN1TaggedObject tag = (ASN1TaggedObject)obj;
+                if (tag.getTagNo() == tagNo)
+                {
+                    return tag.getObject().toASN1Primitive();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * ECPrivateKey ::= SEQUENCE {
+     *     version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+     *     privateKey OCTET STRING,
+     *     parameters [0] Parameters OPTIONAL,
+     *     publicKey [1] BIT STRING OPTIONAL }
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
new file mode 100644
index 0000000..d2bd3c5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
@@ -0,0 +1,130 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.sec;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * the elliptic curve private key object from SEC 1
+ * @deprecated use ECPrivateKey
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECPrivateKeyStructure
+    extends ASN1Object
+{
+    private ASN1Sequence  seq;
+
+    public ECPrivateKeyStructure(
+        ASN1Sequence  seq)
+    {
+        this.seq = seq;
+    }
+
+    public ECPrivateKeyStructure(
+        BigInteger  key)
+    {
+        byte[] bytes = BigIntegers.asUnsignedByteArray(key);
+
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(1));
+        v.add(new DEROctetString(bytes));
+
+        seq = new DERSequence(v);
+    }
+
+    public ECPrivateKeyStructure(
+        BigInteger    key,
+        ASN1Encodable parameters)
+    {
+        this(key, null, parameters);
+    }
+
+    public ECPrivateKeyStructure(
+        BigInteger    key,
+        DERBitString  publicKey,
+        ASN1Encodable parameters)
+    {
+        byte[] bytes = BigIntegers.asUnsignedByteArray(key);
+
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(1));
+        v.add(new DEROctetString(bytes));
+
+        if (parameters != null)
+        {
+            v.add(new DERTaggedObject(true, 0, parameters));
+        }
+
+        if (publicKey != null)
+        {
+            v.add(new DERTaggedObject(true, 1, publicKey));
+        }
+
+        seq = new DERSequence(v);
+    }
+
+    public BigInteger getKey()
+    {
+        ASN1OctetString  octs = (ASN1OctetString)seq.getObjectAt(1);
+
+        return new BigInteger(1, octs.getOctets());
+    }
+
+    public DERBitString getPublicKey()
+    {
+        return (DERBitString)getObjectInTag(1);
+    }
+
+    public ASN1Primitive getParameters()
+    {
+        return getObjectInTag(0);
+    }
+
+    private ASN1Primitive getObjectInTag(int tagNo)
+    {
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1Encodable obj = (ASN1Encodable)e.nextElement();
+
+            if (obj instanceof ASN1TaggedObject)
+            {
+                ASN1TaggedObject tag = (ASN1TaggedObject)obj;
+                if (tag.getTagNo() == tagNo)
+                {
+                    return (ASN1Primitive)((ASN1Encodable)tag.getObject()).toASN1Primitive();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * ECPrivateKey ::= SEQUENCE {
+     *     version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+     *     privateKey OCTET STRING,
+     *     parameters [0] Parameters OPTIONAL,
+     *     publicKey [1] BIT STRING OPTIONAL }
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/SECNamedCurves.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/SECNamedCurves.java
new file mode 100644
index 0000000..ea78ab4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/SECNamedCurves.java
@@ -0,0 +1,1086 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.sec;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParametersHolder;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECPoint;
+import com.android.internal.org.bouncycastle.math.ec.ECConstants;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism;
+import com.android.internal.org.bouncycastle.math.ec.endo.GLVTypeBParameters;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SECNamedCurves
+{
+    private static ECCurve configureCurve(ECCurve curve)
+    {
+        return curve;
+    }
+
+    private static ECCurve configureCurveGLV(ECCurve c, GLVTypeBParameters p)
+    {
+        return c.configure().setEndomorphism(new GLVTypeBEndomorphism(c, p)).create();
+    }
+
+    private static BigInteger fromHex(
+        String hex)
+    {
+        return new BigInteger(1, Hex.decode(hex));
+    }
+
+    /*
+     * secp112r1
+     */
+    static X9ECParametersHolder secp112r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = (2^128 - 3) / 76439
+            BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B");
+            BigInteger a = fromHex("DB7C2ABF62E35E668076BEAD2088");
+            BigInteger b = fromHex("659EF8BA043916EEDE8911702B22");
+            byte[] S = Hex.decode("00F50B028E4D696E676875615175290472783FB1");
+            BigInteger n = fromHex("DB7C2ABF62E35E7628DFAC6561C5");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "09487239995A5EE76B55F9C2F098"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "09487239995A5EE76B55F9C2F098"
+                + "A89CE5AF8724C0A23E0E0FF77500"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp112r2
+     */
+    static X9ECParametersHolder secp112r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = (2^128 - 3) / 76439
+            BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B");
+            BigInteger a = fromHex("6127C24C05F38A0AAAF65C0EF02C");
+            BigInteger b = fromHex("51DEF1815DB5ED74FCC34C85D709");
+            byte[] S = Hex.decode("002757A1114D696E6768756151755316C05E0BD4");
+            BigInteger n = fromHex("36DF0AAFD8B8D7597CA10520D04B");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "4BA30AB5E892B4E1649DD0928643"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "4BA30AB5E892B4E1649DD0928643"
+                + "ADCD46F5882E3747DEF36E956E97"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp128r1
+     */
+    static X9ECParametersHolder secp128r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^128 - 2^97 - 1
+            BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
+            BigInteger a = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC");
+            BigInteger b = fromHex("E87579C11079F43DD824993C2CEE5ED3");
+            byte[] S = Hex.decode("000E0D4D696E6768756151750CC03A4473D03679");
+            BigInteger n = fromHex("FFFFFFFE0000000075A30D1B9038A115");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "161FF7528B899B2D0C28607CA52C5B86"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "161FF7528B899B2D0C28607CA52C5B86"
+                + "CF5AC8395BAFEB13C02DA292DDED7A83"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp128r2
+     */
+    static X9ECParametersHolder secp128r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^128 - 2^97 - 1
+            BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
+            BigInteger a = fromHex("D6031998D1B3BBFEBF59CC9BBFF9AEE1");
+            BigInteger b = fromHex("5EEEFCA380D02919DC2C6558BB6D8A5D");
+            byte[] S = Hex.decode("004D696E67687561517512D8F03431FCE63B88F4");
+            BigInteger n = fromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "7B6AA5D85E572983E6FB32A7CDEBC140"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "7B6AA5D85E572983E6FB32A7CDEBC140"
+                + "27B6916A894D3AEE7106FE805FC34B44"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp160k1
+     */
+    static X9ECParametersHolder secp160k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(7);
+            byte[] S = null;
+            BigInteger n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
+            BigInteger h = BigInteger.valueOf(1);
+
+            GLVTypeBParameters glv = new GLVTypeBParameters(
+                new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16),
+                new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16),
+                new BigInteger[]{
+                    new BigInteger("9162fbe73984472a0a9e", 16),
+                    new BigInteger("-96341f1138933bc2f505", 16) },
+                new BigInteger[]{
+                    new BigInteger("127971af8721782ecffa3", 16),
+                    new BigInteger("9162fbe73984472a0a9e", 16) },
+                new BigInteger("9162fbe73984472a0a9d0590", 16),
+                new BigInteger("96341f1138933bc2f503fd44", 16),
+                176);
+
+            ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv);
+//            ECPoint G = curve.decodePoint(Hex.decode("02"
+//                + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
+                + "938CF935318FDCED6BC28286531733C3F03C4FEE"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp160r1
+     */
+    static X9ECParametersHolder secp160r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^160 - 2^31 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF");
+            BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC");
+            BigInteger b = fromHex("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45");
+            byte[] S = Hex.decode("1053CDE42C14D696E67687561517533BF3F83345");
+            BigInteger n = fromHex("0100000000000000000001F4C8F927AED3CA752257");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+                //+ "4A96B5688EF573284664698968C38BB913CBFC82"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "4A96B5688EF573284664698968C38BB913CBFC82"
+                + "23A628553168947D59DCC912042351377AC5FB32"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp160r2
+     */
+    static X9ECParametersHolder secp160r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
+            BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70");
+            BigInteger b = fromHex("B4E134D3FB59EB8BAB57274904664D5AF50388BA");
+            byte[] S = Hex.decode("B99B99B099B323E02709A4D696E6768756151751");
+            BigInteger n = fromHex("0100000000000000000000351EE786A818F3A1A16B");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
+                + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp192k1
+     */
+    static X9ECParametersHolder secp192k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37");
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(3);
+            byte[] S = null;
+            BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
+            BigInteger h = BigInteger.valueOf(1);
+
+            GLVTypeBParameters glv = new GLVTypeBParameters(
+                new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16),
+                new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16),
+                new BigInteger[]{
+                    new BigInteger("71169be7330b3038edb025f1", 16),
+                    new BigInteger("-b3fb3400dec5c4adceb8655c", 16) },
+                new BigInteger[]{
+                    new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
+                    new BigInteger("71169be7330b3038edb025f1", 16) },
+                new BigInteger("71169be7330b3038edb025f1d0f9", 16),
+                new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16),
+                208);
+
+            ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+                + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp192r1
+     */
+    static X9ECParametersHolder secp192r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^192 - 2^64 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF");
+            BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC");
+            BigInteger b = fromHex("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1");
+            byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
+            BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+                + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp224k1
+     */
+    static X9ECParametersHolder secp224k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D");
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(5);
+            byte[] S = null;
+            BigInteger n = fromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
+            BigInteger h = BigInteger.valueOf(1);
+
+            GLVTypeBParameters glv = new GLVTypeBParameters(
+                new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16),
+                new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16),
+                new BigInteger[]{
+                    new BigInteger("6b8cf07d4ca75c88957d9d670591", 16),
+                    new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) },
+                new BigInteger[]{
+                    new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
+                    new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
+                new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16),
+                new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16),
+                240);
+
+            ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv);
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+                + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp224r1
+     */
+    static X9ECParametersHolder secp224r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^224 - 2^96 + 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001");
+            BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE");
+            BigInteger b = fromHex("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4");
+            byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
+            BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+                + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp256k1
+     */
+    static X9ECParametersHolder secp256k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(7);
+            byte[] S = null;
+            BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
+            BigInteger h = BigInteger.valueOf(1);
+
+            GLVTypeBParameters glv = new GLVTypeBParameters(
+                new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16),
+                new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16),
+                new BigInteger[]{
+                    new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16),
+                    new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) },
+                new BigInteger[]{
+                    new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
+                    new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
+                new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16),
+                new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16),
+                272);
+
+            ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv);
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+                + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp256r1
+     */
+    static X9ECParametersHolder secp256r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1
+            BigInteger p = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
+            BigInteger a = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
+            BigInteger b = fromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
+            byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90");
+            BigInteger n = fromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+                + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp384r1
+     */
+    static X9ECParametersHolder secp384r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^384 - 2^128 - 2^96 + 2^32 - 1
+            BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF");
+            BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC");
+            BigInteger b = fromHex("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF");
+            byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
+            BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+                + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * secp521r1
+     */
+    static X9ECParametersHolder secp521r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            // p = 2^521 - 1
+            BigInteger p = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+            BigInteger a = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC");
+            BigInteger b = fromHex("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00");
+            byte[] S = Hex.decode("D09E8800291CB85396CC6717393284AAA0DA64BA");
+            BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409");
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h));
+
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
+                + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect113r1
+     */
+    static X9ECParametersHolder sect113r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 113;
+            int k = 9;
+
+            BigInteger a = fromHex("003088250CA6E7C7FE649CE85820F7");
+            BigInteger b = fromHex("00E8BEE4D3E2260744188BE0E9C723");
+            byte[] S = Hex.decode("10E723AB14D696E6768756151756FEBF8FCB49A9");
+            BigInteger n = fromHex("0100000000000000D9CCEC8A39E56F");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "009D73616F35F4AB1407D73562C10F"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "009D73616F35F4AB1407D73562C10F"
+                + "00A52830277958EE84D1315ED31886"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect113r2
+     */
+    static X9ECParametersHolder sect113r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 113;
+            int k = 9;
+
+            BigInteger a = fromHex("00689918DBEC7E5A0DD6DFC0AA55C7");
+            BigInteger b = fromHex("0095E9A9EC9B297BD4BF36E059184F");
+            byte[] S = Hex.decode("10C0FB15760860DEF1EEF4D696E676875615175D");
+            BigInteger n = fromHex("010000000000000108789B2496AF93");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "01A57A6A7B26CA5EF52FCDB8164797"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "01A57A6A7B26CA5EF52FCDB8164797"
+                + "00B3ADC94ED1FE674C06E695BABA1D"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect131r1
+     */
+    static X9ECParametersHolder sect131r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 131;
+            int k1 = 2;
+            int k2 = 3;
+            int k3 = 8;
+
+            BigInteger a = fromHex("07A11B09A76B562144418FF3FF8C2570B8");
+            BigInteger b = fromHex("0217C05610884B63B9C6C7291678F9D341");
+            byte[] S = Hex.decode("4D696E676875615175985BD3ADBADA21B43A97E2");
+            BigInteger n = fromHex("0400000000000000023123953A9464B54D");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "0081BAF91FDF9833C40F9C181343638399"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0081BAF91FDF9833C40F9C181343638399"
+                + "078C6E7EA38C001F73C8134B1B4EF9E150"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect131r2
+     */
+    static X9ECParametersHolder sect131r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 131;
+            int k1 = 2;
+            int k2 = 3;
+            int k3 = 8;
+
+            BigInteger a = fromHex("03E5A88919D7CAFCBF415F07C2176573B2");
+            BigInteger b = fromHex("04B8266A46C55657AC734CE38F018F2192");
+            byte[] S = Hex.decode("985BD3ADBAD4D696E676875615175A21B43A97E3");
+            BigInteger n = fromHex("0400000000000000016954A233049BA98F");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "0356DCD8F2F95031AD652D23951BB366A8"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0356DCD8F2F95031AD652D23951BB366A8"
+                + "0648F06D867940A5366D9E265DE9EB240F"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect163k1
+     */
+    static X9ECParametersHolder sect163k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 163;
+            int k1 = 3;
+            int k2 = 6;
+            int k3 = 7;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("04000000000000000000020108A2E0CC0D99F8A5EF");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
+                + "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect163r1
+     */
+    static X9ECParametersHolder sect163r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 163;
+            int k1 = 3;
+            int k2 = 6;
+            int k3 = 7;
+
+            BigInteger a = fromHex("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2");
+            BigInteger b = fromHex("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9");
+            byte[] S = Hex.decode("24B7B137C8A14D696E6768756151756FD0DA2E5C");
+            BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "0369979697AB43897789566789567F787A7876A654"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0369979697AB43897789566789567F787A7876A654"
+                + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect163r2
+     */
+    static X9ECParametersHolder sect163r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 163;
+            int k1 = 3;
+            int k2 = 6;
+            int k3 = 7;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = fromHex("020A601907B8C953CA1481EB10512F78744A3205FD");
+            byte[] S = Hex.decode("85E25BFE5C86226CDB12016F7553F9D0E693A268");
+            BigInteger n = fromHex("040000000000000000000292FE77E70C12A4234C33");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "03F0EBA16286A2D57EA0991168D4994637E8343E36"
+                + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect193r1
+     */
+    static X9ECParametersHolder sect193r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 193;
+            int k = 15;
+
+            BigInteger a = fromHex("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01");
+            BigInteger b = fromHex("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814");
+            byte[] S = Hex.decode("103FAEC74D696E676875615175777FC5B191EF30");
+            BigInteger n = fromHex("01000000000000000000000000C7F34A778F443ACC920EBA49");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"
+                + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect193r2
+     */
+    static X9ECParametersHolder sect193r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 193;
+            int k = 15;
+
+            BigInteger a = fromHex("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B");
+            BigInteger b = fromHex("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE");
+            byte[] S = Hex.decode("10B7B4D696E676875615175137C8A16FD0DA2211");
+            BigInteger n = fromHex("010000000000000000000000015AAB561B005413CCD4EE99D5");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"
+                + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect233k1
+     */
+    static X9ECParametersHolder sect233k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 233;
+            int k = 74;
+
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
+                + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect233r1
+     */
+    static X9ECParametersHolder sect233r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 233;
+            int k = 74;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = fromHex("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD");
+            byte[] S = Hex.decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3");
+            BigInteger n = fromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
+                + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect239k1
+     */
+    static X9ECParametersHolder sect239k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 239;
+            int k = 158;
+
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
+                + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect283k1
+     */
+    static X9ECParametersHolder sect283k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 283;
+            int k1 = 5;
+            int k2 = 7;
+            int k3 = 12;
+
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
+                + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect283r1
+     */
+    static X9ECParametersHolder sect283r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 283;
+            int k1 = 5;
+            int k2 = 7;
+            int k3 = 12;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = fromHex("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5");
+            byte[] S = Hex.decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE");
+            BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
+                + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect409k1
+     */
+    static X9ECParametersHolder sect409k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 409;
+            int k = 87;
+
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
+                + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect409r1
+     */
+    static X9ECParametersHolder sect409r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 409;
+            int k = 87;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = fromHex("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F");
+            byte[] S = Hex.decode("4099B5A457F9D69F79213D094C4BCD4D4262210B");
+            BigInteger n = fromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
+                + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect571k1
+     */
+    static X9ECParametersHolder sect571k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 571;
+            int k1 = 2;
+            int k2 = 5;
+            int k3 = 10;
+
+            BigInteger a = ECConstants.ZERO;
+            BigInteger b = BigInteger.valueOf(1);
+            byte[] S = null;
+            BigInteger n = fromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001");
+            BigInteger h = BigInteger.valueOf(4);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("02"
+            //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
+                + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+    /*
+     * sect571r1
+     */
+    static X9ECParametersHolder sect571r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            int m = 571;
+            int k1 = 2;
+            int k2 = 5;
+            int k3 = 10;
+
+            BigInteger a = BigInteger.valueOf(1);
+            BigInteger b = fromHex("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A");
+            byte[] S = Hex.decode("2AA058F73A0E33AB486B0F610410C53A7F132310");
+            BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47");
+            BigInteger h = BigInteger.valueOf(2);
+
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
+            //ECPoint G = curve.decodePoint(Hex.decode("03"
+            //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"));
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
+                + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
+
+            return new X9ECParameters(curve, G, n, h, S);
+        }
+    };
+
+
+    static final Hashtable objIds = new Hashtable();
+    static final Hashtable curves = new Hashtable();
+    static final Hashtable names = new Hashtable();
+
+    static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
+    {
+        objIds.put(name, oid);
+        names.put(oid, name);
+        curves.put(oid, holder);
+    }
+
+    static
+    {
+        defineCurve("secp112r1", SECObjectIdentifiers.secp112r1, secp112r1);
+        defineCurve("secp112r2", SECObjectIdentifiers.secp112r2, secp112r2);
+        defineCurve("secp128r1", SECObjectIdentifiers.secp128r1, secp128r1);
+        defineCurve("secp128r2", SECObjectIdentifiers.secp128r2, secp128r2);
+        defineCurve("secp160k1", SECObjectIdentifiers.secp160k1, secp160k1);
+        defineCurve("secp160r1", SECObjectIdentifiers.secp160r1, secp160r1);
+        defineCurve("secp160r2", SECObjectIdentifiers.secp160r2, secp160r2);
+        defineCurve("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1);
+        defineCurve("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1);
+        defineCurve("secp224k1", SECObjectIdentifiers.secp224k1, secp224k1);
+        defineCurve("secp224r1", SECObjectIdentifiers.secp224r1, secp224r1); 
+        defineCurve("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1);
+        defineCurve("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1); 
+        defineCurve("secp384r1", SECObjectIdentifiers.secp384r1, secp384r1); 
+        defineCurve("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1); 
+
+        defineCurve("sect113r1", SECObjectIdentifiers.sect113r1, sect113r1);
+        defineCurve("sect113r2", SECObjectIdentifiers.sect113r2, sect113r2);
+        defineCurve("sect131r1", SECObjectIdentifiers.sect131r1, sect131r1);
+        defineCurve("sect131r2", SECObjectIdentifiers.sect131r2, sect131r2);
+        defineCurve("sect163k1", SECObjectIdentifiers.sect163k1, sect163k1);
+        defineCurve("sect163r1", SECObjectIdentifiers.sect163r1, sect163r1);
+        defineCurve("sect163r2", SECObjectIdentifiers.sect163r2, sect163r2);
+        defineCurve("sect193r1", SECObjectIdentifiers.sect193r1, sect193r1);
+        defineCurve("sect193r2", SECObjectIdentifiers.sect193r2, sect193r2);
+        defineCurve("sect233k1", SECObjectIdentifiers.sect233k1, sect233k1);
+        defineCurve("sect233r1", SECObjectIdentifiers.sect233r1, sect233r1);
+        defineCurve("sect239k1", SECObjectIdentifiers.sect239k1, sect239k1);
+        defineCurve("sect283k1", SECObjectIdentifiers.sect283k1, sect283k1);
+        defineCurve("sect283r1", SECObjectIdentifiers.sect283r1, sect283r1);
+        defineCurve("sect409k1", SECObjectIdentifiers.sect409k1, sect409k1);
+        defineCurve("sect409r1", SECObjectIdentifiers.sect409r1, sect409r1);
+        defineCurve("sect571k1", SECObjectIdentifiers.sect571k1, sect571k1);
+        defineCurve("sect571r1", SECObjectIdentifiers.sect571r1, sect571r1); 
+    }
+
+    public static X9ECParameters getByName(
+        String name)
+    {
+        ASN1ObjectIdentifier oid = getOID(name);
+        return oid == null ? null : getByOID(oid);
+    }
+
+    /**
+     * return the X9ECParameters object for the named curve represented by
+     * the passed in object identifier. Null if the curve isn't present.
+     *
+     * @param oid an object identifier representing a named curve, if present.
+     */
+    public static X9ECParameters getByOID(
+        ASN1ObjectIdentifier oid)
+    {
+        X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);
+        return holder == null ? null : holder.getParameters();
+    }
+
+    /**
+     * return the object identifier signified by the passed in name. Null
+     * if there is no object identifier associated with name.
+     *
+     * @return the object identifier associated with name, if present.
+     */
+    public static ASN1ObjectIdentifier getOID(
+        String name)
+    {
+        return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+    }
+
+    /**
+     * return the named curve name represented by the given object identifier.
+     */
+    public static String getName(
+        ASN1ObjectIdentifier oid)
+    {
+        return (String)names.get(oid);
+    }
+
+    /**
+     * returns an enumeration containing the name strings for curves
+     * contained in this structure.
+     */
+    public static Enumeration getNames()
+    {
+        return names.elements();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
new file mode 100644
index 0000000..a0175a6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
@@ -0,0 +1,112 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.sec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+
+/**
+ * Certicom object identifiers
+ * <pre>
+ *  ellipticCurve OBJECT IDENTIFIER ::= {
+ *        iso(1) identified-organization(3) certicom(132) curve(0)
+ *  }
+ *  secg-scheme OBJECT IDENTIFIER ::= {
+ *     iso(1) identified-organization(3) certicom(132) schemes(1) }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface SECObjectIdentifiers
+{
+    /** Base OID: 1.3.132.0 */
+    static final ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier("1.3.132.0");
+
+    /**  sect163k1 OID: 1.3.132.0.1 */
+    static final ASN1ObjectIdentifier sect163k1 = ellipticCurve.branch("1");
+    /**  sect163r1 OID: 1.3.132.0.2 */
+    static final ASN1ObjectIdentifier sect163r1 = ellipticCurve.branch("2");
+    /**  sect239k1 OID: 1.3.132.0.3 */
+    static final ASN1ObjectIdentifier sect239k1 = ellipticCurve.branch("3");
+    /**  sect113r1 OID: 1.3.132.0.4 */
+    static final ASN1ObjectIdentifier sect113r1 = ellipticCurve.branch("4");
+    /**  sect113r2 OID: 1.3.132.0.5 */
+    static final ASN1ObjectIdentifier sect113r2 = ellipticCurve.branch("5");
+    /**  secp112r1 OID: 1.3.132.0.6 */
+    static final ASN1ObjectIdentifier secp112r1 = ellipticCurve.branch("6");
+    /**  secp112r2 OID: 1.3.132.0.7 */
+    static final ASN1ObjectIdentifier secp112r2 = ellipticCurve.branch("7");
+    /**  secp160r1 OID: 1.3.132.0.8 */
+    static final ASN1ObjectIdentifier secp160r1 = ellipticCurve.branch("8");
+    /**  secp160k1 OID: 1.3.132.0.9 */
+    static final ASN1ObjectIdentifier secp160k1 = ellipticCurve.branch("9");
+    /**  secp256k1 OID: 1.3.132.0.10 */
+    static final ASN1ObjectIdentifier secp256k1 = ellipticCurve.branch("10");
+    /**  sect163r2 OID: 1.3.132.0.15 */
+    static final ASN1ObjectIdentifier sect163r2 = ellipticCurve.branch("15");
+    /**  sect283k1 OID: 1.3.132.0.16 */
+    static final ASN1ObjectIdentifier sect283k1 = ellipticCurve.branch("16");
+    /**  sect283r1 OID: 1.3.132.0.17 */
+    static final ASN1ObjectIdentifier sect283r1 = ellipticCurve.branch("17");
+    /**  sect131r1 OID: 1.3.132.0.22 */
+    static final ASN1ObjectIdentifier sect131r1 = ellipticCurve.branch("22");
+    /**  sect131r2 OID: 1.3.132.0.23 */
+    static final ASN1ObjectIdentifier sect131r2 = ellipticCurve.branch("23");
+    /**  sect193r1 OID: 1.3.132.0.24 */
+    static final ASN1ObjectIdentifier sect193r1 = ellipticCurve.branch("24");
+    /**  sect193r2 OID: 1.3.132.0.25 */
+    static final ASN1ObjectIdentifier sect193r2 = ellipticCurve.branch("25");
+    /**  sect233k1 OID: 1.3.132.0.26 */
+    static final ASN1ObjectIdentifier sect233k1 = ellipticCurve.branch("26");
+    /**  sect233r1 OID: 1.3.132.0.27 */
+    static final ASN1ObjectIdentifier sect233r1 = ellipticCurve.branch("27");
+    /**  secp128r1 OID: 1.3.132.0.28 */
+    static final ASN1ObjectIdentifier secp128r1 = ellipticCurve.branch("28");
+    /**  secp128r2 OID: 1.3.132.0.29 */
+    static final ASN1ObjectIdentifier secp128r2 = ellipticCurve.branch("29");
+    /**  secp160r2 OID: 1.3.132.0.30 */
+    static final ASN1ObjectIdentifier secp160r2 = ellipticCurve.branch("30");
+    /**  secp192k1 OID: 1.3.132.0.31 */
+    static final ASN1ObjectIdentifier secp192k1 = ellipticCurve.branch("31");
+    /**  secp224k1 OID: 1.3.132.0.32 */
+    static final ASN1ObjectIdentifier secp224k1 = ellipticCurve.branch("32");
+    /**  secp224r1 OID: 1.3.132.0.33 */
+    static final ASN1ObjectIdentifier secp224r1 = ellipticCurve.branch("33");
+    /**  secp384r1 OID: 1.3.132.0.34 */
+    static final ASN1ObjectIdentifier secp384r1 = ellipticCurve.branch("34");
+    /**  secp521r1 OID: 1.3.132.0.35 */
+    static final ASN1ObjectIdentifier secp521r1 = ellipticCurve.branch("35");
+    /**  sect409k1 OID: 1.3.132.0.36 */
+    static final ASN1ObjectIdentifier sect409k1 = ellipticCurve.branch("36");
+    /**  sect409r1 OID: 1.3.132.0.37 */
+    static final ASN1ObjectIdentifier sect409r1 = ellipticCurve.branch("37");
+    /**  sect571k1 OID: 1.3.132.0.38 */
+    static final ASN1ObjectIdentifier sect571k1 = ellipticCurve.branch("38");
+    /**  sect571r1 OID: 1.3.132.0.39 */
+    static final ASN1ObjectIdentifier sect571r1 = ellipticCurve.branch("39");
+
+    /**  secp192r1 OID: 1.3.132.0.prime192v1 */
+    static final ASN1ObjectIdentifier secp192r1 = X9ObjectIdentifiers.prime192v1;
+    /**  secp256r1 OID: 1.3.132.0.prime256v1 */
+    static final ASN1ObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1;
+
+    static final ASN1ObjectIdentifier secg_scheme = new ASN1ObjectIdentifier("1.3.132.1");
+
+    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha224kdf_scheme = secg_scheme.branch("11.0");
+    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha256kdf_scheme = secg_scheme.branch("11.1");
+    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha384kdf_scheme = secg_scheme.branch("11.2");
+    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha512kdf_scheme = secg_scheme.branch("11.3");
+
+    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha224kdf_scheme = secg_scheme.branch("14.0");
+    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha256kdf_scheme = secg_scheme.branch("14.1");
+    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha384kdf_scheme = secg_scheme.branch("14.2");
+    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha512kdf_scheme = secg_scheme.branch("14.3");
+
+    static final ASN1ObjectIdentifier mqvSinglePass_sha224kdf_scheme = secg_scheme.branch("15.0");
+    static final ASN1ObjectIdentifier mqvSinglePass_sha256kdf_scheme = secg_scheme.branch("15.1");
+    static final ASN1ObjectIdentifier mqvSinglePass_sha384kdf_scheme = secg_scheme.branch("15.2");
+    static final ASN1ObjectIdentifier mqvSinglePass_sha512kdf_scheme = secg_scheme.branch("15.3");
+
+    static final ASN1ObjectIdentifier mqvFull_sha224kdf_scheme = secg_scheme.branch("16.0");
+    static final ASN1ObjectIdentifier mqvFull_sha256kdf_scheme = secg_scheme.branch("16.1");
+    static final ASN1ObjectIdentifier mqvFull_sha384kdf_scheme = secg_scheme.branch("16.2");
+    static final ASN1ObjectIdentifier mqvFull_sha512kdf_scheme = secg_scheme.branch("16.3");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
new file mode 100644
index 0000000..5c7041e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
@@ -0,0 +1,79 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.teletrust;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * Object identifiers based on the TeleTrust branch.
+ * <pre>
+ * TeleTrusT:
+ *   { iso(1) identifier-organization(3) teleTrust(36) algorithm(3)
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface TeleTrusTObjectIdentifiers
+{
+    /** 1.3.36.3 */
+    static final ASN1ObjectIdentifier teleTrusTAlgorithm = new ASN1ObjectIdentifier("1.3.36.3");
+
+    /** 1.3.36.3.2.1 */
+    static final ASN1ObjectIdentifier    ripemd160           = teleTrusTAlgorithm.branch("2.1");
+    /** 1.3.36.3.2.2 */
+    static final ASN1ObjectIdentifier    ripemd128           = teleTrusTAlgorithm.branch("2.2");
+    /** 1.3.36.3.2.3 */
+    static final ASN1ObjectIdentifier    ripemd256           = teleTrusTAlgorithm.branch("2.3");
+
+    /** 1.3.36.3.3.1 */
+    static final ASN1ObjectIdentifier teleTrusTRSAsignatureAlgorithm = teleTrusTAlgorithm.branch("3.1");
+
+    /** 1.3.36.3.3.1.2 */
+    static final ASN1ObjectIdentifier rsaSignatureWithripemd160      = teleTrusTRSAsignatureAlgorithm.branch("2");
+    /** 1.3.36.3.3.1.3 */
+    static final ASN1ObjectIdentifier rsaSignatureWithripemd128      = teleTrusTRSAsignatureAlgorithm.branch("3");
+    /** 1.3.36.3.3.1.4 */
+    static final ASN1ObjectIdentifier rsaSignatureWithripemd256      = teleTrusTRSAsignatureAlgorithm.branch("4");
+
+    /** 1.3.36.3.3.2 */
+    static final ASN1ObjectIdentifier    ecSign               = teleTrusTAlgorithm.branch("3.2");
+
+    /** 1.3.36.3.3.2,1 */
+    static final ASN1ObjectIdentifier    ecSignWithSha1       = ecSign.branch("1");
+    /** 1.3.36.3.3.2.2 */
+    static final ASN1ObjectIdentifier    ecSignWithRipemd160  = ecSign.branch("2");
+
+    /** 1.3.36.3.3.2.8 */
+    static final ASN1ObjectIdentifier ecc_brainpool = teleTrusTAlgorithm.branch("3.2.8");
+    /** 1.3.36.3.3.2.8.1 */
+    static final ASN1ObjectIdentifier ellipticCurve = ecc_brainpool.branch("1");
+    /** 1.3.36.3.3.2.8.1.1 */
+    static final ASN1ObjectIdentifier versionOne = ellipticCurve.branch("1");
+
+    /** 1.3.36.3.3.2.8.1.1.1 */
+    static final ASN1ObjectIdentifier brainpoolP160r1 = versionOne.branch("1");
+    /** 1.3.36.3.3.2.8.1.1.2 */
+    static final ASN1ObjectIdentifier brainpoolP160t1 = versionOne.branch("2");
+    /** 1.3.36.3.3.2.8.1.1.3 */
+    static final ASN1ObjectIdentifier brainpoolP192r1 = versionOne.branch("3");
+    /** 1.3.36.3.3.2.8.1.1.4 */
+    static final ASN1ObjectIdentifier brainpoolP192t1 = versionOne.branch("4");
+    /** 1.3.36.3.3.2.8.1.1.5 */
+    static final ASN1ObjectIdentifier brainpoolP224r1 = versionOne.branch("5");
+    /** 1.3.36.3.3.2.8.1.1.6 */
+    static final ASN1ObjectIdentifier brainpoolP224t1 = versionOne.branch("6");
+    /** 1.3.36.3.3.2.8.1.1.7 */
+    static final ASN1ObjectIdentifier brainpoolP256r1 = versionOne.branch("7");
+    /** 1.3.36.3.3.2.8.1.1.8 */
+    static final ASN1ObjectIdentifier brainpoolP256t1 = versionOne.branch("8");
+    /** 1.3.36.3.3.2.8.1.1.9 */
+    static final ASN1ObjectIdentifier brainpoolP320r1 = versionOne.branch("9");
+    /** 1.3.36.3.3.2.8.1.1.10 */
+    static final ASN1ObjectIdentifier brainpoolP320t1 = versionOne.branch("10");
+    /** 1.3.36.3.3.2.8.1.1.11 */
+    static final ASN1ObjectIdentifier brainpoolP384r1 = versionOne.branch("11");
+    /** 1.3.36.3.3.2.8.1.1.12 */
+    static final ASN1ObjectIdentifier brainpoolP384t1 = versionOne.branch("12");
+    /** 1.3.36.3.3.2.8.1.1.13 */
+    static final ASN1ObjectIdentifier brainpoolP512r1 = versionOne.branch("13");
+    /** 1.3.36.3.3.2.8.1.1.14 */
+    static final ASN1ObjectIdentifier brainpoolP512t1 = versionOne.branch("14");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/util/ASN1Dump.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/util/ASN1Dump.java
new file mode 100644
index 0000000..e904391
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/util/ASN1Dump.java
@@ -0,0 +1,429 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.util;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ApplicationSpecific;
+import com.android.internal.org.bouncycastle.asn1.ASN1Boolean;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated;
+import com.android.internal.org.bouncycastle.asn1.ASN1External;
+import com.android.internal.org.bouncycastle.asn1.ASN1GeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.ASN1UTCTime;
+import com.android.internal.org.bouncycastle.asn1.BERApplicationSpecific;
+import com.android.internal.org.bouncycastle.asn1.BEROctetString;
+import com.android.internal.org.bouncycastle.asn1.BERSequence;
+import com.android.internal.org.bouncycastle.asn1.BERSet;
+import com.android.internal.org.bouncycastle.asn1.BERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.BERTags;
+import com.android.internal.org.bouncycastle.asn1.DERApplicationSpecific;
+import com.android.internal.org.bouncycastle.asn1.DERBMPString;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERGraphicString;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DERPrintableString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERSet;
+import com.android.internal.org.bouncycastle.asn1.DERT61String;
+import com.android.internal.org.bouncycastle.asn1.DERUTF8String;
+import com.android.internal.org.bouncycastle.asn1.DERVideotexString;
+import com.android.internal.org.bouncycastle.asn1.DERVisibleString;
+import com.android.internal.org.bouncycastle.asn1.DLApplicationSpecific;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * Utility class for dumping ASN.1 objects as (hopefully) human friendly strings.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ASN1Dump
+{
+    private static final String  TAB = "    ";
+    private static final int SAMPLE_SIZE = 32;
+
+    /**
+     * dump a DER object as a formatted string with indentation
+     *
+     * @param obj the ASN1Primitive to be dumped out.
+     */
+    static void _dumpAsString(
+        String      indent,
+        boolean     verbose,
+        ASN1Primitive obj,
+        StringBuffer    buf)
+    {
+        String nl = Strings.lineSeparator();
+        if (obj instanceof ASN1Sequence)
+        {
+            Enumeration     e = ((ASN1Sequence)obj).getObjects();
+            String          tab = indent + TAB;
+
+            buf.append(indent);
+            if (obj instanceof BERSequence)
+            {
+                buf.append("BER Sequence");
+            }
+            else if (obj instanceof DERSequence)
+            {
+                buf.append("DER Sequence");
+            }
+            else
+            {
+                buf.append("Sequence");
+            }
+
+            buf.append(nl);
+
+            while (e.hasMoreElements())
+            {
+                Object  o = e.nextElement();
+
+                if (o == null || o.equals(DERNull.INSTANCE))
+                {
+                    buf.append(tab);
+                    buf.append("NULL");
+                    buf.append(nl);
+                }
+                else if (o instanceof ASN1Primitive)
+                {
+                    _dumpAsString(tab, verbose, (ASN1Primitive)o, buf);
+                }
+                else
+                {
+                    _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf);
+                }
+            }
+        }
+        else if (obj instanceof ASN1TaggedObject)
+        {
+            String          tab = indent + TAB;
+
+            buf.append(indent);
+            if (obj instanceof BERTaggedObject)
+            {
+                buf.append("BER Tagged [");
+            }
+            else
+            {
+                buf.append("Tagged [");
+            }
+
+            ASN1TaggedObject o = (ASN1TaggedObject)obj;
+
+            buf.append(Integer.toString(o.getTagNo()));
+            buf.append(']');
+
+            if (!o.isExplicit())
+            {
+                buf.append(" IMPLICIT ");
+            }
+
+            buf.append(nl);
+
+            if (o.isEmpty())
+            {
+                buf.append(tab);
+                buf.append("EMPTY");
+                buf.append(nl);
+            }
+            else
+            {
+                _dumpAsString(tab, verbose, o.getObject(), buf);
+            }
+        }
+        else if (obj instanceof ASN1Set)
+        {
+            Enumeration     e = ((ASN1Set)obj).getObjects();
+            String          tab = indent + TAB;
+
+            buf.append(indent);
+
+            if (obj instanceof BERSet)
+            {
+                buf.append("BER Set");
+            }
+            else if (obj instanceof DERSet)
+            {
+                buf.append("DER Set");
+            }
+            else
+            {
+                buf.append("Set");
+            }
+            buf.append(nl);
+
+            while (e.hasMoreElements())
+            {
+                Object  o = e.nextElement();
+
+                if (o == null)
+                {
+                    buf.append(tab);
+                    buf.append("NULL");
+                    buf.append(nl);
+                }
+                else if (o instanceof ASN1Primitive)
+                {
+                    _dumpAsString(tab, verbose, (ASN1Primitive)o, buf);
+                }
+                else
+                {
+                    _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf);
+                }
+            }
+        }
+        else if (obj instanceof ASN1OctetString)
+        {
+            ASN1OctetString oct = (ASN1OctetString)obj;
+
+            if (obj instanceof BEROctetString)
+            {
+                buf.append(indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] ");
+            }
+            else
+            {
+                buf.append(indent + "DER Octet String" + "[" + oct.getOctets().length + "] ");
+            }
+            if (verbose)
+            {
+                buf.append(dumpBinaryDataAsString(indent, oct.getOctets()));
+            }
+            else
+            {
+                buf.append(nl);
+            }
+        }
+        else if (obj instanceof ASN1ObjectIdentifier)
+        {
+            buf.append(indent + "ObjectIdentifier(" + ((ASN1ObjectIdentifier)obj).getId() + ")" + nl);
+        }
+        else if (obj instanceof ASN1Boolean)
+        {
+            buf.append(indent + "Boolean(" + ((ASN1Boolean)obj).isTrue() + ")" + nl);
+        }
+        else if (obj instanceof ASN1Integer)
+        {
+            buf.append(indent + "Integer(" + ((ASN1Integer)obj).getValue() + ")" + nl);
+        }
+        else if (obj instanceof DERBitString)
+        {
+            DERBitString bt = (DERBitString)obj;
+            buf.append(indent + "DER Bit String" + "[" + bt.getBytes().length + ", " + bt.getPadBits() + "] ");
+            if (verbose)
+            {
+                buf.append(dumpBinaryDataAsString(indent, bt.getBytes()));
+            }
+            else
+            {
+                buf.append(nl);
+            }
+        }
+        else if (obj instanceof DERIA5String)
+        {
+            buf.append(indent + "IA5String(" + ((DERIA5String)obj).getString() + ") " + nl);
+        }
+        else if (obj instanceof DERUTF8String)
+        {
+            buf.append(indent + "UTF8String(" + ((DERUTF8String)obj).getString() + ") " + nl);
+        }
+        else if (obj instanceof DERPrintableString)
+        {
+            buf.append(indent + "PrintableString(" + ((DERPrintableString)obj).getString() + ") " + nl);
+        }
+        else if (obj instanceof DERVisibleString)
+        {
+            buf.append(indent + "VisibleString(" + ((DERVisibleString)obj).getString() + ") " + nl);
+        }
+        else if (obj instanceof DERBMPString)
+        {
+            buf.append(indent + "BMPString(" + ((DERBMPString)obj).getString() + ") " + nl);
+        }
+        else if (obj instanceof DERT61String)
+        {
+            buf.append(indent + "T61String(" + ((DERT61String)obj).getString() + ") " + nl);
+        }
+        else if (obj instanceof DERGraphicString)
+        {
+            buf.append(indent + "GraphicString(" + ((DERGraphicString)obj).getString() + ") " + nl);
+        }
+        else if (obj instanceof DERVideotexString)
+        {
+            buf.append(indent + "VideotexString(" + ((DERVideotexString)obj).getString() + ") " + nl);
+        }
+        else if (obj instanceof ASN1UTCTime)
+        {
+            buf.append(indent + "UTCTime(" + ((ASN1UTCTime)obj).getTime() + ") " + nl);
+        }
+        else if (obj instanceof ASN1GeneralizedTime)
+        {
+            buf.append(indent + "GeneralizedTime(" + ((ASN1GeneralizedTime)obj).getTime() + ") " + nl);
+        }
+        else if (obj instanceof BERApplicationSpecific)
+        {
+            buf.append(outputApplicationSpecific("BER", indent, verbose, obj, nl));
+        }
+        else if (obj instanceof DERApplicationSpecific)
+        {
+            buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl));
+        }
+        else if (obj instanceof DLApplicationSpecific)
+        {
+            buf.append(outputApplicationSpecific("", indent, verbose, obj, nl));
+        }
+        else if (obj instanceof ASN1Enumerated)
+        {
+            ASN1Enumerated en = (ASN1Enumerated) obj;
+            buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl);
+        }
+        else if (obj instanceof ASN1External)
+        {
+            ASN1External ext = (ASN1External) obj;
+            buf.append(indent + "External " + nl);
+            String          tab = indent + TAB;
+            if (ext.getDirectReference() != null)
+            {
+                buf.append(tab + "Direct Reference: " + ext.getDirectReference().getId() + nl);
+            }
+            if (ext.getIndirectReference() != null)
+            {
+                buf.append(tab + "Indirect Reference: " + ext.getIndirectReference().toString() + nl);
+            }
+            if (ext.getDataValueDescriptor() != null)
+            {
+                _dumpAsString(tab, verbose, ext.getDataValueDescriptor(), buf);
+            }
+            buf.append(tab + "Encoding: " + ext.getEncoding() + nl);
+            _dumpAsString(tab, verbose, ext.getExternalContent(), buf);
+        }
+        else
+        {
+            buf.append(indent + obj.toString() + nl);
+        }
+    }
+    
+    private static String outputApplicationSpecific(String type, String indent, boolean verbose, ASN1Primitive obj, String nl)
+    {
+        ASN1ApplicationSpecific app = ASN1ApplicationSpecific.getInstance(obj);
+        StringBuffer buf = new StringBuffer();
+
+        if (app.isConstructed())
+        {
+            try
+            {
+                ASN1Sequence s = ASN1Sequence.getInstance(app.getObject(BERTags.SEQUENCE));
+                buf.append(indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "]" + nl);
+                for (Enumeration e = s.getObjects(); e.hasMoreElements();)
+                {
+                    _dumpAsString(indent + TAB, verbose, (ASN1Primitive)e.nextElement(), buf);
+                }
+            }
+            catch (IOException e)
+            {
+                buf.append(e);
+            }
+            return buf.toString();
+        }
+
+        return indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "] (" + Strings.fromByteArray(Hex.encode(app.getContents())) + ")" + nl;
+    }
+
+    /**
+     * dump out a DER object as a formatted string, in non-verbose mode.
+     *
+     * @param obj the ASN1Primitive to be dumped out.
+     * @return  the resulting string.
+     */
+    public static String dumpAsString(
+        Object   obj)
+    {
+        return dumpAsString(obj, false);
+    }
+
+    /**
+     * Dump out the object as a string.
+     *
+     * @param obj  the object to be dumped
+     * @param verbose  if true, dump out the contents of octet and bit strings.
+     * @return  the resulting string.
+     */
+    public static String dumpAsString(
+        Object   obj,
+        boolean  verbose)
+    {
+        StringBuffer buf = new StringBuffer();
+
+        if (obj instanceof ASN1Primitive)
+        {
+            _dumpAsString("", verbose, (ASN1Primitive)obj, buf);
+        }
+        else if (obj instanceof ASN1Encodable)
+        {
+            _dumpAsString("", verbose, ((ASN1Encodable)obj).toASN1Primitive(), buf);
+        }
+        else
+        {
+            return "unknown object type " + obj.toString();
+        }
+
+        return buf.toString();
+    }
+
+    private static String dumpBinaryDataAsString(String indent, byte[] bytes)
+    {
+        String nl = Strings.lineSeparator();
+        StringBuffer buf = new StringBuffer();
+
+        indent += TAB;
+        
+        buf.append(nl);
+        for (int i = 0; i < bytes.length; i += SAMPLE_SIZE)
+        {
+            if (bytes.length - i > SAMPLE_SIZE)
+            {
+                buf.append(indent);
+                buf.append(Strings.fromByteArray(Hex.encode(bytes, i, SAMPLE_SIZE)));
+                buf.append(TAB);
+                buf.append(calculateAscString(bytes, i, SAMPLE_SIZE));
+                buf.append(nl);
+            }
+            else
+            {
+                buf.append(indent);
+                buf.append(Strings.fromByteArray(Hex.encode(bytes, i, bytes.length - i)));
+                for (int j = bytes.length - i; j != SAMPLE_SIZE; j++)
+                {
+                    buf.append("  ");
+                }
+                buf.append(TAB);
+                buf.append(calculateAscString(bytes, i, bytes.length - i));
+                buf.append(nl);
+            }
+        }
+        
+        return buf.toString();
+    }
+
+    private static String calculateAscString(byte[] bytes, int off, int len)
+    {
+        StringBuffer buf = new StringBuffer();
+
+        for (int i = off; i != off + len; i++)
+        {
+            if (bytes[i] >= ' ' && bytes[i] <= '~')
+            {
+                buf.append((char)bytes[i]);
+            }
+        }
+
+        return buf.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java
new file mode 100644
index 0000000..5c68a35
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java
@@ -0,0 +1,77 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * Holding class for the AttributeTypeAndValue structures that make up an RDN.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AttributeTypeAndValue
+    extends ASN1Object
+{
+    private ASN1ObjectIdentifier type;
+    private ASN1Encodable       value;
+
+    private AttributeTypeAndValue(ASN1Sequence seq)
+    {
+        type = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+        value = (ASN1Encodable)seq.getObjectAt(1);
+    }
+
+    public static AttributeTypeAndValue getInstance(Object o)
+    {
+        if (o instanceof AttributeTypeAndValue)
+        {
+            return (AttributeTypeAndValue)o;
+        }
+        else if (o != null)
+        {
+            return new AttributeTypeAndValue(ASN1Sequence.getInstance(o));
+        }
+
+        throw new IllegalArgumentException("null value in getInstance()");
+    }
+
+    public AttributeTypeAndValue(
+        ASN1ObjectIdentifier type,
+        ASN1Encodable value)
+    {
+        this.type = type;
+        this.value = value;
+    }
+
+    public ASN1ObjectIdentifier getType()
+    {
+        return type;
+    }
+
+    public ASN1Encodable getValue()
+    {
+        return value;
+    }
+
+    /**
+     * <pre>
+     * AttributeTypeAndValue ::= SEQUENCE {
+     *           type         OBJECT IDENTIFIER,
+     *           value        ANY DEFINED BY type }
+     * </pre>
+     * @return a basic ASN.1 object representation.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(type);
+        v.add(value);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/DirectoryString.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/DirectoryString.java
new file mode 100644
index 0000000..d13ae8f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/DirectoryString.java
@@ -0,0 +1,130 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Choice;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1String;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBMPString;
+import com.android.internal.org.bouncycastle.asn1.DERPrintableString;
+import com.android.internal.org.bouncycastle.asn1.DERT61String;
+import com.android.internal.org.bouncycastle.asn1.DERUTF8String;
+import com.android.internal.org.bouncycastle.asn1.DERUniversalString;
+
+/**
+ * The DirectoryString CHOICE object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DirectoryString
+    extends ASN1Object
+    implements ASN1Choice, ASN1String
+{
+    private ASN1String string;
+
+    public static DirectoryString getInstance(Object o)
+    {
+        if (o == null || o instanceof DirectoryString)
+        {
+            return (DirectoryString)o;
+        }
+
+        if (o instanceof DERT61String)
+        {
+            return new DirectoryString((DERT61String)o);
+        }
+
+        if (o instanceof DERPrintableString)
+        {
+            return new DirectoryString((DERPrintableString)o);
+        }
+
+        if (o instanceof DERUniversalString)
+        {
+            return new DirectoryString((DERUniversalString)o);
+        }
+
+        if (o instanceof DERUTF8String)
+        {
+            return new DirectoryString((DERUTF8String)o);
+        }
+
+        if (o instanceof DERBMPString)
+        {
+            return new DirectoryString((DERBMPString)o);
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + o.getClass().getName());
+    }
+
+    public static DirectoryString getInstance(ASN1TaggedObject o, boolean explicit)
+    {
+        if (!explicit)
+        {
+            throw new IllegalArgumentException("choice item must be explicitly tagged");
+        }
+
+        return getInstance(o.getObject());
+    }
+
+    private DirectoryString(
+        DERT61String string)
+    {
+        this.string = string;
+    }
+
+    private DirectoryString(
+        DERPrintableString string)
+    {
+        this.string = string;
+    }
+
+    private DirectoryString(
+        DERUniversalString string)
+    {
+        this.string = string;
+    }
+
+    private DirectoryString(
+        DERUTF8String string)
+    {
+        this.string = string;
+    }
+
+    private DirectoryString(
+        DERBMPString string)
+    {
+        this.string = string;
+    }
+
+    public DirectoryString(String string)
+    {
+        this.string = new DERUTF8String(string);
+    }
+
+    public String getString()
+    {
+        return string.getString();
+    }
+
+    public String toString()
+    {
+        return string.getString();
+    }
+
+    /**
+     * <pre>
+     *  DirectoryString ::= CHOICE {
+     *    teletexString               TeletexString (SIZE (1..MAX)),
+     *    printableString             PrintableString (SIZE (1..MAX)),
+     *    universalString             UniversalString (SIZE (1..MAX)),
+     *    utf8String                  UTF8String (SIZE (1..MAX)),
+     *    bmpString                   BMPString (SIZE (1..MAX))  }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return ((ASN1Encodable)string).toASN1Primitive();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/RDN.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/RDN.java
new file mode 100644
index 0000000..efcca20
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/RDN.java
@@ -0,0 +1,124 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERSet;
+
+/**
+ * Holding class for a single Relative Distinguished Name (RDN).
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RDN
+    extends ASN1Object
+{
+    private ASN1Set values;
+
+    private RDN(ASN1Set values)
+    {
+        this.values = values;
+    }
+
+    public static RDN getInstance(Object obj)
+    {
+        if (obj instanceof RDN)
+        {
+            return (RDN)obj;
+        }
+        else if (obj != null)
+        {
+            return new RDN(ASN1Set.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * Create a single valued RDN.
+     *
+     * @param oid RDN type.
+     * @param value RDN value.
+     */
+    public RDN(ASN1ObjectIdentifier oid, ASN1Encodable value)
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(oid);
+        v.add(value);
+
+        this.values = new DERSet(new DERSequence(v));
+    }
+
+    public RDN(AttributeTypeAndValue attrTAndV)
+    {
+        this.values = new DERSet(attrTAndV);
+    }
+
+    /**
+     * Create a multi-valued RDN.
+     *
+     * @param aAndVs attribute type/value pairs making up the RDN
+     */
+    public RDN(AttributeTypeAndValue[] aAndVs)
+    {
+        this.values = new DERSet(aAndVs);
+    }
+
+    public boolean isMultiValued()
+    {
+        return this.values.size() > 1;
+    }
+
+    /**
+     * Return the number of AttributeTypeAndValue objects in this RDN,
+     *
+     * @return size of RDN, greater than 1 if multi-valued.
+     */
+    public int size()
+    {
+        return this.values.size();
+    }
+
+    public AttributeTypeAndValue getFirst()
+    {
+        if (this.values.size() == 0)
+        {
+            return null;
+        }
+
+        return AttributeTypeAndValue.getInstance(this.values.getObjectAt(0));
+    }
+
+    public AttributeTypeAndValue[] getTypesAndValues()
+    {
+        AttributeTypeAndValue[] tmp = new AttributeTypeAndValue[values.size()];
+
+        for (int i = 0; i != tmp.length; i++)
+        {
+            tmp[i] = AttributeTypeAndValue.getInstance(values.getObjectAt(i));
+        }
+
+        return tmp;
+    }
+
+    /**
+     * <pre>
+     * RelativeDistinguishedName ::=
+     *                     SET OF AttributeTypeAndValue
+
+     * AttributeTypeAndValue ::= SEQUENCE {
+     *        type     AttributeType,
+     *        value    AttributeValue }
+     * </pre>
+     * @return this object as its ASN1Primitive type
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return values;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/X500Name.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/X500Name.java
new file mode 100644
index 0000000..63a4a22
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/X500Name.java
@@ -0,0 +1,341 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Choice;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x500.style.BCStyle;
+
+/**
+ * The X.500 Name object.
+ * <pre>
+ *     Name ::= CHOICE {
+ *                       RDNSequence }
+ *
+ *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+ *
+ *     AttributeTypeAndValue ::= SEQUENCE {
+ *                                   type  OBJECT IDENTIFIER,
+ *                                   value ANY }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X500Name
+    extends ASN1Object
+    implements ASN1Choice
+{
+    private static X500NameStyle    defaultStyle = BCStyle.INSTANCE;
+
+    private boolean                 isHashCodeCalculated;
+    private int                     hashCodeValue;
+
+    private X500NameStyle style;
+    private RDN[] rdns;
+
+    /**
+     * @deprecated use the getInstance() method that takes a style.
+     */
+    public X500Name(X500NameStyle style, X500Name name)
+    {
+        this.rdns = name.rdns;
+        this.style = style;
+    }
+
+    /**
+     * Return a X500Name based on the passed in tagged object.
+     * 
+     * @param obj tag object holding name.
+     * @param explicit true if explicitly tagged false otherwise.
+     * @return the X500Name
+     */
+    public static X500Name getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        // must be true as choice item
+        return getInstance(ASN1Sequence.getInstance(obj, true));
+    }
+
+    public static X500Name getInstance(
+        Object  obj)
+    {
+        if (obj instanceof X500Name)
+        {
+            return (X500Name)obj;
+        }
+        else if (obj != null)
+        {
+            return new X500Name(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static X500Name getInstance(
+        X500NameStyle style,
+        Object        obj)
+    {
+        if (obj instanceof X500Name)
+        {
+            return new X500Name(style, (X500Name)obj);
+        }
+        else if (obj != null)
+        {
+            return new X500Name(style, ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * Constructor from ASN1Sequence
+     *
+     * the principal will be a list of constructed sets, each containing an (OID, String) pair.
+     */
+    private X500Name(
+        ASN1Sequence  seq)
+    {
+        this(defaultStyle, seq);
+    }
+
+    private X500Name(
+        X500NameStyle style,
+        ASN1Sequence  seq)
+    {
+        this.style = style;
+        this.rdns = new RDN[seq.size()];
+
+        int index = 0;
+
+        for (Enumeration e = seq.getObjects(); e.hasMoreElements();)
+        {
+            rdns[index++] = RDN.getInstance(e.nextElement());
+        }
+    }
+
+    public X500Name(
+        RDN[] rDNs)
+    {
+        this(defaultStyle, rDNs);
+    }
+
+    public X500Name(
+        X500NameStyle style,
+        RDN[]         rDNs)
+    {
+        this.rdns = copy(rDNs);
+        this.style = style;
+    }
+
+    public X500Name(
+        String dirName)
+    {
+        this(defaultStyle, dirName);
+    }
+
+    public X500Name(
+        X500NameStyle style,
+        String        dirName)
+    {
+        this(style.fromString(dirName));
+
+        this.style = style;
+    }
+
+    /**
+     * return an array of RDNs in structure order.
+     *
+     * @return an array of RDN objects.
+     */
+    public RDN[] getRDNs()
+    {
+        RDN[] tmp = new RDN[this.rdns.length];
+
+        System.arraycopy(rdns, 0, tmp, 0, tmp.length);
+
+        return tmp;
+    }
+
+    /**
+     * return an array of OIDs contained in the attribute type of each RDN in structure order.
+     *
+     * @return an array, possibly zero length, of ASN1ObjectIdentifiers objects.
+     */
+    public ASN1ObjectIdentifier[] getAttributeTypes()
+    {
+        int   count = 0;
+
+        for (int i = 0; i != rdns.length; i++)
+        {
+            RDN rdn = rdns[i];
+
+            count += rdn.size();
+        }
+
+        ASN1ObjectIdentifier[] res = new ASN1ObjectIdentifier[count];
+
+        count = 0;
+
+        for (int i = 0; i != rdns.length; i++)
+        {
+            RDN rdn = rdns[i];
+
+            if (rdn.isMultiValued())
+            {
+                AttributeTypeAndValue[] attr = rdn.getTypesAndValues();
+                for (int j = 0; j != attr.length; j++)
+                {
+                    res[count++] = attr[j].getType();
+                }
+            }
+            else if (rdn.size() != 0)
+            {
+                res[count++] = rdn.getFirst().getType();
+            }
+        }
+
+        return res;
+    }
+
+    /**
+     * return an array of RDNs containing the attribute type given by OID in structure order.
+     *
+     * @param attributeType the type OID we are looking for.
+     * @return an array, possibly zero length, of RDN objects.
+     */
+    public RDN[] getRDNs(ASN1ObjectIdentifier attributeType)
+    {
+        RDN[] res = new RDN[rdns.length];
+        int   count = 0;
+
+        for (int i = 0; i != rdns.length; i++)
+        {
+            RDN rdn = rdns[i];
+
+            if (rdn.isMultiValued())
+            {
+                AttributeTypeAndValue[] attr = rdn.getTypesAndValues();
+                for (int j = 0; j != attr.length; j++)
+                {
+                    if (attr[j].getType().equals(attributeType))
+                    {
+                        res[count++] = rdn;
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                if (rdn.getFirst().getType().equals(attributeType))
+                {
+                    res[count++] = rdn;
+                }
+            }
+        }
+
+        RDN[] tmp = new RDN[count];
+
+        System.arraycopy(res, 0, tmp, 0, tmp.length);
+
+        return tmp;
+    }
+
+    private RDN[] copy(RDN[] rdns)
+    {
+        RDN[] tmp = new RDN[rdns.length];
+
+        System.arraycopy(rdns, 0, tmp, 0, tmp.length);
+
+        return tmp;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return new DERSequence(rdns);
+    }
+
+    public int hashCode()
+    {
+        if (isHashCodeCalculated)
+        {
+            return hashCodeValue;
+        }
+
+        isHashCodeCalculated = true;
+
+        hashCodeValue = style.calculateHashCode(this);
+
+        return hashCodeValue;
+    }
+
+    /**
+     * test for equality - note: case is ignored.
+     */
+    public boolean equals(Object obj)
+    {
+        if (obj == this)
+        {
+            return true;
+        }
+
+        if (!(obj instanceof X500Name || obj instanceof ASN1Sequence))
+        {
+            return false;
+        }
+        
+        ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
+
+        if (this.toASN1Primitive().equals(derO))
+        {
+            return true;
+        }
+
+        try
+        {
+            return style.areEqual(this, new X500Name(ASN1Sequence.getInstance(((ASN1Encodable)obj).toASN1Primitive())));
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+    }
+    
+    public String toString()
+    {
+        return style.toString(this);
+    }
+
+    /**
+     * Set the default style for X500Name construction.
+     *
+     * @param style  an X500NameStyle
+     */
+    public static void setDefaultStyle(X500NameStyle style)
+    {
+        if (style == null)
+        {
+            throw new NullPointerException("cannot set style to null");
+        }
+
+        defaultStyle = style;
+    }
+
+    /**
+     * Return the current default style.
+     *
+     * @return default style for X500Name construction.
+     */
+    public static X500NameStyle getDefaultStyle()
+    {
+        return defaultStyle;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/X500NameBuilder.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/X500NameBuilder.java
new file mode 100644
index 0000000..8091b6d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/X500NameBuilder.java
@@ -0,0 +1,145 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500;
+
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x500.style.BCStyle;
+
+/**
+ * A builder class for making X.500 Name objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X500NameBuilder
+{
+    private X500NameStyle template;
+    private Vector rdns = new Vector();
+
+    /**
+     * Constructor using the default style (BCStyle).
+     */
+    public X500NameBuilder()
+    {
+        this(BCStyle.INSTANCE);
+    }
+
+    /**
+     * Constructor using a specified style.
+     *
+     * @param template the style template for string to DN conversion.
+     */
+    public X500NameBuilder(X500NameStyle template)
+    {
+        this.template = template;
+    }
+
+    /**
+     * Add an RDN based on a single OID and a string representation of its value.
+     *
+     * @param oid the OID for this RDN.
+     * @param value the string representation of the value the OID refers to.
+     * @return the current builder instance.
+     */
+    public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, String value)
+    {
+        this.addRDN(oid, template.stringToValue(oid, value));
+
+        return this;
+    }
+
+    /**
+     * Add an RDN based on a single OID and an ASN.1 value.
+     *
+     * @param oid the OID for this RDN.
+     * @param value the ASN.1 value the OID refers to.
+     * @return the current builder instance.
+     */
+    public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, ASN1Encodable value)
+    {
+        rdns.addElement(new RDN(oid, value));
+
+        return this;
+    }
+
+    /**
+     * Add an RDN based on the passed in AttributeTypeAndValue.
+     *
+     * @param attrTAndV the AttributeTypeAndValue to build the RDN from.
+     * @return the current builder instance.
+     */
+    public X500NameBuilder addRDN(AttributeTypeAndValue attrTAndV)
+    {
+        rdns.addElement(new RDN(attrTAndV));
+
+        return this;
+    }
+
+    /**
+     * Add a multi-valued RDN made up of the passed in OIDs and associated string values.
+     *
+     * @param oids the OIDs making up the RDN.
+     * @param values the string representation of the values the OIDs refer to.
+     * @return the current builder instance.
+     */
+    public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, String[] values)
+    {
+        ASN1Encodable[] vals = new ASN1Encodable[values.length];
+
+        for (int i = 0; i != vals.length; i++)
+        {
+            vals[i] = template.stringToValue(oids[i], values[i]);
+        }
+
+        return addMultiValuedRDN(oids, vals);
+    }
+
+    /**
+     * Add a multi-valued RDN made up of the passed in OIDs and associated ASN.1 values.
+     *
+     * @param oids the OIDs making up the RDN.
+     * @param values the ASN.1 values the OIDs refer to.
+     * @return the current builder instance.
+     */
+    public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, ASN1Encodable[] values)
+    {
+        AttributeTypeAndValue[] avs = new AttributeTypeAndValue[oids.length];
+
+        for (int i = 0; i != oids.length; i++)
+        {
+            avs[i] = new AttributeTypeAndValue(oids[i], values[i]);
+        }
+
+        return addMultiValuedRDN(avs);
+    }
+
+    /**
+     * Add an RDN based on the passed in AttributeTypeAndValues.
+     *
+     * @param attrTAndVs the AttributeTypeAndValues to build the RDN from.
+     * @return the current builder instance.
+     */
+    public X500NameBuilder addMultiValuedRDN(AttributeTypeAndValue[] attrTAndVs)
+    {
+        rdns.addElement(new RDN(attrTAndVs));
+
+        return this;
+    }
+
+    /**
+     * Build an X.500 name for the current builder state.
+     *
+     * @return a new X.500 name.
+     */
+    public X500Name build()
+    {
+        RDN[] vals = new RDN[rdns.size()];
+
+        for (int i = 0; i != vals.length; i++)
+        {
+            vals[i] = (RDN)rdns.elementAt(i);
+        }
+
+        return new X500Name(template, vals);
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/X500NameStyle.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/X500NameStyle.java
new file mode 100644
index 0000000..dfdde96
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/X500NameStyle.java
@@ -0,0 +1,81 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * This interface provides a profile to conform to when
+ * DNs are being converted into strings and back. The idea being that we'll be able to deal with
+ * the number of standard ways the fields in a DN should be
+ * encoded into their ASN.1 counterparts - a number that is rapidly approaching the
+ * number of machines on the internet.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface X500NameStyle
+{
+    /**
+     * Convert the passed in String value into the appropriate ASN.1
+     * encoded object.
+     * 
+     * @param oid the OID associated with the value in the DN.
+     * @param value the value of the particular DN component.
+     * @return the ASN.1 equivalent for the value.
+     */
+    ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value);
+
+    /**
+     * Return the OID associated with the passed in name.
+     *
+     * @param attrName the string to match.
+     * @return an OID
+     */
+    ASN1ObjectIdentifier attrNameToOID(String attrName);
+
+    /**
+     * Return an array of RDN generated from the passed in String.
+     * @param dirName  the String representation.
+     * @return  an array of corresponding RDNs.
+     */
+    RDN[] fromString(String dirName);
+
+    /**
+     * Return true if the two names are equal.
+     *
+     * @param name1 first name for comparison.
+     * @param name2 second name for comparison.
+     * @return true if name1 = name 2, false otherwise.
+     */
+    boolean areEqual(X500Name name1, X500Name name2);
+
+    /**
+     * Calculate a hashCode for the passed in name.
+     *
+     * @param name the name the hashCode is required for.
+     * @return the calculated hashCode.
+     */
+    int calculateHashCode(X500Name name);
+
+    /**
+     * Convert the passed in X500Name to a String.
+     * @param name the name to convert.
+     * @return a String representation.
+     */
+    String toString(X500Name name);
+
+    /**
+     * Return the display name for toString() associated with the OID.
+     *
+     * @param oid  the OID of interest.
+     * @return the name displayed in toString(), null if no mapping provided.
+     */
+    String oidToDisplayName(ASN1ObjectIdentifier oid);
+
+    /**
+     * Return the acceptable names in a String DN that map to OID.
+     *
+     * @param oid  the OID of interest.
+     * @return an array of String aliases for the OID, zero length if there are none.
+     */
+    String[] oidToAttrNames(ASN1ObjectIdentifier oid);
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java
new file mode 100644
index 0000000..7e36d8d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java
@@ -0,0 +1,195 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500.style;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1ParsingException;
+import com.android.internal.org.bouncycastle.asn1.DERUTF8String;
+import com.android.internal.org.bouncycastle.asn1.x500.AttributeTypeAndValue;
+import com.android.internal.org.bouncycastle.asn1.x500.RDN;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x500.X500NameStyle;
+
+/**
+ * This class provides some default behavior and common implementation for a
+ * X500NameStyle. It should be easily extendable to support implementing the
+ * desired X500NameStyle.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class AbstractX500NameStyle
+    implements X500NameStyle
+{
+
+    /**
+     * Tool function to shallow copy a Hashtable.
+     *
+     * @param paramsMap table to copy
+     * @return the copy of the table
+     */
+    public static Hashtable copyHashTable(Hashtable paramsMap)
+    {
+        Hashtable newTable = new Hashtable();
+
+        Enumeration keys = paramsMap.keys();
+        while (keys.hasMoreElements())
+        {
+            Object key = keys.nextElement();
+            newTable.put(key, paramsMap.get(key));
+        }
+
+        return newTable;
+    }
+
+    private int calcHashCode(ASN1Encodable enc)
+    {
+        String value = IETFUtils.valueToString(enc);
+        value = IETFUtils.canonicalize(value);
+        return value.hashCode();
+    }
+
+    public int calculateHashCode(X500Name name)
+    {
+        int hashCodeValue = 0;
+        RDN[] rdns = name.getRDNs();
+
+        // this needs to be order independent, like equals
+        for (int i = 0; i != rdns.length; i++)
+        {
+            if (rdns[i].isMultiValued())
+            {
+                AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
+
+                for (int j = 0; j != atv.length; j++)
+                {
+                    hashCodeValue ^= atv[j].getType().hashCode();
+                    hashCodeValue ^= calcHashCode(atv[j].getValue());
+                }
+            }
+            else
+            {
+                hashCodeValue ^= rdns[i].getFirst().getType().hashCode();
+                hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());
+            }
+        }
+
+        return hashCodeValue;
+    }
+
+
+    /**
+     * For all string values starting with '#' is assumed, that these are
+     * already valid ASN.1 objects encoded in hex.
+     * <p>
+     * All other string values are send to
+     * {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)}.
+     * </p>
+     * Subclasses should overwrite
+     * {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)}
+     * to change the encoding of specific types.
+     *
+     * @param oid the DN name of the value.
+     * @param value the String representation of the value.
+     */
+    public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)
+    {
+        if (value.length() != 0 && value.charAt(0) == '#')
+        {
+            try
+            {
+                return IETFUtils.valueFromHexString(value, 1);
+            }
+            catch (IOException e)
+            {
+                throw new ASN1ParsingException("can't recode value for oid " + oid.getId());
+            }
+        }
+
+        if (value.length() != 0 && value.charAt(0) == '\\')
+        {
+            value = value.substring(1);
+        }
+
+        return encodeStringValue(oid, value);
+    }
+
+    /**
+     * Encoded every value into a UTF8String.
+     * <p>
+     * Subclasses should overwrite
+     * this method to change the encoding of specific types.
+     * </p>
+     *
+     * @param oid the DN oid of the value
+     * @param value the String representation of the value
+     * @return a the value encoded into a ASN.1 object. Never returns <code>null</code>.
+     */
+    protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid, String value)
+    {
+        return new DERUTF8String(value);
+    }
+
+    public boolean areEqual(X500Name name1, X500Name name2)
+    {
+        RDN[] rdns1 = name1.getRDNs();
+        RDN[] rdns2 = name2.getRDNs();
+
+        if (rdns1.length != rdns2.length)
+        {
+            return false;
+        }
+
+        boolean reverse = false;
+
+        if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null)
+        {
+            reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType());  // guess forward
+        }
+
+        for (int i = 0; i != rdns1.length; i++)
+        {
+            if (!foundMatch(reverse, rdns1[i], rdns2))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs)
+    {
+        if (reverse)
+        {
+            for (int i = possRDNs.length - 1; i >= 0; i--)
+            {
+                if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
+                {
+                    possRDNs[i] = null;
+                    return true;
+                }
+            }
+        }
+        else
+        {
+            for (int i = 0; i != possRDNs.length; i++)
+            {
+                if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
+                {
+                    possRDNs[i] = null;
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    protected boolean rdnAreEqual(RDN rdn1, RDN rdn2)
+    {
+        return IETFUtils.rDNAreEqual(rdn1, rdn2);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/BCStrictStyle.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/BCStrictStyle.java
new file mode 100644
index 0000000..86f124f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/BCStrictStyle.java
@@ -0,0 +1,38 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500.style;
+
+import com.android.internal.org.bouncycastle.asn1.x500.RDN;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x500.X500NameStyle;
+
+/**
+ * Variation of BCStyle that insists on strict ordering for equality
+ * and hashCode comparisons
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCStrictStyle
+    extends BCStyle
+{
+    public static final X500NameStyle INSTANCE = new BCStrictStyle();
+
+    public boolean areEqual(X500Name name1, X500Name name2)
+    {
+        RDN[] rdns1 = name1.getRDNs();
+        RDN[] rdns2 = name2.getRDNs();
+
+        if (rdns1.length != rdns2.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != rdns1.length; i++)
+        {
+            if (!rdnAreEqual(rdns1[i], rdns2[i]))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/BCStyle.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/BCStyle.java
new file mode 100644
index 0000000..1cc9914
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/BCStyle.java
@@ -0,0 +1,352 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500.style;
+
+import java.util.Hashtable;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1GeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.DERPrintableString;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x500.RDN;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x500.X500NameStyle;
+import com.android.internal.org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCStyle
+    extends AbstractX500NameStyle
+{
+    /**
+     * country code - StringType(SIZE(2))
+     */
+    public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6").intern();
+
+    /**
+     * organization - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10").intern();
+
+    /**
+     * organizational unit name - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11").intern();
+
+    /**
+     * Title
+     */
+    public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12").intern();
+
+    /**
+     * common name - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3").intern();
+
+    /**
+     * device serial number name - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5").intern();
+
+    /**
+     * street - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9").intern();
+
+    /**
+     * device serial number name - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier SERIALNUMBER = SN;
+
+    /**
+     * locality name - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7").intern();
+
+    /**
+     * state, or province name - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8").intern();
+
+    /**
+     * Naming attributes of type X520name
+     */
+    public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier("2.5.4.4").intern();
+    public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier("2.5.4.42").intern();
+    public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier("2.5.4.43").intern();
+    public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier("2.5.4.44").intern();
+    public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier("2.5.4.45").intern();
+
+    /**
+     * businessCategory - DirectoryString(SIZE(1..128)
+     */
+    public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier("2.5.4.15").intern();
+
+    /**
+     * postalCode - DirectoryString(SIZE(1..40)
+     */
+    public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier("2.5.4.17").intern();
+
+    /**
+     * dnQualifier - DirectoryString(SIZE(1..64)
+     */
+    public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier("2.5.4.46").intern();
+
+    /**
+     * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+     */
+    public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier("2.5.4.65").intern();
+
+
+    /**
+     * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+     */
+    public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.1").intern();
+
+    /**
+     * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
+     */
+    public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.2").intern();
+
+    /**
+     * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
+     */
+    public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.3").intern();
+
+    /**
+     * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+     * codes only
+     */
+    public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.4").intern();
+
+    /**
+     * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166
+     * codes only
+     */
+    public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.9.5").intern();
+
+
+    /**
+     * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+     */
+    public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier("1.3.36.8.3.14").intern();
+
+    /**
+     * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+     * DirectoryString(SIZE(1..30))
+     */
+    public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16").intern();
+
+    /**
+     * RFC 2256 dmdName
+     */
+    public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54").intern();
+
+    /**
+     * id-at-telephoneNumber
+     */
+    public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber;
+
+    /**
+     * id-at-name
+     */
+    public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name;
+
+
+    /**
+     * id-at-organizationIdentifier
+     */
+    public static final ASN1ObjectIdentifier ORGANIZATION_IDENTIFIER = X509ObjectIdentifiers.id_at_organizationIdentifier;
+
+    /**
+     * Email address (RSA PKCS#9 extension) - IA5String.
+     * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
+     */
+    public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;
+
+    /**
+     * more from PKCS#9
+     */
+    public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName;
+    public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress;
+
+    /**
+     * email address in Verisign certificates
+     */
+    public static final ASN1ObjectIdentifier E = EmailAddress;
+
+    /*
+    * others...
+    */
+    public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25");
+
+    /**
+     * LDAP User id.
+     */
+    public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1");
+
+    /**
+     * default look up table translating OID values into their common symbols following
+     * the convention in RFC 2253 with a few extras
+     */
+    private static final Hashtable DefaultSymbols = new Hashtable();
+
+    /**
+     * look up table translating common symbols into their OIDS.
+     */
+    private static final Hashtable DefaultLookUp = new Hashtable();
+
+    static
+    {
+        DefaultSymbols.put(C, "C");
+        DefaultSymbols.put(O, "O");
+        DefaultSymbols.put(T, "T");
+        DefaultSymbols.put(OU, "OU");
+        DefaultSymbols.put(CN, "CN");
+        DefaultSymbols.put(L, "L");
+        DefaultSymbols.put(ST, "ST");
+        DefaultSymbols.put(SN, "SERIALNUMBER");
+        DefaultSymbols.put(EmailAddress, "E");
+        DefaultSymbols.put(DC, "DC");
+        DefaultSymbols.put(UID, "UID");
+        DefaultSymbols.put(STREET, "STREET");
+        DefaultSymbols.put(SURNAME, "SURNAME");
+        DefaultSymbols.put(GIVENNAME, "GIVENNAME");
+        DefaultSymbols.put(INITIALS, "INITIALS");
+        DefaultSymbols.put(GENERATION, "GENERATION");
+        DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress");
+        DefaultSymbols.put(UnstructuredName, "unstructuredName");
+        DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier");
+        DefaultSymbols.put(DN_QUALIFIER, "DN");
+        DefaultSymbols.put(PSEUDONYM, "Pseudonym");
+        DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress");
+        DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth");
+        DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship");
+        DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence");
+        DefaultSymbols.put(GENDER, "Gender");
+        DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth");
+        DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth");
+        DefaultSymbols.put(POSTAL_CODE, "PostalCode");
+        DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory");
+        DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber");
+        DefaultSymbols.put(NAME, "Name");
+        DefaultSymbols.put(ORGANIZATION_IDENTIFIER, "organizationIdentifier");
+
+        DefaultLookUp.put("c", C);
+        DefaultLookUp.put("o", O);
+        DefaultLookUp.put("t", T);
+        DefaultLookUp.put("ou", OU);
+        DefaultLookUp.put("cn", CN);
+        DefaultLookUp.put("l", L);
+        DefaultLookUp.put("st", ST);
+        DefaultLookUp.put("sn", SN);
+        DefaultLookUp.put("serialnumber", SN);
+        DefaultLookUp.put("street", STREET);
+        DefaultLookUp.put("emailaddress", E);
+        DefaultLookUp.put("dc", DC);
+        DefaultLookUp.put("e", E);
+        DefaultLookUp.put("uid", UID);
+        DefaultLookUp.put("surname", SURNAME);
+        DefaultLookUp.put("givenname", GIVENNAME);
+        DefaultLookUp.put("initials", INITIALS);
+        DefaultLookUp.put("generation", GENERATION);
+        DefaultLookUp.put("unstructuredaddress", UnstructuredAddress);
+        DefaultLookUp.put("unstructuredname", UnstructuredName);
+        DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER);
+        DefaultLookUp.put("dn", DN_QUALIFIER);
+        DefaultLookUp.put("pseudonym", PSEUDONYM);
+        DefaultLookUp.put("postaladdress", POSTAL_ADDRESS);
+        DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH);
+        DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP);
+        DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE);
+        DefaultLookUp.put("gender", GENDER);
+        DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH);
+        DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH);
+        DefaultLookUp.put("postalcode", POSTAL_CODE);
+        DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY);
+        DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER);
+        DefaultLookUp.put("name", NAME);
+        DefaultLookUp.put("organizationidentifier", ORGANIZATION_IDENTIFIER);
+    }
+
+    /**
+     * Singleton instance.
+     */
+    public static final X500NameStyle INSTANCE = new BCStyle();
+
+    protected final Hashtable defaultLookUp;
+    protected final Hashtable defaultSymbols;
+
+    protected BCStyle()
+    {
+        defaultSymbols = copyHashTable(DefaultSymbols);
+        defaultLookUp = copyHashTable(DefaultLookUp);
+    }
+
+    protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid,
+    		String value) {
+    	if (oid.equals(EmailAddress) || oid.equals(DC))
+        {
+            return new DERIA5String(value);
+        }
+        else if (oid.equals(DATE_OF_BIRTH))  // accept time string as well as # (for compatibility)
+        {
+            return new ASN1GeneralizedTime(value);
+        }
+        else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER)
+            || oid.equals(TELEPHONE_NUMBER))
+        {
+            return new DERPrintableString(value);
+        }
+    	
+    	return super.encodeStringValue(oid, value);
+    }
+
+    public String oidToDisplayName(ASN1ObjectIdentifier oid)
+    {
+        return (String)DefaultSymbols.get(oid);
+    }
+
+    public String[] oidToAttrNames(ASN1ObjectIdentifier oid)
+    {
+        return IETFUtils.findAttrNamesForOID(oid, defaultLookUp);
+    }
+
+    public ASN1ObjectIdentifier attrNameToOID(String attrName)
+    {
+        return IETFUtils.decodeAttrName(attrName, defaultLookUp);
+    }
+
+    public RDN[] fromString(String dirName)
+    {
+        return IETFUtils.rDNsFromString(dirName, this);
+    }
+
+    public String toString(X500Name name)
+    {
+        StringBuffer buf = new StringBuffer();
+        boolean first = true;
+
+        RDN[] rdns = name.getRDNs();
+
+        for (int i = 0; i < rdns.length; i++)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                buf.append(',');
+            }
+
+            IETFUtils.appendRDN(buf, rdns[i], defaultSymbols);
+        }
+
+        return buf.toString();
+    }
+
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/IETFUtils.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/IETFUtils.java
new file mode 100644
index 0000000..fb78084
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/IETFUtils.java
@@ -0,0 +1,599 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500.style;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1String;
+import com.android.internal.org.bouncycastle.asn1.DERUniversalString;
+import com.android.internal.org.bouncycastle.asn1.x500.AttributeTypeAndValue;
+import com.android.internal.org.bouncycastle.asn1.x500.RDN;
+import com.android.internal.org.bouncycastle.asn1.x500.X500NameBuilder;
+import com.android.internal.org.bouncycastle.asn1.x500.X500NameStyle;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class IETFUtils
+{
+    private static String unescape(String elt)
+    {
+        if (elt.length() == 0 || (elt.indexOf('\\') < 0 && elt.indexOf('"') < 0))
+        {
+            return elt.trim();
+        }
+
+        char[] elts = elt.toCharArray();
+        boolean escaped = false;
+        boolean quoted = false;
+        StringBuffer buf = new StringBuffer(elt.length());
+        int start = 0;
+
+        // if it's an escaped hash string and not an actual encoding in string form
+        // we need to leave it escaped.
+        if (elts[0] == '\\')
+        {
+            if (elts[1] == '#')
+            {
+                start = 2;
+                buf.append("\\#");
+            }
+        }
+
+        boolean nonWhiteSpaceEncountered = false;
+        int     lastEscaped = 0;
+        char    hex1 = 0;
+
+        for (int i = start; i != elts.length; i++)
+        {
+            char c = elts[i];
+
+            if (c != ' ')
+            {
+                nonWhiteSpaceEncountered = true;
+            }
+
+            if (c == '"')
+            {
+                if (!escaped)
+                {
+                    quoted = !quoted;
+                }
+                else
+                {
+                    buf.append(c);
+                }
+                escaped = false;
+            }
+            else if (c == '\\' && !(escaped || quoted))
+            {
+                escaped = true;
+                lastEscaped = buf.length();
+            }
+            else
+            {
+                if (c == ' ' && !escaped && !nonWhiteSpaceEncountered)
+                {
+                    continue;
+                }
+                if (escaped && isHexDigit(c))
+                {
+                    if (hex1 != 0)
+                    {
+                        buf.append((char)(convertHex(hex1) * 16 + convertHex(c)));
+                        escaped = false;
+                        hex1 = 0;
+                        continue;
+                    }
+                    hex1 = c;
+                    continue;
+                }
+                buf.append(c);
+                escaped = false;
+            }
+        }
+
+        if (buf.length() > 0)
+        {
+            while (buf.charAt(buf.length() - 1) == ' ' && lastEscaped != (buf.length() - 1))
+            {
+                buf.setLength(buf.length() - 1);
+            }
+        }
+
+        return buf.toString();
+    }
+
+    private static boolean isHexDigit(char c)
+    {
+        return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+    }
+
+    private static int convertHex(char c)
+    {
+        if ('0' <= c && c <= '9')
+        {
+            return c - '0';
+        }
+        if ('a' <= c && c <= 'f')
+        {
+            return c - 'a' + 10;
+        }
+        return c - 'A' + 10;
+    }
+
+    public static RDN[] rDNsFromString(String name, X500NameStyle x500Style)
+    {
+        X500NameTokenizer nTok = new X500NameTokenizer(name);
+        X500NameBuilder builder = new X500NameBuilder(x500Style);
+
+        while (nTok.hasMoreTokens())
+        {
+            String  token = nTok.nextToken();
+
+            if (token.indexOf('+') > 0)
+            {
+                X500NameTokenizer   pTok = new X500NameTokenizer(token, '+');
+                X500NameTokenizer   vTok = new X500NameTokenizer(pTok.nextToken(), '=');
+
+                String              attr = vTok.nextToken();
+
+                if (!vTok.hasMoreTokens())
+                {
+                    throw new IllegalArgumentException("badly formatted directory string");
+                }
+
+                String               value = vTok.nextToken();
+                ASN1ObjectIdentifier oid = x500Style.attrNameToOID(attr.trim());
+
+                if (pTok.hasMoreTokens())
+                {
+                    Vector oids = new Vector();
+                    Vector values = new Vector();
+
+                    oids.addElement(oid);
+                    values.addElement(unescape(value));
+
+                    while (pTok.hasMoreTokens())
+                    {
+                        vTok = new X500NameTokenizer(pTok.nextToken(), '=');
+
+                        attr = vTok.nextToken();
+
+                        if (!vTok.hasMoreTokens())
+                        {
+                            throw new IllegalArgumentException("badly formatted directory string");
+                        }
+
+                        value = vTok.nextToken();
+                        oid = x500Style.attrNameToOID(attr.trim());
+
+
+                        oids.addElement(oid);
+                        values.addElement(unescape(value));
+                    }
+
+                    builder.addMultiValuedRDN(toOIDArray(oids), toValueArray(values));
+                }
+                else
+                {
+                    builder.addRDN(oid, unescape(value));
+                }
+            }
+            else
+            {
+                X500NameTokenizer   vTok = new X500NameTokenizer(token, '=');
+
+                String              attr = vTok.nextToken();
+
+                if (!vTok.hasMoreTokens())
+                {
+                    throw new IllegalArgumentException("badly formatted directory string");
+                }
+
+                String               value = vTok.nextToken();
+                ASN1ObjectIdentifier oid = x500Style.attrNameToOID(attr.trim());
+
+                builder.addRDN(oid, unescape(value));
+            }
+        }
+
+        return builder.build().getRDNs();
+    }
+
+    private static String[] toValueArray(Vector values)
+    {
+        String[] tmp = new String[values.size()];
+
+        for (int i = 0; i != tmp.length; i++)
+        {
+            tmp[i] = (String)values.elementAt(i);
+        }
+
+        return tmp;
+    }
+
+    private static ASN1ObjectIdentifier[] toOIDArray(Vector oids)
+    {
+        ASN1ObjectIdentifier[] tmp = new ASN1ObjectIdentifier[oids.size()];
+
+        for (int i = 0; i != tmp.length; i++)
+        {
+            tmp[i] = (ASN1ObjectIdentifier)oids.elementAt(i);
+        }
+
+        return tmp;
+    }
+
+    public static String[] findAttrNamesForOID(
+        ASN1ObjectIdentifier oid,
+        Hashtable            lookup)
+    {
+        int count = 0;
+        for (Enumeration en = lookup.elements(); en.hasMoreElements();)
+        {
+            if (oid.equals(en.nextElement()))
+            {
+                count++;
+            }
+        }
+
+        String[] aliases = new String[count];
+        count = 0;
+
+        for (Enumeration en = lookup.keys(); en.hasMoreElements();)
+        {
+            String key = (String)en.nextElement();
+            if (oid.equals(lookup.get(key)))
+            {
+                aliases[count++] = key;
+            }
+        }
+
+        return aliases;
+    }
+
+    public static ASN1ObjectIdentifier decodeAttrName(
+        String      name,
+        Hashtable   lookUp)
+    {
+        if (Strings.toUpperCase(name).startsWith("OID."))
+        {
+            return new ASN1ObjectIdentifier(name.substring(4));
+        }
+        else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')
+        {
+            return new ASN1ObjectIdentifier(name);
+        }
+
+        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
+        if (oid == null)
+        {
+            throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+        }
+
+        return oid;
+    }
+
+    public static ASN1Encodable valueFromHexString(
+        String  str,
+        int     off)
+        throws IOException
+    {
+        byte[] data = new byte[(str.length() - off) / 2];
+        for (int index = 0; index != data.length; index++)
+        {
+            char left = str.charAt((index * 2) + off);
+            char right = str.charAt((index * 2) + off + 1);
+
+            data[index] = (byte)((convertHex(left) << 4) | convertHex(right));
+        }
+
+        return ASN1Primitive.fromByteArray(data);
+    }
+
+    public static void appendRDN(
+        StringBuffer          buf,
+        RDN                   rdn,
+        Hashtable             oidSymbols)
+    {
+        if (rdn.isMultiValued())
+        {
+            AttributeTypeAndValue[] atv = rdn.getTypesAndValues();
+            boolean firstAtv = true;
+
+            for (int j = 0; j != atv.length; j++)
+            {
+                if (firstAtv)
+                {
+                    firstAtv = false;
+                }
+                else
+                {
+                    buf.append('+');
+                }
+
+                IETFUtils.appendTypeAndValue(buf, atv[j], oidSymbols);
+            }
+        }
+        else
+        {
+            if (rdn.getFirst() != null)
+            {
+                IETFUtils.appendTypeAndValue(buf, rdn.getFirst(), oidSymbols);
+            }
+        }
+    }
+
+    public static void appendTypeAndValue(
+        StringBuffer          buf,
+        AttributeTypeAndValue typeAndValue,
+        Hashtable             oidSymbols)
+    {
+        String  sym = (String)oidSymbols.get(typeAndValue.getType());
+
+        if (sym != null)
+        {
+            buf.append(sym);
+        }
+        else
+        {
+            buf.append(typeAndValue.getType().getId());
+        }
+
+        buf.append('=');
+
+        buf.append(valueToString(typeAndValue.getValue()));
+    }
+
+    public static String valueToString(ASN1Encodable value)
+    {
+        StringBuffer vBuf = new StringBuffer();
+
+        if (value instanceof ASN1String && !(value instanceof DERUniversalString))
+        {
+            String v = ((ASN1String)value).getString();
+            if (v.length() > 0 && v.charAt(0) == '#')
+            {
+                vBuf.append("\\" + v);
+            }
+            else
+            {
+                vBuf.append(v);
+            }
+        }
+        else
+        {
+            try
+            {
+                vBuf.append("#" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER))));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("Other value has no encoded form");
+            }
+        }
+
+        int     end = vBuf.length();
+        int     index = 0;
+
+        if (vBuf.length() >= 2 && vBuf.charAt(0) == '\\' && vBuf.charAt(1) == '#')
+        {
+            index += 2;
+        }
+
+        while (index != end)
+        {
+            if ((vBuf.charAt(index) == ',')
+               || (vBuf.charAt(index) == '"')
+               || (vBuf.charAt(index) == '\\')
+               || (vBuf.charAt(index) == '+')
+               || (vBuf.charAt(index) == '=')
+               || (vBuf.charAt(index) == '<')
+               || (vBuf.charAt(index) == '>')
+               || (vBuf.charAt(index) == ';'))
+            {
+                vBuf.insert(index, "\\");
+                index++;
+                end++;
+            }
+
+            index++;
+        }
+
+        int start = 0;
+        if (vBuf.length() > 0)
+        {
+            while (vBuf.length() > start && vBuf.charAt(start) == ' ')
+            {
+                vBuf.insert(start, "\\");
+                start += 2;
+            }
+        }
+
+        int endBuf = vBuf.length() - 1;
+
+        while (endBuf >= 0 && vBuf.charAt(endBuf) == ' ')
+        {
+            vBuf.insert(endBuf, '\\');
+            endBuf--;
+        }
+
+        return vBuf.toString();
+    }
+
+    private static String bytesToString(
+        byte[] data)
+    {
+        char[]  cs = new char[data.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            cs[i] = (char)(data[i] & 0xff);
+        }
+
+        return new String(cs);
+    }
+
+    public static String canonicalize(String s)
+    {
+        String value = Strings.toLowerCase(s);
+
+        if (value.length() > 0 && value.charAt(0) == '#')
+        {
+            ASN1Primitive obj = decodeObject(value);
+
+            if (obj instanceof ASN1String)
+            {
+                value = Strings.toLowerCase(((ASN1String)obj).getString());
+            }
+        }
+
+        if (value.length() > 1)
+        {
+            int start = 0;
+            while (start + 1 < value.length() && value.charAt(start) == '\\' && value.charAt(start + 1) == ' ')
+            {
+                start += 2;
+            }
+
+            int end = value.length() - 1;
+            while (end - 1 > 0 && value.charAt(end - 1) == '\\' && value.charAt(end) == ' ')
+            {
+                end -= 2;
+            }
+
+            if (start > 0 || end < value.length() - 1)
+            {
+                value = value.substring(start, end + 1);
+            }
+        }
+
+        value = stripInternalSpaces(value);
+
+        return value;
+    }
+
+    private static ASN1Primitive decodeObject(String oValue)
+    {
+        try
+        {
+            return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1)));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("unknown encoding in name: " + e);
+        }
+    }
+
+    public static String stripInternalSpaces(
+        String str)
+    {
+        StringBuffer res = new StringBuffer();
+
+        if (str.length() != 0)
+        {
+            char c1 = str.charAt(0);
+
+            res.append(c1);
+
+            for (int k = 1; k < str.length(); k++)
+            {
+                char c2 = str.charAt(k);
+                if (!(c1 == ' ' && c2 == ' '))
+                {
+                    res.append(c2);
+                }
+                c1 = c2;
+            }
+        }
+
+        return res.toString();
+    }
+
+    public static boolean rDNAreEqual(RDN rdn1, RDN rdn2)
+    {
+        if (rdn1.isMultiValued())
+        {
+            if (rdn2.isMultiValued())
+            {
+                AttributeTypeAndValue[] atvs1 = rdn1.getTypesAndValues();
+                AttributeTypeAndValue[] atvs2 = rdn2.getTypesAndValues();
+
+                if (atvs1.length != atvs2.length)
+                {
+                    return false;
+                }
+
+                for (int i = 0; i != atvs1.length; i++)
+                {
+                    if (!atvAreEqual(atvs1[i], atvs2[i]))
+                    {
+                        return false;
+                    }
+                }
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if (!rdn2.isMultiValued())
+            {
+                return atvAreEqual(rdn1.getFirst(), rdn2.getFirst());
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean atvAreEqual(AttributeTypeAndValue atv1, AttributeTypeAndValue atv2)
+    {
+        if (atv1 == atv2)
+        {
+            return true;
+        }
+
+        if (atv1 == null)
+        {
+            return false;
+        }
+
+        if (atv2 == null)
+        {
+            return false;
+        }
+
+        ASN1ObjectIdentifier o1 = atv1.getType();
+        ASN1ObjectIdentifier o2 = atv2.getType();
+
+        if (!o1.equals(o2))
+        {
+            return false;
+        }
+
+        String v1 = IETFUtils.canonicalize(IETFUtils.valueToString(atv1.getValue()));
+        String v2 = IETFUtils.canonicalize(IETFUtils.valueToString(atv2.getValue()));
+
+        if (!v1.equals(v2))
+        {
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/RFC4519Style.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/RFC4519Style.java
new file mode 100644
index 0000000..7d8f676
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/RFC4519Style.java
@@ -0,0 +1,252 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500.style;
+
+import java.util.Hashtable;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.DERPrintableString;
+import com.android.internal.org.bouncycastle.asn1.x500.RDN;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x500.X500NameStyle;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RFC4519Style
+	extends AbstractX500NameStyle
+{
+    public static final ASN1ObjectIdentifier businessCategory = new ASN1ObjectIdentifier("2.5.4.15").intern();
+    public static final ASN1ObjectIdentifier c = new ASN1ObjectIdentifier("2.5.4.6").intern();
+    public static final ASN1ObjectIdentifier cn = new ASN1ObjectIdentifier("2.5.4.3").intern();
+    public static final ASN1ObjectIdentifier dc = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25").intern();
+    public static final ASN1ObjectIdentifier description = new ASN1ObjectIdentifier("2.5.4.13").intern();
+    public static final ASN1ObjectIdentifier destinationIndicator = new ASN1ObjectIdentifier("2.5.4.27").intern();
+    public static final ASN1ObjectIdentifier distinguishedName = new ASN1ObjectIdentifier("2.5.4.49").intern();
+    public static final ASN1ObjectIdentifier dnQualifier = new ASN1ObjectIdentifier("2.5.4.46").intern();
+    public static final ASN1ObjectIdentifier enhancedSearchGuide = new ASN1ObjectIdentifier("2.5.4.47").intern();
+    public static final ASN1ObjectIdentifier facsimileTelephoneNumber = new ASN1ObjectIdentifier("2.5.4.23").intern();
+    public static final ASN1ObjectIdentifier generationQualifier = new ASN1ObjectIdentifier("2.5.4.44").intern();
+    public static final ASN1ObjectIdentifier givenName = new ASN1ObjectIdentifier("2.5.4.42").intern();
+    public static final ASN1ObjectIdentifier houseIdentifier = new ASN1ObjectIdentifier("2.5.4.51").intern();
+    public static final ASN1ObjectIdentifier initials = new ASN1ObjectIdentifier("2.5.4.43").intern();
+    public static final ASN1ObjectIdentifier internationalISDNNumber = new ASN1ObjectIdentifier("2.5.4.25").intern();
+    public static final ASN1ObjectIdentifier l = new ASN1ObjectIdentifier("2.5.4.7").intern();
+    public static final ASN1ObjectIdentifier member = new ASN1ObjectIdentifier("2.5.4.31").intern();
+    public static final ASN1ObjectIdentifier name = new ASN1ObjectIdentifier("2.5.4.41").intern();
+    public static final ASN1ObjectIdentifier o = new ASN1ObjectIdentifier("2.5.4.10").intern();
+    public static final ASN1ObjectIdentifier ou = new ASN1ObjectIdentifier("2.5.4.11").intern();
+    public static final ASN1ObjectIdentifier owner = new ASN1ObjectIdentifier("2.5.4.32").intern();
+    public static final ASN1ObjectIdentifier physicalDeliveryOfficeName = new ASN1ObjectIdentifier("2.5.4.19").intern();
+    public static final ASN1ObjectIdentifier postalAddress = new ASN1ObjectIdentifier("2.5.4.16").intern();
+    public static final ASN1ObjectIdentifier postalCode = new ASN1ObjectIdentifier("2.5.4.17").intern();
+    public static final ASN1ObjectIdentifier postOfficeBox = new ASN1ObjectIdentifier("2.5.4.18").intern();
+    public static final ASN1ObjectIdentifier preferredDeliveryMethod = new ASN1ObjectIdentifier("2.5.4.28").intern();
+    public static final ASN1ObjectIdentifier registeredAddress = new ASN1ObjectIdentifier("2.5.4.26").intern();
+    public static final ASN1ObjectIdentifier roleOccupant = new ASN1ObjectIdentifier("2.5.4.33").intern();
+    public static final ASN1ObjectIdentifier searchGuide = new ASN1ObjectIdentifier("2.5.4.14").intern();
+    public static final ASN1ObjectIdentifier seeAlso = new ASN1ObjectIdentifier("2.5.4.34").intern();
+    public static final ASN1ObjectIdentifier serialNumber = new ASN1ObjectIdentifier("2.5.4.5").intern();
+    public static final ASN1ObjectIdentifier sn = new ASN1ObjectIdentifier("2.5.4.4").intern();
+    public static final ASN1ObjectIdentifier st = new ASN1ObjectIdentifier("2.5.4.8").intern();
+    public static final ASN1ObjectIdentifier street = new ASN1ObjectIdentifier("2.5.4.9").intern();
+    public static final ASN1ObjectIdentifier telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20").intern();
+    public static final ASN1ObjectIdentifier teletexTerminalIdentifier = new ASN1ObjectIdentifier("2.5.4.22").intern();
+    public static final ASN1ObjectIdentifier telexNumber = new ASN1ObjectIdentifier("2.5.4.21").intern();
+    public static final ASN1ObjectIdentifier title = new ASN1ObjectIdentifier("2.5.4.12").intern();
+    public static final ASN1ObjectIdentifier uid = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1").intern();
+    public static final ASN1ObjectIdentifier uniqueMember = new ASN1ObjectIdentifier("2.5.4.50").intern();
+    public static final ASN1ObjectIdentifier userPassword = new ASN1ObjectIdentifier("2.5.4.35").intern();
+    public static final ASN1ObjectIdentifier x121Address = new ASN1ObjectIdentifier("2.5.4.24").intern();
+    public static final ASN1ObjectIdentifier x500UniqueIdentifier = new ASN1ObjectIdentifier("2.5.4.45").intern();
+
+    /**
+     * default look up table translating OID values into their common symbols following
+     * the convention in RFC 2253 with a few extras
+     */
+    private static final Hashtable DefaultSymbols = new Hashtable();
+
+    /**
+     * look up table translating common symbols into their OIDS.
+     */
+    private static final Hashtable DefaultLookUp = new Hashtable();
+
+    static
+    {
+        DefaultSymbols.put(businessCategory, "businessCategory");
+        DefaultSymbols.put(c, "c");
+        DefaultSymbols.put(cn, "cn");
+        DefaultSymbols.put(dc, "dc");
+        DefaultSymbols.put(description, "description");
+        DefaultSymbols.put(destinationIndicator, "destinationIndicator");
+        DefaultSymbols.put(distinguishedName, "distinguishedName");
+        DefaultSymbols.put(dnQualifier, "dnQualifier");
+        DefaultSymbols.put(enhancedSearchGuide, "enhancedSearchGuide");
+        DefaultSymbols.put(facsimileTelephoneNumber, "facsimileTelephoneNumber");
+        DefaultSymbols.put(generationQualifier, "generationQualifier");
+        DefaultSymbols.put(givenName, "givenName");
+        DefaultSymbols.put(houseIdentifier, "houseIdentifier");
+        DefaultSymbols.put(initials, "initials");
+        DefaultSymbols.put(internationalISDNNumber, "internationalISDNNumber");
+        DefaultSymbols.put(l, "l");
+        DefaultSymbols.put(member, "member");
+        DefaultSymbols.put(name, "name");
+        DefaultSymbols.put(o, "o");
+        DefaultSymbols.put(ou, "ou");
+        DefaultSymbols.put(owner, "owner");
+        DefaultSymbols.put(physicalDeliveryOfficeName, "physicalDeliveryOfficeName");
+        DefaultSymbols.put(postalAddress, "postalAddress");
+        DefaultSymbols.put(postalCode, "postalCode");
+        DefaultSymbols.put(postOfficeBox, "postOfficeBox");
+        DefaultSymbols.put(preferredDeliveryMethod, "preferredDeliveryMethod");
+        DefaultSymbols.put(registeredAddress, "registeredAddress");
+        DefaultSymbols.put(roleOccupant, "roleOccupant");
+        DefaultSymbols.put(searchGuide, "searchGuide");
+        DefaultSymbols.put(seeAlso, "seeAlso");
+        DefaultSymbols.put(serialNumber, "serialNumber");
+        DefaultSymbols.put(sn, "sn");
+        DefaultSymbols.put(st, "st");
+        DefaultSymbols.put(street, "street");
+        DefaultSymbols.put(telephoneNumber, "telephoneNumber");
+        DefaultSymbols.put(teletexTerminalIdentifier, "teletexTerminalIdentifier");
+        DefaultSymbols.put(telexNumber, "telexNumber");
+        DefaultSymbols.put(title, "title");
+        DefaultSymbols.put(uid, "uid");
+        DefaultSymbols.put(uniqueMember, "uniqueMember");
+        DefaultSymbols.put(userPassword, "userPassword");
+        DefaultSymbols.put(x121Address, "x121Address");
+        DefaultSymbols.put(x500UniqueIdentifier, "x500UniqueIdentifier");
+
+        DefaultLookUp.put("businesscategory", businessCategory);
+        DefaultLookUp.put("c", c);
+        DefaultLookUp.put("cn", cn);
+        DefaultLookUp.put("dc", dc);
+        DefaultLookUp.put("description", description);
+        DefaultLookUp.put("destinationindicator", destinationIndicator);
+        DefaultLookUp.put("distinguishedname", distinguishedName);
+        DefaultLookUp.put("dnqualifier", dnQualifier);
+        DefaultLookUp.put("enhancedsearchguide", enhancedSearchGuide);
+        DefaultLookUp.put("facsimiletelephonenumber", facsimileTelephoneNumber);
+        DefaultLookUp.put("generationqualifier", generationQualifier);
+        DefaultLookUp.put("givenname", givenName);
+        DefaultLookUp.put("houseidentifier", houseIdentifier);
+        DefaultLookUp.put("initials", initials);
+        DefaultLookUp.put("internationalisdnnumber", internationalISDNNumber);
+        DefaultLookUp.put("l", l);
+        DefaultLookUp.put("member", member);
+        DefaultLookUp.put("name", name);
+        DefaultLookUp.put("o", o);
+        DefaultLookUp.put("ou", ou);
+        DefaultLookUp.put("owner", owner);
+        DefaultLookUp.put("physicaldeliveryofficename", physicalDeliveryOfficeName);
+        DefaultLookUp.put("postaladdress", postalAddress);
+        DefaultLookUp.put("postalcode", postalCode);
+        DefaultLookUp.put("postofficebox", postOfficeBox);
+        DefaultLookUp.put("preferreddeliverymethod", preferredDeliveryMethod);
+        DefaultLookUp.put("registeredaddress", registeredAddress);
+        DefaultLookUp.put("roleoccupant", roleOccupant);
+        DefaultLookUp.put("searchguide", searchGuide);
+        DefaultLookUp.put("seealso", seeAlso);
+        DefaultLookUp.put("serialnumber", serialNumber);
+        DefaultLookUp.put("sn", sn);
+        DefaultLookUp.put("st", st);
+        DefaultLookUp.put("street", street);
+        DefaultLookUp.put("telephonenumber", telephoneNumber);
+        DefaultLookUp.put("teletexterminalidentifier", teletexTerminalIdentifier);
+        DefaultLookUp.put("telexnumber", telexNumber);
+        DefaultLookUp.put("title", title);
+        DefaultLookUp.put("uid", uid);
+        DefaultLookUp.put("uniquemember", uniqueMember);
+        DefaultLookUp.put("userpassword", userPassword);
+        DefaultLookUp.put("x121address", x121Address);
+        DefaultLookUp.put("x500uniqueidentifier", x500UniqueIdentifier);
+
+        // TODO: need to add correct matching for equality comparisons.
+    }
+
+    /**
+     * Singleton instance.
+     */
+    public static final X500NameStyle INSTANCE = new RFC4519Style();
+
+    protected final Hashtable defaultLookUp;
+    protected final Hashtable defaultSymbols;
+
+    protected RFC4519Style()
+    {
+        defaultSymbols = copyHashTable(DefaultSymbols);
+        defaultLookUp = copyHashTable(DefaultLookUp);
+    }
+
+    protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid,
+    		String value) {
+    	if (oid.equals(dc))
+        {
+            return new DERIA5String(value);
+        }
+        else if (oid.equals(c) || oid.equals(serialNumber) || oid.equals(dnQualifier)
+            || oid.equals(telephoneNumber))
+        {
+            return new DERPrintableString(value);
+        }
+
+    	return super.encodeStringValue(oid, value);
+    }
+
+    public String oidToDisplayName(ASN1ObjectIdentifier oid)
+    {
+        return (String)DefaultSymbols.get(oid);
+    }
+
+    public String[] oidToAttrNames(ASN1ObjectIdentifier oid)
+    {
+        return IETFUtils.findAttrNamesForOID(oid, defaultLookUp);
+    }
+
+    public ASN1ObjectIdentifier attrNameToOID(String attrName)
+    {
+        return IETFUtils.decodeAttrName(attrName, defaultLookUp);
+    }
+
+    // parse backwards
+    public RDN[] fromString(String dirName)
+    {
+        RDN[] tmp = IETFUtils.rDNsFromString(dirName, this);
+        RDN[] res = new RDN[tmp.length];
+
+        for (int i = 0; i != tmp.length; i++)
+        {
+            res[res.length - i - 1] = tmp[i];
+        }
+
+        return res;
+    }
+
+    // convert in reverse
+    public String toString(X500Name name)
+    {
+        StringBuffer buf = new StringBuffer();
+        boolean first = true;
+
+        RDN[] rdns = name.getRDNs();
+
+        for (int i = rdns.length - 1; i >= 0; i--)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                buf.append(',');
+            }
+
+            IETFUtils.appendRDN(buf, rdns[i], defaultSymbols);
+        }
+
+        return buf.toString();
+    }
+
+    
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java
new file mode 100644
index 0000000..6622550
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java
@@ -0,0 +1,92 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x500.style;
+
+/**
+ * class for breaking up an X500 Name into it's component tokens, ala
+ * java.util.StringTokenizer. We need this class as some of the
+ * lightweight Java environment don't support classes like
+ * StringTokenizer.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X500NameTokenizer
+{
+    private String          value;
+    private int             index;
+    private char            separator;
+    private StringBuffer    buf = new StringBuffer();
+
+    public X500NameTokenizer(
+        String  oid)
+    {
+        this(oid, ',');
+    }
+    
+    public X500NameTokenizer(
+        String  oid,
+        char    separator)
+    {
+        this.value = oid;
+        this.index = -1;
+        this.separator = separator;
+    }
+
+    public boolean hasMoreTokens()
+    {
+        return (index != value.length());
+    }
+
+    public String nextToken()
+    {
+        if (index == value.length())
+        {
+            return null;
+        }
+
+        int     end = index + 1;
+        boolean quoted = false;
+        boolean escaped = false;
+
+        buf.setLength(0);
+
+        while (end != value.length())
+        {
+            char    c = value.charAt(end);
+
+            if (c == '"')
+            {
+                if (!escaped)
+                {
+                    quoted = !quoted;
+                }
+                buf.append(c);
+                escaped = false;
+            }
+            else
+            {
+                if (escaped || quoted)
+                {
+                    buf.append(c);
+                    escaped = false;
+                }
+                else if (c == '\\')
+                {
+                    buf.append(c);
+                    escaped = true;
+                }
+                else if (c == separator)
+                {
+                    break;
+                }
+                else
+                {
+                    buf.append(c);
+                }
+            }
+            end++;
+        }
+
+        index = end;
+
+        return buf.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
new file mode 100644
index 0000000..c5da2d9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
@@ -0,0 +1,110 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlgorithmIdentifier
+    extends ASN1Object
+{
+    private ASN1ObjectIdentifier algorithm;
+    private ASN1Encodable       parameters;
+
+    public static AlgorithmIdentifier getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    public static AlgorithmIdentifier getInstance(
+        Object  obj)
+    {
+        if (obj instanceof AlgorithmIdentifier)
+        {
+            return (AlgorithmIdentifier)obj;
+        }
+        else if (obj != null)
+        {
+            return new AlgorithmIdentifier(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public AlgorithmIdentifier(
+        ASN1ObjectIdentifier algorithm)
+    {
+        this.algorithm = algorithm;
+    }
+
+    public AlgorithmIdentifier(
+        ASN1ObjectIdentifier algorithm,
+        ASN1Encodable           parameters)
+    {
+        this.algorithm = algorithm;
+        this.parameters = parameters;
+    }
+
+    private AlgorithmIdentifier(
+        ASN1Sequence   seq)
+    {
+        if (seq.size() < 1 || seq.size() > 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+        
+        algorithm = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+
+        if (seq.size() == 2)
+        {
+            parameters = seq.getObjectAt(1);
+        }
+        else
+        {
+            parameters = null;
+        }
+    }
+
+    public ASN1ObjectIdentifier getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    public ASN1Encodable getParameters()
+    {
+        return parameters;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *      AlgorithmIdentifier ::= SEQUENCE {
+     *                            algorithm OBJECT IDENTIFIER,
+     *                            parameters ANY DEFINED BY algorithm OPTIONAL }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(algorithm);
+
+        if (parameters != null)
+        {
+            v.add(parameters);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttCertIssuer.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttCertIssuer.java
new file mode 100644
index 0000000..ea2103f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttCertIssuer.java
@@ -0,0 +1,95 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Choice;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AttCertIssuer
+    extends ASN1Object
+    implements ASN1Choice
+{
+    ASN1Encodable   obj;
+    ASN1Primitive choiceObj;
+    
+    public static AttCertIssuer getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof AttCertIssuer)
+        {
+            return (AttCertIssuer)obj;
+        }
+        else if (obj instanceof V2Form)
+        {
+            return new AttCertIssuer(V2Form.getInstance(obj));
+        }
+        else if (obj instanceof GeneralNames)
+        {
+            return new AttCertIssuer((GeneralNames)obj);
+        }
+        else if (obj instanceof ASN1TaggedObject)
+        {
+            return new AttCertIssuer(V2Form.getInstance((ASN1TaggedObject)obj, false));
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new AttCertIssuer(GeneralNames.getInstance(obj));
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+    }
+    
+    public static AttCertIssuer getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject()); // must be explicitly tagged
+    }
+
+    /**
+     * Don't use this one if you are trying to be RFC 3281 compliant.
+     * Use it for v1 attribute certificates only.
+     * 
+     * @param names our GeneralNames structure
+     */
+    public AttCertIssuer(
+        GeneralNames  names)
+    {
+        obj = names;
+        choiceObj = obj.toASN1Primitive();
+    }
+    
+    public AttCertIssuer(
+        V2Form  v2Form)
+    {
+        obj = v2Form;
+        choiceObj = new DERTaggedObject(false, 0, obj);
+    }
+
+    public ASN1Encodable getIssuer()
+    {
+        return obj;
+    }
+    
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  AttCertIssuer ::= CHOICE {
+     *       v1Form   GeneralNames,  -- MUST NOT be used in this
+     *                               -- profile
+     *       v2Form   [0] V2Form     -- v2 only
+     *  }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return choiceObj;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
new file mode 100644
index 0000000..be63354
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
@@ -0,0 +1,88 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1GeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AttCertValidityPeriod
+    extends ASN1Object
+{
+    ASN1GeneralizedTime  notBeforeTime;
+    ASN1GeneralizedTime  notAfterTime;
+
+    public static AttCertValidityPeriod getInstance(
+            Object  obj)
+    {
+        if (obj instanceof AttCertValidityPeriod)
+        {
+            return (AttCertValidityPeriod)obj;
+        }
+        else if (obj != null)
+        {
+            return new AttCertValidityPeriod(ASN1Sequence.getInstance(obj));
+        }
+        
+        return null;
+    }
+    
+    private AttCertValidityPeriod(
+        ASN1Sequence    seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        notBeforeTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(0));
+        notAfterTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(1));
+    }
+
+    /**
+     * @param notBeforeTime
+     * @param notAfterTime
+     */
+    public AttCertValidityPeriod(
+        ASN1GeneralizedTime notBeforeTime,
+        ASN1GeneralizedTime notAfterTime)
+    {
+        this.notBeforeTime = notBeforeTime;
+        this.notAfterTime = notAfterTime;
+    }
+
+    public ASN1GeneralizedTime getNotBeforeTime()
+    {
+        return notBeforeTime;
+    }
+
+    public ASN1GeneralizedTime getNotAfterTime()
+    {
+        return notAfterTime;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  AttCertValidityPeriod  ::= SEQUENCE {
+     *       notBeforeTime  GeneralizedTime,
+     *       notAfterTime   GeneralizedTime
+     *  } 
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(notBeforeTime);
+        v.add(notAfterTime);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Attribute.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Attribute.java
new file mode 100644
index 0000000..4ac78b5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Attribute.java
@@ -0,0 +1,97 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Attribute
+    extends ASN1Object
+{
+    private ASN1ObjectIdentifier attrType;
+    private ASN1Set             attrValues;
+
+    /**
+     * return an Attribute object from the given object.
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static Attribute getInstance(
+        Object o)
+    {
+        if (o instanceof Attribute)
+        {
+            return (Attribute)o;
+        }
+        
+        if (o != null)
+        {
+            return new Attribute(ASN1Sequence.getInstance(o));
+        }
+
+        return null;
+    }
+    
+    private Attribute(
+        ASN1Sequence seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        attrType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+        attrValues = ASN1Set.getInstance(seq.getObjectAt(1));
+    }
+
+    public Attribute(
+        ASN1ObjectIdentifier attrType,
+        ASN1Set             attrValues)
+    {
+        this.attrType = attrType;
+        this.attrValues = attrValues;
+    }
+
+    public ASN1ObjectIdentifier getAttrType()
+    {
+        return new ASN1ObjectIdentifier(attrType.getId());
+    }
+
+    public ASN1Encodable[] getAttributeValues()
+    {
+        return attrValues.toArray();
+    }
+
+    public ASN1Set getAttrValues()
+    {
+        return attrValues;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Attribute ::= SEQUENCE {
+     *     attrType OBJECT IDENTIFIER,
+     *     attrValues SET OF AttributeValue
+     * }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(attrType);
+        v.add(attrValues);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttributeCertificate.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttributeCertificate.java
new file mode 100644
index 0000000..4ff69d4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttributeCertificate.java
@@ -0,0 +1,101 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AttributeCertificate
+    extends ASN1Object
+{
+    AttributeCertificateInfo    acinfo;
+    AlgorithmIdentifier         signatureAlgorithm;
+    DERBitString                signatureValue;
+
+    /**
+     * @param obj
+     * @return an AttributeCertificate object
+     */
+    public static AttributeCertificate getInstance(Object obj)
+    {
+        if (obj instanceof AttributeCertificate)
+        {
+            return (AttributeCertificate)obj;
+        }
+        else if (obj != null)
+        {
+            return new AttributeCertificate(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+    
+    public AttributeCertificate(
+        AttributeCertificateInfo    acinfo,
+        AlgorithmIdentifier         signatureAlgorithm,
+        DERBitString                signatureValue)
+    {
+        this.acinfo = acinfo;
+        this.signatureAlgorithm = signatureAlgorithm;
+        this.signatureValue = signatureValue;
+    }
+
+    /**
+     * @deprecated use getInstance() method.
+     */
+    public AttributeCertificate(
+        ASN1Sequence    seq)
+    {
+        if (seq.size() != 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        this.acinfo = AttributeCertificateInfo.getInstance(seq.getObjectAt(0));
+        this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+        this.signatureValue = DERBitString.getInstance(seq.getObjectAt(2));
+    }
+    
+    public AttributeCertificateInfo getAcinfo()
+    {
+        return acinfo;
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return signatureAlgorithm;
+    }
+
+    public DERBitString getSignatureValue()
+    {
+        return signatureValue;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  AttributeCertificate ::= SEQUENCE {
+     *       acinfo               AttributeCertificateInfo,
+     *       signatureAlgorithm   AlgorithmIdentifier,
+     *       signatureValue       BIT STRING
+     *  }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(acinfo);
+        v.add(signatureAlgorithm);
+        v.add(signatureValue);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
new file mode 100644
index 0000000..8d54f21
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
@@ -0,0 +1,184 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AttributeCertificateInfo
+    extends ASN1Object
+{
+    private ASN1Integer             version;
+    private Holder                  holder;
+    private AttCertIssuer           issuer;
+    private AlgorithmIdentifier     signature;
+    private ASN1Integer              serialNumber;
+    private AttCertValidityPeriod   attrCertValidityPeriod;
+    private ASN1Sequence            attributes;
+    private DERBitString            issuerUniqueID;
+    private Extensions              extensions;
+
+    public static AttributeCertificateInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static AttributeCertificateInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof AttributeCertificateInfo)
+        {
+            return (AttributeCertificateInfo)obj;
+        }
+        else if (obj != null)
+        {
+            return new AttributeCertificateInfo(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private AttributeCertificateInfo(
+        ASN1Sequence   seq)
+    {
+        if (seq.size() < 6 || seq.size() > 9)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        int start;
+        if (seq.getObjectAt(0) instanceof ASN1Integer)   // in version 1 certs version is DEFAULT  v1(0)
+        {
+            this.version = ASN1Integer.getInstance(seq.getObjectAt(0));
+            start = 1;
+        }
+        else
+        {
+            this.version = new ASN1Integer(0);
+            start = 0;
+        }
+
+        this.holder = Holder.getInstance(seq.getObjectAt(start));
+        this.issuer = AttCertIssuer.getInstance(seq.getObjectAt(start + 1));
+        this.signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(start + 2));
+        this.serialNumber = ASN1Integer.getInstance(seq.getObjectAt(start + 3));
+        this.attrCertValidityPeriod = AttCertValidityPeriod.getInstance(seq.getObjectAt(start + 4));
+        this.attributes = ASN1Sequence.getInstance(seq.getObjectAt(start + 5));
+        
+        for (int i = start + 6; i < seq.size(); i++)
+        {
+            ASN1Encodable    obj = seq.getObjectAt(i);
+
+            if (obj instanceof DERBitString)
+            {
+                this.issuerUniqueID = DERBitString.getInstance(seq.getObjectAt(i));
+            }
+            else if (obj instanceof ASN1Sequence || obj instanceof Extensions)
+            {
+                this.extensions = Extensions.getInstance(seq.getObjectAt(i));
+            }
+        }
+    }
+    
+    public ASN1Integer getVersion()
+    {
+        return version;
+    }
+
+    public Holder getHolder()
+    {
+        return holder;
+    }
+
+    public AttCertIssuer getIssuer()
+    {
+        return issuer;
+    }
+
+    public AlgorithmIdentifier getSignature()
+    {
+        return signature;
+    }
+
+    public ASN1Integer getSerialNumber()
+    {
+        return serialNumber;
+    }
+
+    public AttCertValidityPeriod getAttrCertValidityPeriod()
+    {
+        return attrCertValidityPeriod;
+    }
+
+    public ASN1Sequence getAttributes()
+    {
+        return attributes;
+    }
+
+    public DERBitString getIssuerUniqueID()
+    {
+        return issuerUniqueID;
+    }
+
+    public Extensions getExtensions()
+    {
+        return extensions;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  AttributeCertificateInfo ::= SEQUENCE {
+     *       version              AttCertVersion -- version is v2,
+     *       holder               Holder,
+     *       issuer               AttCertIssuer,
+     *       signature            AlgorithmIdentifier,
+     *       serialNumber         CertificateSerialNumber,
+     *       attrCertValidityPeriod   AttCertValidityPeriod,
+     *       attributes           SEQUENCE OF Attribute,
+     *       issuerUniqueID       UniqueIdentifier OPTIONAL,
+     *       extensions           Extensions OPTIONAL
+     *  }
+     *
+     *  AttCertVersion ::= INTEGER { v2(1) }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (version.getValue().intValue() != 0)
+        {
+            v.add(version);
+        }
+        v.add(holder);
+        v.add(issuer);
+        v.add(signature);
+        v.add(serialNumber);
+        v.add(attrCertValidityPeriod);
+        v.add(attributes);
+        
+        if (issuerUniqueID != null)
+        {
+            v.add(issuerUniqueID);
+        }
+        
+        if (extensions != null)
+        {
+            v.add(extensions);
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
new file mode 100644
index 0000000..808803a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
@@ -0,0 +1,238 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+// Android-changed: Use Android digests
+// import org.bouncycastle.crypto.digests.SHA1Digest;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * The AuthorityKeyIdentifier object.
+ * <pre>
+ * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }
+ *
+ *   AuthorityKeyIdentifier ::= SEQUENCE {
+ *      keyIdentifier             [0] IMPLICIT KeyIdentifier           OPTIONAL,
+ *      authorityCertIssuer       [1] IMPLICIT GeneralNames            OPTIONAL,
+ *      authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL  }
+ *
+ *   KeyIdentifier ::= OCTET STRING
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ *
+ */
+public class AuthorityKeyIdentifier
+    extends ASN1Object
+{
+    ASN1OctetString keyidentifier=null;
+    GeneralNames certissuer=null;
+    ASN1Integer certserno=null;
+
+    public static AuthorityKeyIdentifier getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static AuthorityKeyIdentifier getInstance(
+        Object  obj)
+    {
+        if (obj instanceof AuthorityKeyIdentifier)
+        {
+            return (AuthorityKeyIdentifier)obj;
+        }
+        if (obj != null)
+        {
+            return new AuthorityKeyIdentifier(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static AuthorityKeyIdentifier fromExtensions(Extensions extensions)
+    {
+         return AuthorityKeyIdentifier.getInstance(extensions.getExtensionParsedValue(Extension.authorityKeyIdentifier));
+    }
+
+    protected AuthorityKeyIdentifier(
+        ASN1Sequence   seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1TaggedObject o = DERTaggedObject.getInstance(e.nextElement());
+
+            switch (o.getTagNo())
+            {
+            case 0:
+                this.keyidentifier = ASN1OctetString.getInstance(o, false);
+                break;
+            case 1:
+                this.certissuer = GeneralNames.getInstance(o, false);
+                break;
+            case 2:
+                this.certserno = ASN1Integer.getInstance(o, false);
+                break;
+            default:
+                throw new IllegalArgumentException("illegal tag");
+            }
+        }
+    }
+
+    /**
+     *
+     * Calulates the keyidentifier using a SHA1 hash over the BIT STRING
+     * from SubjectPublicKeyInfo as defined in RFC2459.
+     *
+     * Example of making a AuthorityKeyIdentifier:
+     * <pre>
+     *   SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+     *       publicKey.getEncoded()).readObject());
+     *   AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki);
+     * </pre>
+     * @deprecated create the extension using org.bouncycastle.cert.X509ExtensionUtils
+     **/
+    public AuthorityKeyIdentifier(
+        SubjectPublicKeyInfo    spki)
+    {
+        // Android-changed: Use Android digests
+        // Digest  digest = new SHA1Digest();
+        Digest  digest = AndroidDigestFactory.getSHA1();
+        byte[]  resBuf = new byte[digest.getDigestSize()];
+
+        byte[] bytes = spki.getPublicKeyData().getBytes();
+        digest.update(bytes, 0, bytes.length);
+        digest.doFinal(resBuf, 0);
+        this.keyidentifier = new DEROctetString(resBuf);
+    }
+
+    /**
+     * create an AuthorityKeyIdentifier with the GeneralNames tag and
+     * the serial number provided as well.
+     * @deprecated create the extension using org.bouncycastle.cert.X509ExtensionUtils
+     */
+    public AuthorityKeyIdentifier(
+        SubjectPublicKeyInfo    spki,
+        GeneralNames            name,
+        BigInteger              serialNumber)
+    {
+        // Android-changed: Use Android digests
+        // Digest  digest = new SHA1Digest();
+        Digest  digest = AndroidDigestFactory.getSHA1();
+        byte[]  resBuf = new byte[digest.getDigestSize()];
+
+        byte[] bytes = spki.getPublicKeyData().getBytes();
+        digest.update(bytes, 0, bytes.length);
+        digest.doFinal(resBuf, 0);
+
+        this.keyidentifier = new DEROctetString(resBuf);
+        this.certissuer = GeneralNames.getInstance(name.toASN1Primitive());
+        this.certserno = new ASN1Integer(serialNumber);
+    }
+
+    /**
+     * create an AuthorityKeyIdentifier with the GeneralNames tag and
+     * the serial number provided.
+     */
+    public AuthorityKeyIdentifier(
+        GeneralNames            name,
+        BigInteger              serialNumber)
+    {
+        this((byte[])null, name, serialNumber);
+    }
+
+    /**
+      * create an AuthorityKeyIdentifier with a precomputed key identifier
+      */
+     public AuthorityKeyIdentifier(
+         byte[]                  keyIdentifier)
+     {
+         this(keyIdentifier, null, null);
+     }
+
+    /**
+     * create an AuthorityKeyIdentifier with a precomputed key identifier
+     * and the GeneralNames tag and the serial number provided as well.
+     */
+    public AuthorityKeyIdentifier(
+        byte[]                  keyIdentifier,
+        GeneralNames            name,
+        BigInteger              serialNumber)
+    {
+        this.keyidentifier = (keyIdentifier != null) ? new DEROctetString(keyIdentifier) : null;
+        this.certissuer = name;
+        this.certserno = (serialNumber != null) ? new ASN1Integer(serialNumber) : null;
+    }
+    
+    public byte[] getKeyIdentifier()
+    {
+        if (keyidentifier != null)
+        {
+            return keyidentifier.getOctets();
+        }
+
+        return null;
+    }
+
+    public GeneralNames getAuthorityCertIssuer()
+    {
+        return certissuer;
+    }
+    
+    public BigInteger getAuthorityCertSerialNumber()
+    {
+        if (certserno != null)
+        {
+            return certserno.getValue();
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (keyidentifier != null)
+        {
+            v.add(new DERTaggedObject(false, 0, keyidentifier));
+        }
+
+        if (certissuer != null)
+        {
+            v.add(new DERTaggedObject(false, 1, certissuer));
+        }
+
+        if (certserno != null)
+        {
+            v.add(new DERTaggedObject(false, 2, certserno));
+        }
+
+
+        return new DERSequence(v);
+    }
+
+    public String toString()
+    {
+        return ("AuthorityKeyIdentifier: KeyID(" + ((keyidentifier != null) ? Hex.toHexString(this.keyidentifier.getOctets()) : "null") + ")");
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/BasicConstraints.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/BasicConstraints.java
new file mode 100644
index 0000000..c23f92e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/BasicConstraints.java
@@ -0,0 +1,167 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Boolean;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BasicConstraints
+    extends ASN1Object
+{
+    ASN1Boolean  cA = ASN1Boolean.getInstance(false);
+    ASN1Integer  pathLenConstraint = null;
+
+    public static BasicConstraints getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static BasicConstraints getInstance(
+        Object  obj)
+    {
+        if (obj instanceof BasicConstraints)
+        {
+            return (BasicConstraints)obj;
+        }
+        if (obj instanceof X509Extension)
+        {
+            return getInstance(X509Extension.convertValueToObject((X509Extension)obj));
+        }
+        if (obj != null)
+        {
+            return new BasicConstraints(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static BasicConstraints fromExtensions(Extensions extensions)
+    {
+        return BasicConstraints.getInstance(extensions.getExtensionParsedValue(Extension.basicConstraints));
+    }
+
+    private BasicConstraints(
+        ASN1Sequence   seq)
+    {
+        if (seq.size() == 0)
+        {
+            this.cA = null;
+            this.pathLenConstraint = null;
+        }
+        else
+        {
+            if (seq.getObjectAt(0) instanceof ASN1Boolean)
+            {
+                this.cA = ASN1Boolean.getInstance(seq.getObjectAt(0));
+            }
+            else
+            {
+                this.cA = null;
+                this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(0));
+            }
+            if (seq.size() > 1)
+            {
+                if (this.cA != null)
+                {
+                    this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(1));
+                }
+                else
+                {
+                    throw new IllegalArgumentException("wrong sequence in constructor");
+                }
+            }
+        }
+    }
+
+    public BasicConstraints(
+        boolean cA)
+    {
+        if (cA)
+        {
+            this.cA = ASN1Boolean.getInstance(true);
+        }
+        else
+        {
+            this.cA = null;
+        }
+        this.pathLenConstraint = null;
+    }
+
+    /**
+     * create a cA=true object for the given path length constraint.
+     * 
+     * @param pathLenConstraint
+     */
+    public BasicConstraints(
+        int     pathLenConstraint)
+    {
+        this.cA = ASN1Boolean.getInstance(true);
+        this.pathLenConstraint = new ASN1Integer(pathLenConstraint);
+    }
+
+    public boolean isCA()
+    {
+        return (cA != null) && cA.isTrue();
+    }
+
+    public BigInteger getPathLenConstraint()
+    {
+        if (pathLenConstraint != null)
+        {
+            return pathLenConstraint.getValue();
+        }
+
+        return null;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * BasicConstraints := SEQUENCE {
+     *    cA                  BOOLEAN DEFAULT FALSE,
+     *    pathLenConstraint   INTEGER (0..MAX) OPTIONAL
+     * }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (cA != null)
+        {
+            v.add(cA);
+        }
+
+        if (pathLenConstraint != null)  // yes some people actually do this when cA is false...
+        {
+            v.add(pathLenConstraint);
+        }
+
+        return new DERSequence(v);
+    }
+
+    public String toString()
+    {
+        if (pathLenConstraint == null)
+        {
+            if (cA == null)
+            {
+                return "BasicConstraints: isCa(false)";
+            }
+            return "BasicConstraints: isCa(" + this.isCA() + ")";
+        }
+        return "BasicConstraints: isCa(" + this.isCA() + "), pathLenConstraint = " + pathLenConstraint.getValue();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CRLDistPoint.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CRLDistPoint.java
new file mode 100644
index 0000000..561b1ca
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CRLDistPoint.java
@@ -0,0 +1,110 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CRLDistPoint
+    extends ASN1Object
+{
+    ASN1Sequence  seq = null;
+
+    public static CRLDistPoint getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static CRLDistPoint fromExtensions(Extensions extensions)
+    {
+        return CRLDistPoint.getInstance(extensions.getExtensionParsedValue(Extension.cRLDistributionPoints));
+    }
+
+    public static CRLDistPoint getInstance(
+        Object  obj)
+    {
+        if (obj instanceof CRLDistPoint)
+        {
+            return (CRLDistPoint)obj;
+        }
+        else if (obj != null)
+        {
+            return new CRLDistPoint(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private CRLDistPoint(
+        ASN1Sequence seq)
+    {
+        this.seq = seq;
+    }
+    
+    public CRLDistPoint(
+        DistributionPoint[] points)
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        for (int i = 0; i != points.length; i++)
+        {
+            v.add(points[i]);
+        }
+
+        seq = new DERSequence(v);
+    }
+
+    /**
+     * Return the distribution points making up the sequence.
+     * 
+     * @return DistributionPoint[]
+     */
+    public DistributionPoint[] getDistributionPoints()
+    {
+        DistributionPoint[]    dp = new DistributionPoint[seq.size()];
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            dp[i] = DistributionPoint.getInstance(seq.getObjectAt(i));
+        }
+        
+        return dp;
+    }
+    
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * CRLDistPoint ::= SEQUENCE SIZE {1..MAX} OF DistributionPoint
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        String       sep = Strings.lineSeparator();
+
+        buf.append("CRLDistPoint:");
+        buf.append(sep);
+        DistributionPoint dp[] = getDistributionPoints();
+        for (int i = 0; i != dp.length; i++)
+        {
+            buf.append("    ");
+            buf.append(dp[i]);
+            buf.append(sep);
+        }
+        return buf.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CRLNumber.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CRLNumber.java
new file mode 100644
index 0000000..291bf6c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CRLNumber.java
@@ -0,0 +1,56 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+
+/**
+ * The CRLNumber object.
+ * <pre>
+ * CRLNumber::= INTEGER(0..MAX)
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CRLNumber
+    extends ASN1Object
+{
+    private BigInteger number;
+
+    public CRLNumber(
+        BigInteger number)
+    {
+        this.number = number;
+    }
+
+    public BigInteger getCRLNumber()
+    {
+        return number;
+    }
+
+    public String toString()
+    {
+        return "CRLNumber: " + getCRLNumber();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return new ASN1Integer(number);
+    }
+
+    public static CRLNumber getInstance(Object o)
+    {
+        if (o instanceof CRLNumber)
+        {
+            return (CRLNumber)o;
+        }
+        else if (o != null)
+        {
+            return new CRLNumber(ASN1Integer.getInstance(o).getValue());
+        }
+
+        return null;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CRLReason.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CRLReason.java
new file mode 100644
index 0000000..f446b9e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CRLReason.java
@@ -0,0 +1,153 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Hashtable;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.util.Integers;
+
+/**
+ * The CRLReason enumeration.
+ * <pre>
+ * CRLReason ::= ENUMERATED {
+ *  unspecified             (0),
+ *  keyCompromise           (1),
+ *  cACompromise            (2),
+ *  affiliationChanged      (3),
+ *  superseded              (4),
+ *  cessationOfOperation    (5),
+ *  certificateHold         (6),
+ *  removeFromCRL           (8),
+ *  privilegeWithdrawn      (9),
+ *  aACompromise           (10)
+ * }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CRLReason
+    extends ASN1Object
+{
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int UNSPECIFIED = 0;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int KEY_COMPROMISE = 1;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CA_COMPROMISE = 2;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int AFFILIATION_CHANGED = 3;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int SUPERSEDED = 4;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CESSATION_OF_OPERATION  = 5;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CERTIFICATE_HOLD = 6;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int REMOVE_FROM_CRL = 8;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int PRIVILEGE_WITHDRAWN = 9;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int AA_COMPROMISE = 10;
+
+    public static final int unspecified = 0;
+    public static final int keyCompromise = 1;
+    public static final int cACompromise = 2;
+    public static final int affiliationChanged = 3;
+    public static final int superseded = 4;
+    public static final int cessationOfOperation  = 5;
+    public static final int certificateHold = 6;
+    // 7 -> unknown
+    public static final int removeFromCRL = 8;
+    public static final int privilegeWithdrawn = 9;
+    public static final int aACompromise = 10;
+
+    private static final String[] reasonString =
+    {
+        "unspecified", "keyCompromise", "cACompromise", "affiliationChanged",
+        "superseded", "cessationOfOperation", "certificateHold", "unknown",
+        "removeFromCRL", "privilegeWithdrawn", "aACompromise"
+    };
+
+    private static final Hashtable table = new Hashtable();
+
+    private ASN1Enumerated value;
+
+    public static CRLReason getInstance(Object o)
+    {
+        if (o instanceof CRLReason)
+        {
+            return (CRLReason)o;
+        }
+        else if (o != null)
+        {
+            return lookup(ASN1Enumerated.getInstance(o).getValue().intValue());
+        }
+
+        return null;
+    }
+
+    private CRLReason(
+        int reason)
+    {
+        value = new ASN1Enumerated(reason);
+    }
+
+    public String toString()
+    {
+        String str;
+        int reason = getValue().intValue();
+        if (reason < 0 || reason > 10)
+        {
+            str = "invalid";
+        }
+        else
+        {
+            str = reasonString[reason];
+        }
+        return "CRLReason: " + str;
+    }
+
+    public BigInteger getValue()
+    {
+        return value.getValue();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return value;
+    }
+
+    public static CRLReason lookup(int value)
+    {
+        Integer idx = Integers.valueOf(value);
+
+        if (!table.containsKey(idx))
+        {
+            table.put(idx, new CRLReason(value));
+        }
+
+        return (CRLReason)table.get(idx);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Certificate.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Certificate.java
new file mode 100644
index 0000000..667c834
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Certificate.java
@@ -0,0 +1,133 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * an X509Certificate structure.
+ * <pre>
+ *  Certificate ::= SEQUENCE {
+ *      tbsCertificate          TBSCertificate,
+ *      signatureAlgorithm      AlgorithmIdentifier,
+ *      signature               BIT STRING
+ *  }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Certificate
+    extends ASN1Object
+{
+    ASN1Sequence  seq;
+    TBSCertificate tbsCert;
+    AlgorithmIdentifier     sigAlgId;
+    DERBitString            sig;
+
+    public static Certificate getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static Certificate getInstance(
+        Object  obj)
+    {
+        if (obj instanceof Certificate)
+        {
+            return (Certificate)obj;
+        }
+        else if (obj != null)
+        {
+            return new Certificate(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private Certificate(
+        ASN1Sequence seq)
+    {
+        this.seq = seq;
+
+        //
+        // correct x509 certficate
+        //
+        if (seq.size() == 3)
+        {
+            tbsCert = TBSCertificate.getInstance(seq.getObjectAt(0));
+            sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+
+            sig = DERBitString.getInstance(seq.getObjectAt(2));
+        }
+        else
+        {
+            throw new IllegalArgumentException("sequence wrong size for a certificate");
+        }
+    }
+
+    public TBSCertificate getTBSCertificate()
+    {
+        return tbsCert;
+    }
+
+    public ASN1Integer getVersion()
+    {
+        return tbsCert.getVersion();
+    }
+
+    public int getVersionNumber()
+    {
+        return tbsCert.getVersionNumber();
+    }
+
+    public ASN1Integer getSerialNumber()
+    {
+        return tbsCert.getSerialNumber();
+    }
+
+    public X500Name getIssuer()
+    {
+        return tbsCert.getIssuer();
+    }
+
+    public Time getStartDate()
+    {
+        return tbsCert.getStartDate();
+    }
+
+    public Time getEndDate()
+    {
+        return tbsCert.getEndDate();
+    }
+
+    public X500Name getSubject()
+    {
+        return tbsCert.getSubject();
+    }
+
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+    {
+        return tbsCert.getSubjectPublicKeyInfo();
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return sigAlgId;
+    }
+
+    public DERBitString getSignature()
+    {
+        return sig;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CertificateList.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CertificateList.java
new file mode 100644
index 0000000..2b18089
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/CertificateList.java
@@ -0,0 +1,146 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * PKIX RFC-2459
+ *
+ * The X.509 v2 CRL syntax is as follows.  For signature calculation,
+ * the data that is to be signed is ASN.1 DER encoded.
+ *
+ * <pre>
+ * CertificateList  ::=  SEQUENCE  {
+ *      tbsCertList          TBSCertList,
+ *      signatureAlgorithm   AlgorithmIdentifier,
+ *      signatureValue       BIT STRING  }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CertificateList
+    extends ASN1Object
+{
+    TBSCertList            tbsCertList;
+    AlgorithmIdentifier    sigAlgId;
+    DERBitString           sig;
+    boolean                isHashCodeSet = false;
+    int                    hashCodeValue;
+
+    public static CertificateList getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static CertificateList getInstance(
+        Object  obj)
+    {
+        if (obj instanceof CertificateList)
+        {
+            return (CertificateList)obj;
+        }
+        else if (obj != null)
+        {
+            return new CertificateList(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * @deprecated use getInstance() method.
+     * @param seq
+     */
+    public CertificateList(
+        ASN1Sequence seq)
+    {
+        if (seq.size() == 3)
+        {
+            tbsCertList = TBSCertList.getInstance(seq.getObjectAt(0));
+            sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+            sig = DERBitString.getInstance(seq.getObjectAt(2));
+        }
+        else
+        {
+            throw new IllegalArgumentException("sequence wrong size for CertificateList");
+        }
+    }
+
+    public TBSCertList getTBSCertList()
+    {
+        return tbsCertList;
+    }
+
+    public TBSCertList.CRLEntry[] getRevokedCertificates()
+    {
+        return tbsCertList.getRevokedCertificates();
+    }
+
+    public Enumeration getRevokedCertificateEnumeration()
+    {
+        return tbsCertList.getRevokedCertificateEnumeration();
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return sigAlgId;
+    }
+
+    public DERBitString getSignature()
+    {
+        return sig;
+    }
+
+    public int getVersionNumber()
+    {
+        return tbsCertList.getVersionNumber();
+    }
+
+    public X500Name getIssuer()
+    {
+        return tbsCertList.getIssuer();
+    }
+
+    public Time getThisUpdate()
+    {
+        return tbsCertList.getThisUpdate();
+    }
+
+    public Time getNextUpdate()
+    {
+        return tbsCertList.getNextUpdate();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(tbsCertList);
+        v.add(sigAlgId);
+        v.add(sig);
+
+        return new DERSequence(v);
+    }
+
+    public int hashCode()
+    {
+        if (!isHashCodeSet)
+        {
+            hashCodeValue = super.hashCode();
+            isHashCodeSet = true;
+        }
+
+        return hashCodeValue;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DSAParameter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DSAParameter.java
new file mode 100644
index 0000000..6ef3ea7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DSAParameter.java
@@ -0,0 +1,96 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSAParameter
+    extends ASN1Object
+{
+    ASN1Integer      p, q, g;
+
+    public static DSAParameter getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static DSAParameter getInstance(
+        Object obj)
+    {
+        if (obj instanceof DSAParameter)
+        {
+            return (DSAParameter)obj;
+        }
+        
+        if(obj != null)
+        {
+            return new DSAParameter(ASN1Sequence.getInstance(obj));
+        }
+        
+        return null;
+    }
+
+    public DSAParameter(
+        BigInteger  p,
+        BigInteger  q,
+        BigInteger  g)
+    {
+        this.p = new ASN1Integer(p);
+        this.q = new ASN1Integer(q);
+        this.g = new ASN1Integer(g);
+    }
+
+    private DSAParameter(
+        ASN1Sequence  seq)
+    {
+        if (seq.size() != 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+        
+        Enumeration     e = seq.getObjects();
+
+        p = ASN1Integer.getInstance(e.nextElement());
+        q = ASN1Integer.getInstance(e.nextElement());
+        g = ASN1Integer.getInstance(e.nextElement());
+    }
+
+    public BigInteger getP()
+    {
+        return p.getPositiveValue();
+    }
+
+    public BigInteger getQ()
+    {
+        return q.getPositiveValue();
+    }
+
+    public BigInteger getG()
+    {
+        return g.getPositiveValue();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(p);
+        v.add(q);
+        v.add(g);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DigestInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DigestInfo.java
new file mode 100644
index 0000000..b829a59
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DigestInfo.java
@@ -0,0 +1,89 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * The DigestInfo object.
+ * <pre>
+ * DigestInfo::=SEQUENCE{
+ *          digestAlgorithm  AlgorithmIdentifier,
+ *          digest OCTET STRING }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DigestInfo
+    extends ASN1Object
+{
+    private byte[]                  digest;
+    private AlgorithmIdentifier     algId;
+
+    public static DigestInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static DigestInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof DigestInfo)
+        {
+            return (DigestInfo)obj;
+        }
+        else if (obj != null)
+        {
+            return new DigestInfo(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public DigestInfo(
+        AlgorithmIdentifier  algId,
+        byte[]               digest)
+    {
+        this.digest = Arrays.clone(digest);
+        this.algId = algId;
+    }
+
+    public DigestInfo(
+        ASN1Sequence  obj)
+    {
+        Enumeration             e = obj.getObjects();
+
+        algId = AlgorithmIdentifier.getInstance(e.nextElement());
+        digest = ASN1OctetString.getInstance(e.nextElement()).getOctets();
+    }
+
+    public AlgorithmIdentifier getAlgorithmId()
+    {
+        return algId;
+    }
+
+    public byte[] getDigest()
+    {
+        return Arrays.clone(digest);
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(algId);
+        v.add(new DEROctetString(digest));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DistributionPoint.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DistributionPoint.java
new file mode 100644
index 0000000..542ea06
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DistributionPoint.java
@@ -0,0 +1,164 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * The DistributionPoint object.
+ * <pre>
+ * DistributionPoint ::= SEQUENCE {
+ *      distributionPoint [0] DistributionPointName OPTIONAL,
+ *      reasons           [1] ReasonFlags OPTIONAL,
+ *      cRLIssuer         [2] GeneralNames OPTIONAL
+ * }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DistributionPoint
+    extends ASN1Object
+{
+    DistributionPointName       distributionPoint;
+    ReasonFlags                 reasons;
+    GeneralNames                cRLIssuer;
+
+    public static DistributionPoint getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static DistributionPoint getInstance(
+        Object obj)
+    {
+        if(obj == null || obj instanceof DistributionPoint) 
+        {
+            return (DistributionPoint)obj;
+        }
+        
+        if(obj instanceof ASN1Sequence) 
+        {
+            return new DistributionPoint((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid DistributionPoint: " + obj.getClass().getName());
+    }
+
+    public DistributionPoint(
+        ASN1Sequence seq)
+    {
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject    t = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+            switch (t.getTagNo())
+            {
+            case 0:
+                distributionPoint = DistributionPointName.getInstance(t, true);
+                break;
+            case 1:
+                reasons = new ReasonFlags(DERBitString.getInstance(t, false));
+                break;
+            case 2:
+                cRLIssuer = GeneralNames.getInstance(t, false);
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown tag encountered in structure: " + t.getTagNo());
+            }
+        }
+    }
+    
+    public DistributionPoint(
+        DistributionPointName distributionPoint,
+        ReasonFlags                 reasons,
+        GeneralNames            cRLIssuer)
+    {
+        this.distributionPoint = distributionPoint;
+        this.reasons = reasons;
+        this.cRLIssuer = cRLIssuer;
+    }
+    
+    public DistributionPointName getDistributionPoint()
+    {
+        return distributionPoint;
+    }
+
+    public ReasonFlags getReasons()
+    {
+        return reasons;
+    }
+    
+    public GeneralNames getCRLIssuer()
+    {
+        return cRLIssuer;
+    }
+    
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+        
+        if (distributionPoint != null)
+        {
+            //
+            // as this is a CHOICE it must be explicitly tagged
+            //
+            v.add(new DERTaggedObject(0, distributionPoint));
+        }
+
+        if (reasons != null)
+        {
+            v.add(new DERTaggedObject(false, 1, reasons));
+        }
+
+        if (cRLIssuer != null)
+        {
+            v.add(new DERTaggedObject(false, 2, cRLIssuer));
+        }
+
+        return new DERSequence(v);
+    }
+
+    public String toString()
+    {
+        String       sep = Strings.lineSeparator();
+        StringBuffer buf = new StringBuffer();
+        buf.append("DistributionPoint: [");
+        buf.append(sep);
+        if (distributionPoint != null)
+        {
+            appendObject(buf, sep, "distributionPoint", distributionPoint.toString());
+        }
+        if (reasons != null)
+        {
+            appendObject(buf, sep, "reasons", reasons.toString());
+        }
+        if (cRLIssuer != null)
+        {
+            appendObject(buf, sep, "cRLIssuer", cRLIssuer.toString());
+        }
+        buf.append("]");
+        buf.append(sep);
+        return buf.toString();
+    }
+
+    private void appendObject(StringBuffer buf, String sep, String name, String value)
+    {
+        String       indent = "    ";
+
+        buf.append(indent);
+        buf.append(name);
+        buf.append(":");
+        buf.append(sep);
+        buf.append(indent);
+        buf.append(indent);
+        buf.append(value);
+        buf.append(sep);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DistributionPointName.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DistributionPointName.java
new file mode 100644
index 0000000..36154fe
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/DistributionPointName.java
@@ -0,0 +1,141 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Choice;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * The DistributionPointName object.
+ * <pre>
+ * DistributionPointName ::= CHOICE {
+ *     fullName                 [0] GeneralNames,
+ *     nameRelativeToCRLIssuer  [1] RDN
+ * }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DistributionPointName
+    extends ASN1Object
+    implements ASN1Choice
+{
+    ASN1Encodable        name;
+    int                 type;
+
+    public static final int FULL_NAME = 0;
+    public static final int NAME_RELATIVE_TO_CRL_ISSUER = 1;
+
+    public static DistributionPointName getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1TaggedObject.getInstance(obj, true));
+    }
+
+    public static DistributionPointName getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DistributionPointName)
+        {
+            return (DistributionPointName)obj;
+        }
+        else if (obj instanceof ASN1TaggedObject)
+        {
+            return new DistributionPointName((ASN1TaggedObject)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+    }
+
+    public DistributionPointName(
+        int             type,
+        ASN1Encodable   name)
+    {
+        this.type = type;
+        this.name = name;
+    }
+
+    public DistributionPointName(
+        GeneralNames name)
+    {
+        this(FULL_NAME, name);
+    }
+
+    /**
+     * Return the tag number applying to the underlying choice.
+     * 
+     * @return the tag number for this point name.
+     */
+    public int getType()
+    {
+        return this.type;
+    }
+    
+    /**
+     * Return the tagged object inside the distribution point name.
+     * 
+     * @return the underlying choice item.
+     */
+    public ASN1Encodable getName()
+    {
+        return (ASN1Encodable)name;
+    }
+    
+    public DistributionPointName(
+        ASN1TaggedObject    obj)
+    {
+        this.type = obj.getTagNo();
+        
+        if (type == 0)
+        {
+            this.name = GeneralNames.getInstance(obj, false);
+        }
+        else
+        {
+            this.name = ASN1Set.getInstance(obj, false);
+        }
+    }
+    
+    public ASN1Primitive toASN1Primitive()
+    {
+        return new DERTaggedObject(false, type, name);
+    }
+
+    public String toString()
+    {
+        String       sep = Strings.lineSeparator();
+        StringBuffer buf = new StringBuffer();
+        buf.append("DistributionPointName: [");
+        buf.append(sep);
+        if (type == FULL_NAME)
+        {
+            appendObject(buf, sep, "fullName", name.toString());
+        }
+        else
+        {
+            appendObject(buf, sep, "nameRelativeToCRLIssuer", name.toString());
+        }
+        buf.append("]");
+        buf.append(sep);
+        return buf.toString();
+    }
+
+    private void appendObject(StringBuffer buf, String sep, String name, String value)
+    {
+        String       indent = "    ";
+
+        buf.append(indent);
+        buf.append(name);
+        buf.append(":");
+        buf.append(sep);
+        buf.append(indent);
+        buf.append(indent);
+        buf.append(value);
+        buf.append(sep);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
new file mode 100644
index 0000000..de1190b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
@@ -0,0 +1,194 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The extendedKeyUsage object.
+ * <pre>
+ *      extendedKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ExtendedKeyUsage
+    extends ASN1Object
+{
+    Hashtable     usageTable = new Hashtable();
+    ASN1Sequence  seq;
+
+    /**
+     * Return an ExtendedKeyUsage from the passed in tagged object.
+     *
+     * @param obj the tagged object containing the ExtendedKeyUsage
+     * @param explicit true if the tagged object should be interpreted as explicitly tagged, false if implicit.
+     * @return the ExtendedKeyUsage contained.
+     */
+    public static ExtendedKeyUsage getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    /**
+     * Return an ExtendedKeyUsage from the passed in object.
+     *
+     * @param obj an ExtendedKeyUsage, some form or encoding of one, or null.
+     * @return  an ExtendedKeyUsage object, or null if null is passed in.
+     */
+    public static ExtendedKeyUsage getInstance(
+        Object obj)
+    {
+        if (obj instanceof ExtendedKeyUsage) 
+        {
+            return (ExtendedKeyUsage)obj;
+        }
+        else if (obj != null)
+        {
+            return new ExtendedKeyUsage(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * Retrieve an ExtendedKeyUsage for a passed in Extensions object, if present.
+     *
+     * @param extensions the extensions object to be examined.
+     * @return  the ExtendedKeyUsage, null if the extension is not present.
+     */
+    public static ExtendedKeyUsage fromExtensions(Extensions extensions)
+    {
+        return ExtendedKeyUsage.getInstance(extensions.getExtensionParsedValue(Extension.extendedKeyUsage));
+    }
+
+    /**
+     * Base constructor, from a single KeyPurposeId.
+     *
+     * @param usage the keyPurposeId to be included.
+     */
+    public ExtendedKeyUsage(
+        KeyPurposeId  usage)
+    {
+        this.seq = new DERSequence(usage);
+
+        this.usageTable.put(usage, usage);
+    }
+    
+    private ExtendedKeyUsage(
+        ASN1Sequence  seq)
+    {
+        this.seq = seq;
+
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1Encodable o = (ASN1Encodable)e.nextElement();
+            if (!(o.toASN1Primitive() instanceof ASN1ObjectIdentifier))
+            {
+                throw new IllegalArgumentException("Only ASN1ObjectIdentifiers allowed in ExtendedKeyUsage.");
+            }
+            this.usageTable.put(o, o);
+        }
+    }
+
+    /**
+     * Base constructor, from multiple KeyPurposeIds.
+     *
+     * @param usages an array of KeyPurposeIds.
+     */
+    public ExtendedKeyUsage(
+        KeyPurposeId[]  usages)
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        for (int i = 0; i != usages.length; i++)
+        {
+            v.add(usages[i]);
+            this.usageTable.put(usages[i], usages[i]);
+        }
+
+        this.seq = new DERSequence(v);
+    }
+
+    /**
+     * @deprecated use KeyPurposeId[] constructor.
+     */
+    public ExtendedKeyUsage(
+        Vector usages)
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        Enumeration         e = usages.elements();
+
+        while (e.hasMoreElements())
+        {
+            KeyPurposeId  o = KeyPurposeId.getInstance(e.nextElement());
+
+            v.add(o);
+            this.usageTable.put(o, o);
+        }
+
+        this.seq = new DERSequence(v);
+    }
+
+    /**
+     * Return true if this ExtendedKeyUsage object contains the passed in keyPurposeId.
+     *
+     * @param keyPurposeId  the KeyPurposeId of interest.
+     * @return true if the keyPurposeId is present, false otherwise.
+     */
+    public boolean hasKeyPurposeId(
+        KeyPurposeId keyPurposeId)
+    {
+        return (usageTable.get(keyPurposeId) != null);
+    }
+    
+    /**
+     * Returns all extended key usages.
+     *
+     * @return An array with all key purposes.
+     */
+    public KeyPurposeId[] getUsages()
+    {
+        KeyPurposeId[] temp = new KeyPurposeId[seq.size()];
+
+        int i = 0;
+        for (Enumeration it = seq.getObjects(); it.hasMoreElements();)
+        {
+            temp[i++] = KeyPurposeId.getInstance(it.nextElement());
+        }
+        return temp;
+    }
+
+    /**
+     * Return the number of KeyPurposeIds present in this ExtendedKeyUsage.
+     *
+     * @return the number of KeyPurposeIds
+     */
+    public int size()
+    {
+        return usageTable.size();
+    }
+
+    /**
+     * Return the ASN.1 primitive form of this object.
+     *
+     * @return an ASN1Sequence.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Extension.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Extension.java
new file mode 100644
index 0000000..fdb23a6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Extension.java
@@ -0,0 +1,328 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Boolean;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * an object for the elements in the X.509 V3 extension block.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Extension
+    extends ASN1Object
+{
+    /**
+     * Subject Directory Attributes
+     */
+    public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9").intern();
+    
+    /**
+     * Subject Key Identifier 
+     */
+    public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14").intern();
+
+    /**
+     * Key Usage 
+     */
+    public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier("2.5.29.15").intern();
+
+    /**
+     * Private Key Usage Period 
+     */
+    public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16").intern();
+
+    /**
+     * Subject Alternative Name 
+     */
+    public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17").intern();
+
+    /**
+     * Issuer Alternative Name 
+     */
+    public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18").intern();
+
+    /**
+     * Basic Constraints 
+     */
+    public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19").intern();
+
+    /**
+     * CRL Number 
+     */
+    public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier("2.5.29.20").intern();
+
+    /**
+     * Reason code 
+     */
+    public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier("2.5.29.21").intern();
+
+    /**
+     * Hold Instruction Code 
+     */
+    public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier("2.5.29.23").intern();
+
+    /**
+     * Invalidity Date 
+     */
+    public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier("2.5.29.24").intern();
+
+    /**
+     * Delta CRL indicator 
+     */
+    public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27").intern();
+
+    /**
+     * Issuing Distribution Point 
+     */
+    public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28").intern();
+
+    /**
+     * Certificate Issuer 
+     */
+    public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier("2.5.29.29").intern();
+
+    /**
+     * Name Constraints 
+     */
+    public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier("2.5.29.30").intern();
+
+    /**
+     * CRL Distribution Points 
+     */
+    public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31").intern();
+
+    /**
+     * Certificate Policies 
+     */
+    public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier("2.5.29.32").intern();
+
+    /**
+     * Policy Mappings 
+     */
+    public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier("2.5.29.33").intern();
+
+    /**
+     * Authority Key Identifier 
+     */
+    public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35").intern();
+
+    /**
+     * Policy Constraints 
+     */
+    public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier("2.5.29.36").intern();
+
+    /**
+     * Extended Key Usage 
+     */
+    public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37").intern();
+
+    /**
+     * Freshest CRL
+     */
+    public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier("2.5.29.46").intern();
+     
+    /**
+     * Inhibit Any Policy
+     */
+    public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54").intern();
+
+    /**
+     * Authority Info Access
+     */
+    public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1").intern();
+
+    /**
+     * Subject Info Access
+     */
+    public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11").intern();
+    
+    /**
+     * Logo Type
+     */
+    public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12").intern();
+
+    /**
+     * BiometricInfo
+     */
+    public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2").intern();
+    
+    /**
+     * QCStatements
+     */
+    public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3").intern();
+
+    /**
+     * Audit identity extension in attribute certificates.
+     */
+    public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4").intern();
+    
+    /**
+     * NoRevAvail extension in attribute certificates.
+     */
+    public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier("2.5.29.56").intern();
+
+    /**
+     * TargetInformation extension in attribute certificates.
+     */
+    public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55").intern();
+
+    /**
+     * Expired Certificates on CRL extension
+     */
+    public static final ASN1ObjectIdentifier expiredCertsOnCRL = new ASN1ObjectIdentifier("2.5.29.60").intern();
+
+    private ASN1ObjectIdentifier extnId;
+    private boolean             critical;
+    private ASN1OctetString      value;
+
+    public Extension(
+        ASN1ObjectIdentifier extnId,
+        ASN1Boolean critical,
+        ASN1OctetString value)
+    {
+        this(extnId, critical.isTrue(), value);
+    }
+
+    public Extension(
+        ASN1ObjectIdentifier extnId,
+        boolean critical,
+        byte[] value)
+    {
+        this(extnId, critical, new DEROctetString(value));
+    }
+
+    public Extension(
+        ASN1ObjectIdentifier extnId,
+        boolean critical,
+        ASN1OctetString value)
+    {
+        this.extnId = extnId;
+        this.critical = critical;
+        this.value = value;
+    }
+
+    private Extension(ASN1Sequence seq)
+    {
+        if (seq.size() == 2)
+        {
+            this.extnId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+            this.critical = false;
+            this.value = ASN1OctetString.getInstance(seq.getObjectAt(1));
+        }
+        else if (seq.size() == 3)
+        {
+            this.extnId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+            this.critical = ASN1Boolean.getInstance(seq.getObjectAt(1)).isTrue();
+            this.value = ASN1OctetString.getInstance(seq.getObjectAt(2));
+        }
+        else
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+    }
+
+    public static Extension getInstance(Object obj)
+    {
+        if (obj instanceof Extension)
+        {
+            return (Extension)obj;
+        }
+        else if (obj != null)
+        {
+            return new Extension(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public ASN1ObjectIdentifier getExtnId()
+    {
+        return extnId;
+    }
+
+    public boolean isCritical()
+    {
+        return critical;
+    }
+
+    public ASN1OctetString getExtnValue()
+    {
+        return value;
+    }
+
+    public ASN1Encodable getParsedValue()
+    {
+        return convertValueToObject(this);
+    }
+
+    public int hashCode()
+    {
+        if (this.isCritical())
+        {
+            return this.getExtnValue().hashCode() ^ this.getExtnId().hashCode();
+        }
+
+        return ~(this.getExtnValue().hashCode() ^ this.getExtnId().hashCode());
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof Extension))
+        {
+            return false;
+        }
+
+        Extension other = (Extension)o;
+
+        return other.getExtnId().equals(this.getExtnId())
+            && other.getExtnValue().equals(this.getExtnValue())
+            && (other.isCritical() == this.isCritical());
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(extnId);
+
+        if (critical)
+        {
+            v.add(ASN1Boolean.getInstance(true));
+        }
+
+        v.add(value);
+
+        return new DERSequence(v);
+    }
+
+    /**
+     * Convert the value of the passed in extension to an object
+     * @param ext the extension to parse
+     * @return the object the value string contains
+     * @exception IllegalArgumentException if conversion is not possible
+     */
+    private static ASN1Primitive convertValueToObject(
+        Extension ext)
+        throws IllegalArgumentException
+    {
+        try
+        {
+            return ASN1Primitive.fromByteArray(ext.getExtnValue().getOctets());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't convert extension: " +  e);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Extensions.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Extensions.java
new file mode 100644
index 0000000..a290894
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Extensions.java
@@ -0,0 +1,231 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Extensions
+    extends ASN1Object
+{
+    private Hashtable extensions = new Hashtable();
+    private Vector ordering = new Vector();
+
+    public static Extensions getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static Extensions getInstance(
+        Object obj)
+    {
+        if (obj instanceof Extensions)
+        {
+            return (Extensions)obj;
+        }
+        else if (obj != null)
+        {
+            return new Extensions(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * Constructor from ASN1Sequence.
+     * <p>
+     * The extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)
+     * </p>
+     */
+    private Extensions(
+        ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            Extension ext = Extension.getInstance(e.nextElement());
+
+            if (extensions.containsKey(ext.getExtnId()))
+            {
+                throw new IllegalArgumentException("repeated extension found: " + ext.getExtnId());
+            }
+            
+            extensions.put(ext.getExtnId(), ext);
+            ordering.addElement(ext.getExtnId());
+        }
+    }
+
+    /**
+     * Base Constructor
+     *
+     * @param extension a single extension.
+     */
+    public Extensions(
+        Extension extension)
+    {
+        this.ordering.addElement(extension.getExtnId());
+        this.extensions.put(extension.getExtnId(), extension);
+    }
+
+    /**
+     * Base Constructor
+     *
+     * @param extensions an array of extensions.
+     */
+    public Extensions(
+        Extension[] extensions)
+    {
+        for (int i = 0; i != extensions.length; i++)
+        {
+            Extension ext = extensions[i];
+
+            this.ordering.addElement(ext.getExtnId());
+            this.extensions.put(ext.getExtnId(), ext);
+        }
+    }
+
+    /**
+     * return an Enumeration of the extension field's object ids.
+     */
+    public Enumeration oids()
+    {
+        return ordering.elements();
+    }
+
+    /**
+     * return the extension represented by the object identifier
+     * passed in.
+     *
+     * @return the extension if it's present, null otherwise.
+     */
+    public Extension getExtension(
+        ASN1ObjectIdentifier oid)
+    {
+        return (Extension)extensions.get(oid);
+    }
+
+    /**
+     * return the parsed value of the extension represented by the object identifier
+     * passed in.
+     *
+     * @return the parsed value of the extension if it's present, null otherwise.
+     */
+    public ASN1Encodable getExtensionParsedValue(ASN1ObjectIdentifier oid)
+    {
+        Extension ext = this.getExtension(oid);
+
+        if (ext != null)
+        {
+            return ext.getParsedValue();
+        }
+
+        return null;
+    }
+
+    /**
+     * <pre>
+     *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
+     *
+     *     Extension         ::=   SEQUENCE {
+     *        extnId            EXTENSION.&amp;id ({ExtensionSet}),
+     *        critical          BOOLEAN DEFAULT FALSE,
+     *        extnValue         OCTET STRING }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector vec = new ASN1EncodableVector();
+        Enumeration e = ordering.elements();
+
+        while (e.hasMoreElements())
+        {
+            ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+            Extension ext = (Extension)extensions.get(oid);
+
+            vec.add(ext);
+        }
+
+        return new DERSequence(vec);
+    }
+
+    public boolean equivalent(
+        Extensions other)
+    {
+        if (extensions.size() != other.extensions.size())
+        {
+            return false;
+        }
+
+        Enumeration e1 = extensions.keys();
+
+        while (e1.hasMoreElements())
+        {
+            Object key = e1.nextElement();
+
+            if (!extensions.get(key).equals(other.extensions.get(key)))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public ASN1ObjectIdentifier[] getExtensionOIDs()
+    {
+        return toOidArray(ordering);
+    }
+
+    public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(false);
+    }
+
+    public ASN1ObjectIdentifier[] getCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(true);
+    }
+
+    private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical)
+    {
+        Vector oidVec = new Vector();
+
+        for (int i = 0; i != ordering.size(); i++)
+        {
+            Object oid = ordering.elementAt(i);
+
+            if (((Extension)extensions.get(oid)).isCritical() == isCritical)
+            {
+                oidVec.addElement(oid);
+            }
+        }
+
+        return toOidArray(oidVec);
+    }
+
+    private ASN1ObjectIdentifier[] toOidArray(Vector oidVec)
+    {
+        ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()];
+
+        for (int i = 0; i != oids.length; i++)
+        {
+            oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i);
+        }
+        return oids;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ExtensionsGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ExtensionsGenerator.java
new file mode 100644
index 0000000..0cab859
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ExtensionsGenerator.java
@@ -0,0 +1,113 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+
+/**
+ * Generator for X.509 extensions
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ExtensionsGenerator
+{
+    private Hashtable extensions = new Hashtable();
+    private Vector extOrdering = new Vector();
+
+    /**
+     * Reset the generator
+     */
+    public void reset()
+    {
+        extensions = new Hashtable();
+        extOrdering = new Vector();
+    }
+
+    /**
+     * Add an extension with the given oid and the passed in value to be included
+     * in the OCTET STRING associated with the extension.
+     *
+     * @param oid  OID for the extension.
+     * @param critical  true if critical, false otherwise.
+     * @param value the ASN.1 object to be included in the extension.
+     */
+    public void addExtension(
+        ASN1ObjectIdentifier oid,
+        boolean              critical,
+        ASN1Encodable        value)
+        throws IOException
+    {
+        this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+    }
+
+    /**
+     * Add an extension with the given oid and the passed in byte array to be wrapped in the
+     * OCTET STRING associated with the extension.
+     *
+     * @param oid OID for the extension.
+     * @param critical true if critical, false otherwise.
+     * @param value the byte array to be wrapped.
+     */
+    public void addExtension(
+        ASN1ObjectIdentifier oid,
+        boolean             critical,
+        byte[]              value)
+    {
+        if (extensions.containsKey(oid))
+        {
+            throw new IllegalArgumentException("extension " + oid + " already added");
+        }
+
+        extOrdering.addElement(oid);
+        extensions.put(oid, new Extension(oid, critical, new DEROctetString(value)));
+    }
+
+    /**
+     * Add a given extension.
+     *
+     * @param extension the full extension value.
+     */
+    public void addExtension(
+        Extension extension)
+    {
+        if (extensions.containsKey(extension.getExtnId()))
+        {
+            throw new IllegalArgumentException("extension " + extension.getExtnId() + " already added");
+        }
+
+        extOrdering.addElement(extension.getExtnId());
+        extensions.put(extension.getExtnId(), extension);
+    }
+
+    /**
+     * Return true if there are no extension present in this generator.
+     *
+     * @return true if empty, false otherwise
+     */
+    public boolean isEmpty()
+    {
+        return extOrdering.isEmpty();
+    }
+
+    /**
+     * Generate an Extensions object based on the current state of the generator.
+     *
+     * @return  an X09Extensions object.
+     */
+    public Extensions generate()
+    {
+        Extension[] exts = new Extension[extOrdering.size()];
+
+        for (int i = 0; i != extOrdering.size(); i++)
+        {
+            exts[i] = (Extension)extensions.get(extOrdering.elementAt(i));
+        }
+
+        return new Extensions(exts);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/GeneralName.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/GeneralName.java
new file mode 100644
index 0000000..0a2f941
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/GeneralName.java
@@ -0,0 +1,441 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Choice;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.util.IPAddress;
+
+/**
+ * The GeneralName object.
+ * <pre>
+ * GeneralName ::= CHOICE {
+ *      otherName                       [0]     OtherName,
+ *      rfc822Name                      [1]     IA5String,
+ *      dNSName                         [2]     IA5String,
+ *      x400Address                     [3]     ORAddress,
+ *      directoryName                   [4]     Name,
+ *      ediPartyName                    [5]     EDIPartyName,
+ *      uniformResourceIdentifier       [6]     IA5String,
+ *      iPAddress                       [7]     OCTET STRING,
+ *      registeredID                    [8]     OBJECT IDENTIFIER}
+ *
+ * OtherName ::= SEQUENCE {
+ *      type-id    OBJECT IDENTIFIER,
+ *      value      [0] EXPLICIT ANY DEFINED BY type-id }
+ *
+ * EDIPartyName ::= SEQUENCE {
+ *      nameAssigner            [0]     DirectoryString OPTIONAL,
+ *      partyName               [1]     DirectoryString }
+ * 
+ * Name ::= CHOICE { RDNSequence }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class GeneralName
+    extends ASN1Object
+    implements ASN1Choice
+{
+    public static final int otherName                     = 0;
+    public static final int rfc822Name                    = 1;
+    public static final int dNSName                       = 2;
+    public static final int x400Address                   = 3;
+    public static final int directoryName                 = 4;
+    public static final int ediPartyName                  = 5;
+    public static final int uniformResourceIdentifier     = 6;
+    public static final int iPAddress                     = 7;
+    public static final int registeredID                  = 8;
+
+    private ASN1Encodable obj;
+    private int           tag;
+
+    /**
+     * @deprecated use X500Name constructor.
+     * @param dirName
+     */
+        public GeneralName(
+        X509Name  dirName)
+    {
+        this.obj = X500Name.getInstance(dirName);
+        this.tag = 4;
+    }
+
+    public GeneralName(
+        X500Name  dirName)
+    {
+        this.obj = dirName;
+        this.tag = 4;
+    }
+
+    /**
+     * When the subjectAltName extension contains an Internet mail address,
+     * the address MUST be included as an rfc822Name. The format of an
+     * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822].
+     *
+     * When the subjectAltName extension contains a domain name service
+     * label, the domain name MUST be stored in the dNSName (an IA5String).
+     * The name MUST be in the "preferred name syntax," as specified by RFC
+     * 1034 [RFC 1034].
+     *
+     * When the subjectAltName extension contains a URI, the name MUST be
+     * stored in the uniformResourceIdentifier (an IA5String). The name MUST
+     * be a non-relative URL, and MUST follow the URL syntax and encoding
+     * rules specified in [RFC 1738].  The name must include both a scheme
+     * (e.g., "http" or "ftp") and a scheme-specific-part.  The scheme-
+     * specific-part must include a fully qualified domain name or IP
+     * address as the host.
+     *
+     * When the subjectAltName extension contains a iPAddress, the address
+     * MUST be stored in the octet string in "network byte order," as
+     * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of
+     * each octet is the LSB of the corresponding byte in the network
+     * address. For IP Version 4, as specified in RFC 791, the octet string
+     * MUST contain exactly four octets.  For IP Version 6, as specified in
+     * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC
+     * 1883].
+     */
+    public GeneralName(
+        int           tag,
+        ASN1Encodable name)
+    {
+        this.obj = name;
+        this.tag = tag;
+    }
+    
+    /**
+     * Create a GeneralName for the given tag from the passed in String.
+     * <p>
+     * This constructor can handle:
+     * <ul>
+     * <li>rfc822Name
+     * <li>iPAddress
+     * <li>directoryName
+     * <li>dNSName
+     * <li>uniformResourceIdentifier
+     * <li>registeredID
+     * </ul>
+     * For x400Address, otherName and ediPartyName there is no common string
+     * format defined.
+     * <p>
+     * Note: A directory name can be encoded in different ways into a byte
+     * representation. Be aware of this if the byte representation is used for
+     * comparing results.
+     *
+     * @param tag tag number
+     * @param name string representation of name
+     * @throws IllegalArgumentException if the string encoding is not correct or     *             not supported.
+     */
+    public GeneralName(
+        int       tag,
+        String    name)
+    {
+        this.tag = tag;
+
+        if (tag == rfc822Name || tag == dNSName || tag == uniformResourceIdentifier)
+        {
+            this.obj = new DERIA5String(name);
+        }
+        else if (tag == registeredID)
+        {
+            this.obj = new ASN1ObjectIdentifier(name);
+        }
+        else if (tag == directoryName)
+        {
+            this.obj = new X500Name(name);
+        }
+        else if (tag == iPAddress)
+        {
+            byte[] enc = toGeneralNameEncoding(name);
+            if (enc != null)
+            {
+                this.obj = new DEROctetString(enc);
+            }
+            else
+            {
+                throw new IllegalArgumentException("IP Address is invalid");
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException("can't process String for tag: " + tag);
+        }
+    }
+    
+    public static GeneralName getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof GeneralName)
+        {
+            return (GeneralName)obj;
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            ASN1TaggedObject    tagObj = (ASN1TaggedObject)obj;
+            int                 tag = tagObj.getTagNo();
+
+            switch (tag)
+            {
+            case otherName:
+                return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false));
+            case rfc822Name:
+                return new GeneralName(tag, DERIA5String.getInstance(tagObj, false));
+            case dNSName:
+                return new GeneralName(tag, DERIA5String.getInstance(tagObj, false));
+            case x400Address:
+                throw new IllegalArgumentException("unknown tag: " + tag);
+            case directoryName:
+                return new GeneralName(tag, X500Name.getInstance(tagObj, true));
+            case ediPartyName:
+                return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false));
+            case uniformResourceIdentifier:
+                return new GeneralName(tag, DERIA5String.getInstance(tagObj, false));
+            case iPAddress:
+                return new GeneralName(tag, ASN1OctetString.getInstance(tagObj, false));
+            case registeredID:
+                return new GeneralName(tag, ASN1ObjectIdentifier.getInstance(tagObj, false));
+            }
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return getInstance(ASN1Primitive.fromByteArray((byte[])obj));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("unable to parse encoded general name");
+            }
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+    }
+
+    public static GeneralName getInstance(
+        ASN1TaggedObject tagObj,
+        boolean          explicit)
+    {
+        return GeneralName.getInstance(ASN1TaggedObject.getInstance(tagObj, true));
+    }
+
+    public int getTagNo()
+    {
+        return tag;
+    }
+
+    public ASN1Encodable getName()
+    {
+        return obj;
+    }
+
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+
+        buf.append(tag);
+        buf.append(": ");
+        switch (tag)
+        {
+        case rfc822Name:
+        case dNSName:
+        case uniformResourceIdentifier:
+            buf.append(DERIA5String.getInstance(obj).getString());
+            break;
+        case directoryName:
+            buf.append(X500Name.getInstance(obj).toString());
+            break;
+        default:
+            buf.append(obj.toString());
+        }
+        return buf.toString();
+    }
+
+    private byte[] toGeneralNameEncoding(String ip)
+    {
+        if (IPAddress.isValidIPv6WithNetmask(ip) || IPAddress.isValidIPv6(ip))
+        {
+            int    slashIndex = ip.indexOf('/');
+
+            if (slashIndex < 0)
+            {
+                byte[] addr = new byte[16];
+                int[]  parsedIp = parseIPv6(ip);
+                copyInts(parsedIp, addr, 0);
+
+                return addr;
+            }
+            else
+            {
+                byte[] addr = new byte[32];
+                int[]  parsedIp = parseIPv6(ip.substring(0, slashIndex));
+                copyInts(parsedIp, addr, 0);
+                String mask = ip.substring(slashIndex + 1);
+                if (mask.indexOf(':') > 0)
+                {
+                    parsedIp = parseIPv6(mask);
+                }
+                else
+                {
+                    parsedIp = parseMask(mask);
+                }
+                copyInts(parsedIp, addr, 16);
+
+                return addr;
+            }
+        }
+        else if (IPAddress.isValidIPv4WithNetmask(ip) || IPAddress.isValidIPv4(ip))
+        {
+            int    slashIndex = ip.indexOf('/');
+
+            if (slashIndex < 0)
+            {
+                byte[] addr = new byte[4];
+
+                parseIPv4(ip, addr, 0);
+
+                return addr;
+            }
+            else
+            {
+                byte[] addr = new byte[8];
+
+                parseIPv4(ip.substring(0, slashIndex), addr, 0);
+
+                String mask = ip.substring(slashIndex + 1);
+                if (mask.indexOf('.') > 0)
+                {
+                    parseIPv4(mask, addr, 4);
+                }
+                else
+                {
+                    parseIPv4Mask(mask, addr, 4);
+                }
+
+                return addr;
+            }
+        }
+
+        return null;
+    }
+
+    private void parseIPv4Mask(String mask, byte[] addr, int offset)
+    {
+        int   maskVal = Integer.parseInt(mask);
+
+        for (int i = 0; i != maskVal; i++)
+        {
+            addr[(i / 8) + offset] |= 1 << (7 - (i % 8));
+        }
+    }
+
+    private void parseIPv4(String ip, byte[] addr, int offset)
+    {
+        StringTokenizer sTok = new StringTokenizer(ip, "./");
+        int    index = 0;
+
+        while (sTok.hasMoreTokens())
+        {
+            addr[offset + index++] = (byte)Integer.parseInt(sTok.nextToken());
+        }
+    }
+
+    private int[] parseMask(String mask)
+    {
+        int[] res = new int[8];
+        int   maskVal = Integer.parseInt(mask);
+
+        for (int i = 0; i != maskVal; i++)
+        {
+            res[i / 16] |= 1 << (15 - (i % 16));
+        }
+        return res;
+    }
+
+    private void copyInts(int[] parsedIp, byte[] addr, int offSet)
+    {
+        for (int i = 0; i != parsedIp.length; i++)
+        {
+            addr[(i * 2) + offSet] = (byte)(parsedIp[i] >> 8);
+            addr[(i * 2 + 1) + offSet] = (byte)parsedIp[i];
+        }
+    }
+
+    private int[] parseIPv6(String ip)
+    {
+        StringTokenizer sTok = new StringTokenizer(ip, ":", true);
+        int index = 0;
+        int[] val = new int[8];
+
+        if (ip.charAt(0) == ':' && ip.charAt(1) == ':')
+        {
+           sTok.nextToken(); // skip the first one
+        }
+
+        int doubleColon = -1;
+
+        while (sTok.hasMoreTokens())
+        {
+            String e = sTok.nextToken();
+
+            if (e.equals(":"))
+            {
+                doubleColon = index;
+                val[index++] = 0;
+            }
+            else
+            {
+                if (e.indexOf('.') < 0)
+                {
+                    val[index++] = Integer.parseInt(e, 16);
+                    if (sTok.hasMoreTokens())
+                    {
+                        sTok.nextToken();
+                    }
+                }
+                else
+                {
+                    StringTokenizer eTok = new StringTokenizer(e, ".");
+
+                    val[index++] = (Integer.parseInt(eTok.nextToken()) << 8) | Integer.parseInt(eTok.nextToken());
+                    val[index++] = (Integer.parseInt(eTok.nextToken()) << 8) | Integer.parseInt(eTok.nextToken());
+                }
+            }
+        }
+
+        if (index != val.length)
+        {
+            System.arraycopy(val, doubleColon, val, val.length - (index - doubleColon), index - doubleColon);
+            for (int i = doubleColon; i != val.length - (index - doubleColon); i++)
+            {
+                val[i] = 0;
+            }
+        }
+
+        return val;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        if (tag == directoryName)       // directoryName is explicitly tagged as it is a CHOICE
+        {
+            return new DERTaggedObject(true, tag, obj);
+        }
+        else
+        {
+            return new DERTaggedObject(false, tag, obj);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/GeneralNames.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/GeneralNames.java
new file mode 100644
index 0000000..c32fc0e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/GeneralNames.java
@@ -0,0 +1,118 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class GeneralNames
+    extends ASN1Object
+{
+    private final GeneralName[] names;
+
+    public static GeneralNames getInstance(
+        Object  obj)
+    {
+        if (obj instanceof GeneralNames)
+        {
+            return (GeneralNames)obj;
+        }
+
+        if (obj != null)
+        {
+            return new GeneralNames(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static GeneralNames getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static GeneralNames fromExtensions(Extensions extensions, ASN1ObjectIdentifier extOID)
+    {
+        return GeneralNames.getInstance(extensions.getExtensionParsedValue(extOID));
+    }
+
+    /**
+     * Construct a GeneralNames object containing one GeneralName.
+     * 
+     * @param name the name to be contained.
+     */
+    public GeneralNames(
+        GeneralName  name)
+    {
+        this.names = new GeneralName[] { name };
+    }
+
+
+    public GeneralNames(
+        GeneralName[]  names)
+    {
+        this.names = copy(names);
+    }
+
+    private GeneralNames(
+        ASN1Sequence  seq)
+    {
+        this.names = new GeneralName[seq.size()];
+
+        for (int i = 0; i != seq.size(); i++)
+        {
+            names[i] = GeneralName.getInstance(seq.getObjectAt(i));
+        }
+    }
+
+    public GeneralName[] getNames()
+    {
+        return copy(names);
+    }
+
+    private GeneralName[] copy(GeneralName[] nms)
+    {
+        GeneralName[] tmp = new GeneralName[nms.length];
+
+        System.arraycopy(nms, 0, tmp, 0, tmp.length);
+
+        return tmp;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * GeneralNames ::= SEQUENCE SIZE {1..MAX} OF GeneralName
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return new DERSequence(names);
+    }
+
+    public String toString()
+    {
+        StringBuffer  buf = new StringBuffer();
+        String        sep = Strings.lineSeparator();
+
+        buf.append("GeneralNames:");
+        buf.append(sep);
+
+        for (int i = 0; i != names.length; i++)
+        {
+            buf.append("    ");
+            buf.append(names[i]);
+            buf.append(sep);
+        }
+        return buf.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/GeneralSubtree.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/GeneralSubtree.java
new file mode 100644
index 0000000..ac4e070
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/GeneralSubtree.java
@@ -0,0 +1,220 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * Class for containing a restriction object subtrees in NameConstraints. See
+ * RFC 3280.
+ * 
+ * <pre>
+ *       
+ *       GeneralSubtree ::= SEQUENCE 
+ *       {
+ *         base                    GeneralName,
+ *         minimum         [0]     BaseDistance DEFAULT 0,
+ *         maximum         [1]     BaseDistance OPTIONAL 
+ *       }
+ * </pre>
+ * 
+ * @see com.android.internal.org.bouncycastle.asn1.x509.NameConstraints
+ * @hide This class is not part of the Android public SDK API
+ * 
+ */
+public class GeneralSubtree 
+    extends ASN1Object
+{
+    private static final BigInteger ZERO = BigInteger.valueOf(0);
+
+    private GeneralName base;
+
+    private ASN1Integer minimum;
+
+    private ASN1Integer maximum;
+
+    private GeneralSubtree(
+        ASN1Sequence seq) 
+    {
+        base = GeneralName.getInstance(seq.getObjectAt(0));
+
+        switch (seq.size()) 
+        {
+        case 1:
+            break;
+        case 2:
+            ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(1));
+            switch (o.getTagNo()) 
+            {
+            case 0:
+                minimum = ASN1Integer.getInstance(o, false);
+                break;
+            case 1:
+                maximum = ASN1Integer.getInstance(o, false);
+                break;
+            default:
+                throw new IllegalArgumentException("Bad tag number: "
+                        + o.getTagNo());
+            }
+            break;
+        case 3:
+        {
+            {
+                ASN1TaggedObject oMin = ASN1TaggedObject.getInstance(seq.getObjectAt(1));
+                if (oMin.getTagNo() != 0)
+                {
+                    throw new IllegalArgumentException("Bad tag number for 'minimum': " + oMin.getTagNo());
+                }
+                minimum = ASN1Integer.getInstance(oMin, false);
+            }
+
+            {
+                ASN1TaggedObject oMax = ASN1TaggedObject.getInstance(seq.getObjectAt(2));
+                if (oMax.getTagNo() != 1)
+                {
+                    throw new IllegalArgumentException("Bad tag number for 'maximum': " + oMax.getTagNo());
+                }
+                maximum = ASN1Integer.getInstance(oMax, false);
+            }
+
+            break;
+        }
+        default:
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+    }
+
+    /**
+     * Constructor from a given details.
+     * 
+     * According RFC 3280, the minimum and maximum fields are not used with any
+     * name forms, thus minimum MUST be zero, and maximum MUST be absent.
+     * <p>
+     * If minimum is <code>null</code>, zero is assumed, if
+     * maximum is <code>null</code>, maximum is absent.
+     * 
+     * @param base
+     *            A restriction.
+     * @param minimum
+     *            Minimum
+     * 
+     * @param maximum
+     *            Maximum
+     */
+    public GeneralSubtree(
+        GeneralName base,
+        BigInteger minimum,
+        BigInteger maximum)
+    {
+        this.base = base;
+        if (maximum != null)
+        {
+            this.maximum = new ASN1Integer(maximum);
+        }
+        if (minimum == null)
+        {
+            this.minimum = null;
+        }
+        else
+        {
+            this.minimum = new ASN1Integer(minimum);
+        }
+    }
+
+    public GeneralSubtree(GeneralName base)
+    {
+        this(base, null, null);
+    }
+
+    public static GeneralSubtree getInstance(
+        ASN1TaggedObject o,
+        boolean explicit)
+    {
+        return new GeneralSubtree(ASN1Sequence.getInstance(o, explicit));
+    }
+
+    public static GeneralSubtree getInstance(
+        Object obj)
+    {
+        if (obj == null)
+        {
+            return null;
+        }
+
+        if (obj instanceof GeneralSubtree)
+        {
+            return (GeneralSubtree) obj;
+        }
+
+        return new GeneralSubtree(ASN1Sequence.getInstance(obj));
+    }
+
+    public GeneralName getBase()
+    {
+        return base;
+    }
+
+    public BigInteger getMinimum()
+    {
+        if (minimum == null)
+        {
+            return ZERO;
+        }
+
+        return minimum.getValue();
+    }
+
+    public BigInteger getMaximum()
+    {
+        if (maximum == null)
+        {
+            return null;
+        }
+
+        return maximum.getValue();
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * 
+     * Returns:
+     * 
+     * <pre>
+     *       GeneralSubtree ::= SEQUENCE 
+     *       {
+     *         base                    GeneralName,
+     *         minimum         [0]     BaseDistance DEFAULT 0,
+     *         maximum         [1]     BaseDistance OPTIONAL 
+     *       }
+     * </pre>
+     * 
+     * @return a ASN1Primitive
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(base);
+
+        if (minimum != null && !minimum.getValue().equals(ZERO))
+        {
+            v.add(new DERTaggedObject(false, 0, minimum));
+        }
+
+        if (maximum != null)
+        {
+            v.add(new DERTaggedObject(false, 1, maximum));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Holder.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Holder.java
new file mode 100644
index 0000000..72b0db9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Holder.java
@@ -0,0 +1,247 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * The Holder object.
+ * <p>
+ * For an v2 attribute certificate this is:
+ * 
+ * <pre>
+ *            Holder ::= SEQUENCE {
+ *                  baseCertificateID   [0] IssuerSerial OPTIONAL,
+ *                           -- the issuer and serial number of
+ *                           -- the holder's Public Key Certificate
+ *                  entityName          [1] GeneralNames OPTIONAL,
+ *                           -- the name of the claimant or role
+ *                  objectDigestInfo    [2] ObjectDigestInfo OPTIONAL
+ *                           -- used to directly authenticate the holder,
+ *                           -- for example, an executable
+ *            }
+ * </pre>
+ * 
+ * <p>
+ * For an v1 attribute certificate this is:
+ * 
+ * <pre>
+ *         subject CHOICE {
+ *          baseCertificateID [0] EXPLICIT IssuerSerial,
+ *          -- associated with a Public Key Certificate
+ *          subjectName [1] EXPLICIT GeneralNames },
+ *          -- associated with a name
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Holder
+    extends ASN1Object
+{
+    public static final int V1_CERTIFICATE_HOLDER = 0;
+    public static final int V2_CERTIFICATE_HOLDER = 1;
+
+    IssuerSerial baseCertificateID;
+
+    GeneralNames entityName;
+
+    ObjectDigestInfo objectDigestInfo;
+
+    private int version = V2_CERTIFICATE_HOLDER;
+
+    public static Holder getInstance(Object obj)
+    {
+        if (obj instanceof Holder)
+        {
+            return (Holder)obj;
+        }
+        else if (obj instanceof ASN1TaggedObject)
+        {
+            return new Holder(ASN1TaggedObject.getInstance(obj));
+        }
+        else if (obj != null)
+        {
+            return new Holder(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * Constructor for a holder for an V1 attribute certificate.
+     * 
+     * @param tagObj The ASN.1 tagged holder object.
+     */
+    private Holder(ASN1TaggedObject tagObj)
+    {
+        switch (tagObj.getTagNo())
+        {
+        case 0:
+            baseCertificateID = IssuerSerial.getInstance(tagObj, true);
+            break;
+        case 1:
+            entityName = GeneralNames.getInstance(tagObj, true);
+            break;
+        default:
+            throw new IllegalArgumentException("unknown tag in Holder");
+        }
+        version = 0;
+    }
+
+    /**
+     * Constructor for a holder for an V2 attribute certificate.
+     * 
+     * @param seq The ASN.1 sequence.
+     */
+    private Holder(ASN1Sequence seq)
+    {
+        if (seq.size() > 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                + seq.size());
+        }
+
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(seq
+                .getObjectAt(i));
+
+            switch (tObj.getTagNo())
+            {
+            case 0:
+                baseCertificateID = IssuerSerial.getInstance(tObj, false);
+                break;
+            case 1:
+                entityName = GeneralNames.getInstance(tObj, false);
+                break;
+            case 2:
+                objectDigestInfo = ObjectDigestInfo.getInstance(tObj, false);
+                break;
+            default:
+                throw new IllegalArgumentException("unknown tag in Holder");
+            }
+        }
+        version = 1;
+    }
+
+    public Holder(IssuerSerial baseCertificateID)
+    {
+        this(baseCertificateID, V2_CERTIFICATE_HOLDER);
+    }
+
+    /**
+     * Constructs a holder from a IssuerSerial for a V1 or V2 certificate.
+     * .
+     * @param baseCertificateID The IssuerSerial.
+     * @param version The version of the attribute certificate. 
+     */
+    public Holder(IssuerSerial baseCertificateID, int version)
+    {
+        this.baseCertificateID = baseCertificateID;
+        this.version = version;
+    }
+    
+    /**
+     * Returns 1 for V2 attribute certificates or 0 for V1 attribute
+     * certificates. 
+     * @return The version of the attribute certificate.
+     */
+    public int getVersion()
+    {
+        return version;
+    }
+
+    /**
+     * Constructs a holder with an entityName for V2 attribute certificates.
+     * 
+     * @param entityName The entity or subject name.
+     */
+    public Holder(GeneralNames entityName)
+    {
+        this(entityName, V2_CERTIFICATE_HOLDER);
+    }
+
+    /**
+     * Constructs a holder with an entityName for V2 attribute certificates or
+     * with a subjectName for V1 attribute certificates.
+     * 
+     * @param entityName The entity or subject name.
+     * @param version The version of the attribute certificate. 
+     */
+    public Holder(GeneralNames entityName, int version)
+    {
+        this.entityName = entityName;
+        this.version = version;
+    }
+    
+    /**
+     * Constructs a holder from an object digest info.
+     * 
+     * @param objectDigestInfo The object digest info object.
+     */
+    public Holder(ObjectDigestInfo objectDigestInfo)
+    {
+        this.objectDigestInfo = objectDigestInfo;
+    }
+
+    public IssuerSerial getBaseCertificateID()
+    {
+        return baseCertificateID;
+    }
+
+    /**
+     * Returns the entityName for an V2 attribute certificate or the subjectName
+     * for an V1 attribute certificate.
+     * 
+     * @return The entityname or subjectname.
+     */
+    public GeneralNames getEntityName()
+    {
+        return entityName;
+    }
+
+    public ObjectDigestInfo getObjectDigestInfo()
+    {
+        return objectDigestInfo;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        if (version == 1)
+        {
+            ASN1EncodableVector v = new ASN1EncodableVector();
+
+            if (baseCertificateID != null)
+            {
+                v.add(new DERTaggedObject(false, 0, baseCertificateID));
+            }
+
+            if (entityName != null)
+            {
+                v.add(new DERTaggedObject(false, 1, entityName));
+            }
+
+            if (objectDigestInfo != null)
+            {
+                v.add(new DERTaggedObject(false, 2, objectDigestInfo));
+            }
+
+            return new DERSequence(v);
+        }
+        else
+        {
+            if (entityName != null)
+            {
+                return new DERTaggedObject(true, 1, entityName);
+            }
+            else
+            {
+                return new DERTaggedObject(true, 0, baseCertificateID);
+            }
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/IssuerSerial.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/IssuerSerial.java
new file mode 100644
index 0000000..8eea001
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/IssuerSerial.java
@@ -0,0 +1,127 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class IssuerSerial
+    extends ASN1Object
+{
+    GeneralNames            issuer;
+    ASN1Integer              serial;
+    DERBitString            issuerUID;
+
+    public static IssuerSerial getInstance(
+            Object  obj)
+    {
+        if (obj instanceof IssuerSerial)
+        {
+            return (IssuerSerial)obj;
+        }
+
+        if (obj != null)
+        {
+            return new IssuerSerial(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static IssuerSerial getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    private IssuerSerial(
+        ASN1Sequence    seq)
+    {
+        if (seq.size() != 2 && seq.size() != 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+        
+        issuer = GeneralNames.getInstance(seq.getObjectAt(0));
+        serial = ASN1Integer.getInstance(seq.getObjectAt(1));
+
+        if (seq.size() == 3)
+        {
+            issuerUID = DERBitString.getInstance(seq.getObjectAt(2));
+        }
+    }
+
+    public IssuerSerial(
+        X500Name   issuer,
+        BigInteger serial)
+    {
+        this(new GeneralNames(new GeneralName(issuer)), new ASN1Integer(serial));
+    }
+
+    public IssuerSerial(
+        GeneralNames    issuer,
+        BigInteger serial)
+    {
+        this(issuer, new ASN1Integer(serial));
+    }
+
+    public IssuerSerial(
+        GeneralNames    issuer,
+        ASN1Integer      serial)
+    {
+        this.issuer = issuer;
+        this.serial = serial;
+    }
+
+    public GeneralNames getIssuer()
+    {
+        return issuer;
+    }
+
+    public ASN1Integer getSerial()
+    {
+        return serial;
+    }
+
+    public DERBitString getIssuerUID()
+    {
+        return issuerUID;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  IssuerSerial  ::=  SEQUENCE {
+     *       issuer         GeneralNames,
+     *       serial         CertificateSerialNumber,
+     *       issuerUID      UniqueIdentifier OPTIONAL
+     *  }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(issuer);
+        v.add(serial);
+
+        if (issuerUID != null)
+        {
+            v.add(issuerUID);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
new file mode 100644
index 0000000..8661418
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
@@ -0,0 +1,277 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Boolean;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * <pre>
+ * IssuingDistributionPoint ::= SEQUENCE { 
+ *   distributionPoint          [0] DistributionPointName OPTIONAL, 
+ *   onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE, 
+ *   onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE, 
+ *   onlySomeReasons            [3] ReasonFlags OPTIONAL, 
+ *   indirectCRL                [4] BOOLEAN DEFAULT FALSE,
+ *   onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class IssuingDistributionPoint
+    extends ASN1Object
+{
+    private DistributionPointName distributionPoint;
+
+    private boolean onlyContainsUserCerts;
+
+    private boolean onlyContainsCACerts;
+
+    private ReasonFlags onlySomeReasons;
+
+    private boolean indirectCRL;
+
+    private boolean onlyContainsAttributeCerts;
+
+    private ASN1Sequence seq;
+
+    public static IssuingDistributionPoint getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static IssuingDistributionPoint getInstance(
+        Object obj)
+    {
+        if (obj instanceof IssuingDistributionPoint)
+        {
+            return (IssuingDistributionPoint)obj;
+        }
+        else if (obj != null)
+        {
+            return new IssuingDistributionPoint(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * Constructor from given details.
+     * 
+     * @param distributionPoint
+     *            May contain an URI as pointer to most current CRL.
+     * @param onlyContainsUserCerts Covers revocation information for end certificates.
+     * @param onlyContainsCACerts Covers revocation information for CA certificates.
+     * 
+     * @param onlySomeReasons
+     *            Which revocation reasons does this point cover.
+     * @param indirectCRL
+     *            If <code>true</code> then the CRL contains revocation
+     *            information about certificates ssued by other CAs.
+     * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.
+     */
+    public IssuingDistributionPoint(
+        DistributionPointName distributionPoint,
+        boolean onlyContainsUserCerts,
+        boolean onlyContainsCACerts,
+        ReasonFlags onlySomeReasons,
+        boolean indirectCRL,
+        boolean onlyContainsAttributeCerts)
+    {
+        this.distributionPoint = distributionPoint;
+        this.indirectCRL = indirectCRL;
+        this.onlyContainsAttributeCerts = onlyContainsAttributeCerts;
+        this.onlyContainsCACerts = onlyContainsCACerts;
+        this.onlyContainsUserCerts = onlyContainsUserCerts;
+        this.onlySomeReasons = onlySomeReasons;
+
+        ASN1EncodableVector vec = new ASN1EncodableVector();
+        if (distributionPoint != null)
+        {                                    // CHOICE item so explicitly tagged
+            vec.add(new DERTaggedObject(true, 0, distributionPoint));
+        }
+        if (onlyContainsUserCerts)
+        {
+            vec.add(new DERTaggedObject(false, 1, ASN1Boolean.getInstance(true)));
+        }
+        if (onlyContainsCACerts)
+        {
+            vec.add(new DERTaggedObject(false, 2, ASN1Boolean.getInstance(true)));
+        }
+        if (onlySomeReasons != null)
+        {
+            vec.add(new DERTaggedObject(false, 3, onlySomeReasons));
+        }
+        if (indirectCRL)
+        {
+            vec.add(new DERTaggedObject(false, 4, ASN1Boolean.getInstance(true)));
+        }
+        if (onlyContainsAttributeCerts)
+        {
+            vec.add(new DERTaggedObject(false, 5, ASN1Boolean.getInstance(true)));
+        }
+
+        seq = new DERSequence(vec);
+    }
+
+    /**
+     * Shorthand Constructor from given details.
+     *
+     * @param distributionPoint
+     *            May contain an URI as pointer to most current CRL.
+     * @param indirectCRL
+     *            If <code>true</code> then the CRL contains revocation
+     *            information about certificates ssued by other CAs.
+     * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.
+     */
+    public IssuingDistributionPoint(
+        DistributionPointName distributionPoint,
+        boolean indirectCRL,
+        boolean onlyContainsAttributeCerts)
+    {
+        this(distributionPoint, false, false, null, indirectCRL, onlyContainsAttributeCerts);
+    }
+
+    /**
+     * Constructor from ASN1Sequence
+     */
+    private IssuingDistributionPoint(
+        ASN1Sequence seq)
+    {
+        this.seq = seq;
+
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+
+            switch (o.getTagNo())
+            {
+            case 0:
+                                                    // CHOICE so explicit
+                distributionPoint = DistributionPointName.getInstance(o, true);
+                break;
+            case 1:
+                onlyContainsUserCerts = ASN1Boolean.getInstance(o, false).isTrue();
+                break;
+            case 2:
+                onlyContainsCACerts = ASN1Boolean.getInstance(o, false).isTrue();
+                break;
+            case 3:
+                onlySomeReasons = new ReasonFlags(ReasonFlags.getInstance(o, false));
+                break;
+            case 4:
+                indirectCRL = ASN1Boolean.getInstance(o, false).isTrue();
+                break;
+            case 5:
+                onlyContainsAttributeCerts = ASN1Boolean.getInstance(o, false).isTrue();
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "unknown tag in IssuingDistributionPoint");
+            }
+        }
+    }
+
+    public boolean onlyContainsUserCerts()
+    {
+        return onlyContainsUserCerts;
+    }
+
+    public boolean onlyContainsCACerts()
+    {
+        return onlyContainsCACerts;
+    }
+
+    public boolean isIndirectCRL()
+    {
+        return indirectCRL;
+    }
+
+    public boolean onlyContainsAttributeCerts()
+    {
+        return onlyContainsAttributeCerts;
+    }
+
+    /**
+     * @return Returns the distributionPoint.
+     */
+    public DistributionPointName getDistributionPoint()
+    {
+        return distributionPoint;
+    }
+
+    /**
+     * @return Returns the onlySomeReasons.
+     */
+    public ReasonFlags getOnlySomeReasons()
+    {
+        return onlySomeReasons;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+
+    public String toString()
+    {
+        String       sep = Strings.lineSeparator();
+        StringBuffer buf = new StringBuffer();
+
+        buf.append("IssuingDistributionPoint: [");
+        buf.append(sep);
+        if (distributionPoint != null)
+        {
+            appendObject(buf, sep, "distributionPoint", distributionPoint.toString());
+        }
+        if (onlyContainsUserCerts)
+        {
+            appendObject(buf, sep, "onlyContainsUserCerts", booleanToString(onlyContainsUserCerts));
+        }
+        if (onlyContainsCACerts)
+        {
+            appendObject(buf, sep, "onlyContainsCACerts", booleanToString(onlyContainsCACerts));
+        }
+        if (onlySomeReasons != null)
+        {
+            appendObject(buf, sep, "onlySomeReasons", onlySomeReasons.toString());
+        }
+        if (onlyContainsAttributeCerts)
+        {
+            appendObject(buf, sep, "onlyContainsAttributeCerts", booleanToString(onlyContainsAttributeCerts));
+        }
+        if (indirectCRL)
+        {
+            appendObject(buf, sep, "indirectCRL", booleanToString(indirectCRL));
+        }
+        buf.append("]");
+        buf.append(sep);
+        return buf.toString();
+    }
+
+    private void appendObject(StringBuffer buf, String sep, String name, String value)
+    {
+        String       indent = "    ";
+
+        buf.append(indent);
+        buf.append(name);
+        buf.append(":");
+        buf.append(sep);
+        buf.append(indent);
+        buf.append(indent);
+        buf.append(value);
+        buf.append(sep);
+    }
+
+    private String booleanToString(boolean value)
+    {
+        return value ? "true" : "false";
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/KeyPurposeId.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/KeyPurposeId.java
new file mode 100644
index 0000000..1d68160
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/KeyPurposeId.java
@@ -0,0 +1,187 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+
+/**
+ * The KeyPurposeId object.
+ * <pre>
+ *     KeyPurposeId ::= OBJECT IDENTIFIER
+ *
+ *     id-kp ::= OBJECT IDENTIFIER { iso(1) identified-organization(3)
+ *          dod(6) internet(1) security(5) mechanisms(5) pkix(7) 3}
+ *
+ * </pre>
+ * To create a new KeyPurposeId where none of the below suit, use
+ * <pre>
+ *     ASN1ObjectIdentifier newKeyPurposeIdOID = new ASN1ObjectIdentifier("1.3.6.1...");
+ *
+ *     KeyPurposeId newKeyPurposeId = KeyPurposeId.getInstance(newKeyPurposeIdOID);
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyPurposeId
+    extends ASN1Object
+{
+    private static final ASN1ObjectIdentifier id_kp = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.3");
+
+    /**
+     * { 2 5 29 37 0 }
+     */
+    public static final KeyPurposeId anyExtendedKeyUsage = new KeyPurposeId(Extension.extendedKeyUsage.branch("0"));
+
+    /**
+     * { id-kp 1 }
+     */
+    public static final KeyPurposeId id_kp_serverAuth = new KeyPurposeId(id_kp.branch("1"));
+    /**
+     * { id-kp 2 }
+     */
+    public static final KeyPurposeId id_kp_clientAuth = new KeyPurposeId(id_kp.branch("2"));
+    /**
+     * { id-kp 3 }
+     */
+    public static final KeyPurposeId id_kp_codeSigning = new KeyPurposeId(id_kp.branch("3"));
+    /**
+     * { id-kp 4 }
+     */
+    public static final KeyPurposeId id_kp_emailProtection = new KeyPurposeId(id_kp.branch("4"));
+    /**
+     * Usage deprecated by RFC4945 - was { id-kp 5 }
+     */
+    public static final KeyPurposeId id_kp_ipsecEndSystem = new KeyPurposeId(id_kp.branch("5"));
+    /**
+     * Usage deprecated by RFC4945 - was { id-kp 6 }
+     */
+    public static final KeyPurposeId id_kp_ipsecTunnel = new KeyPurposeId(id_kp.branch("6"));
+    /**
+     * Usage deprecated by RFC4945 - was { idkp 7 }
+     */
+    public static final KeyPurposeId id_kp_ipsecUser = new KeyPurposeId(id_kp.branch("7"));
+    /**
+     * { id-kp 8 }
+     */
+    public static final KeyPurposeId id_kp_timeStamping = new KeyPurposeId(id_kp.branch("8"));
+    /**
+     * { id-kp 9 }
+     */
+    public static final KeyPurposeId id_kp_OCSPSigning = new KeyPurposeId(id_kp.branch("9"));
+    /**
+     * { id-kp 10 }
+     */
+    public static final KeyPurposeId id_kp_dvcs = new KeyPurposeId(id_kp.branch("10"));
+    /**
+     * { id-kp 11 }
+     */
+    public static final KeyPurposeId id_kp_sbgpCertAAServerAuth = new KeyPurposeId(id_kp.branch("11"));
+    /**
+     * { id-kp 12 }
+     */
+    public static final KeyPurposeId id_kp_scvp_responder = new KeyPurposeId(id_kp.branch("12"));
+    /**
+     * { id-kp 13 }
+     */
+    public static final KeyPurposeId id_kp_eapOverPPP = new KeyPurposeId(id_kp.branch("13"));
+    /**
+     * { id-kp 14 }
+     */
+    public static final KeyPurposeId id_kp_eapOverLAN = new KeyPurposeId(id_kp.branch("14"));
+    /**
+     * { id-kp 15 }
+     */
+    public static final KeyPurposeId id_kp_scvpServer = new KeyPurposeId(id_kp.branch("15"));
+    /**
+     * { id-kp 16 }
+     */
+    public static final KeyPurposeId id_kp_scvpClient = new KeyPurposeId(id_kp.branch("16"));
+    /**
+     * { id-kp 17 }
+     */
+    public static final KeyPurposeId id_kp_ipsecIKE = new KeyPurposeId(id_kp.branch("17"));
+    /**
+     * { id-kp 18 }
+     */
+    public static final KeyPurposeId id_kp_capwapAC = new KeyPurposeId(id_kp.branch("18"));
+    /**
+     * { id-kp 19 }
+     */
+    public static final KeyPurposeId id_kp_capwapWTP = new KeyPurposeId(id_kp.branch("19"));
+
+    //
+    // microsoft key purpose ids
+    //
+    /**
+     * { 1 3 6 1 4 1 311 20 2 2 }
+     */
+    public static final KeyPurposeId id_kp_smartcardlogon = new KeyPurposeId(new ASN1ObjectIdentifier("1.3.6.1.4.1.311.20.2.2"));
+
+
+    /**
+     *
+     */
+    public static final KeyPurposeId id_kp_macAddress = new KeyPurposeId(new ASN1ObjectIdentifier("1.3.6.1.1.1.1.22"));
+
+
+    /**
+     * Microsoft Server Gated Crypto (msSGC) see http://www.alvestrand.no/objectid/1.3.6.1.4.1.311.10.3.3.html
+     */
+    public static final KeyPurposeId id_kp_msSGC = new KeyPurposeId(new ASN1ObjectIdentifier("1.3.6.1.4.1.311.10.3.3"));
+
+    /**
+     * Netscape Server Gated Crypto (nsSGC) see http://www.alvestrand.no/objectid/2.16.840.1.113730.4.1.html
+     */
+    public static final KeyPurposeId id_kp_nsSGC = new KeyPurposeId(new ASN1ObjectIdentifier("2.16.840.1.113730.4.1"));
+
+
+    private ASN1ObjectIdentifier id;
+
+    private KeyPurposeId(ASN1ObjectIdentifier id)
+    {
+        this.id = id;
+    }
+
+    /**
+     * @param id string representation of an OID.
+     * @deprecated use getInstance and an OID or one of the constants above.
+     */
+    public KeyPurposeId(String id)
+    {
+        this(new ASN1ObjectIdentifier(id));
+    }
+
+    public static KeyPurposeId getInstance(Object o)
+    {
+        if (o instanceof KeyPurposeId)
+        {
+            return (KeyPurposeId)o;
+        }
+        else if (o != null)
+        {
+            return new KeyPurposeId(ASN1ObjectIdentifier.getInstance(o));
+        }
+
+        return null;
+    }
+
+    public ASN1ObjectIdentifier toOID()
+    {
+        return id;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return id;
+    }
+
+    public String getId()
+    {
+        return id.getId();
+    }
+
+    public String toString()
+    {
+        return id.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/KeyUsage.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/KeyUsage.java
new file mode 100644
index 0000000..6205b18
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/KeyUsage.java
@@ -0,0 +1,115 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+
+/**
+ * The KeyUsage object.
+ * <pre>
+ *    id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
+ *
+ *    KeyUsage ::= BIT STRING {
+ *         digitalSignature        (0),
+ *         nonRepudiation          (1),
+ *         keyEncipherment         (2),
+ *         dataEncipherment        (3),
+ *         keyAgreement            (4),
+ *         keyCertSign             (5),
+ *         cRLSign                 (6),
+ *         encipherOnly            (7),
+ *         decipherOnly            (8) }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyUsage
+    extends ASN1Object
+{
+    public static final int        digitalSignature = (1 << 7); 
+    public static final int        nonRepudiation   = (1 << 6);
+    public static final int        keyEncipherment  = (1 << 5);
+    public static final int        dataEncipherment = (1 << 4);
+    public static final int        keyAgreement     = (1 << 3);
+    public static final int        keyCertSign      = (1 << 2);
+    public static final int        cRLSign          = (1 << 1);
+    public static final int        encipherOnly     = (1 << 0);
+    public static final int        decipherOnly     = (1 << 15);
+
+    private DERBitString bitString;
+
+    public static KeyUsage getInstance(Object obj)   // needs to be DERBitString for other VMs
+    {
+        if (obj instanceof KeyUsage)
+        {
+            return (KeyUsage)obj;
+        }
+        else if (obj != null)
+        {
+            return new KeyUsage(DERBitString.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static KeyUsage fromExtensions(Extensions extensions)
+    {
+        return KeyUsage.getInstance(extensions.getExtensionParsedValue(Extension.keyUsage));
+    }
+
+    /**
+     * Basic constructor.
+     * 
+     * @param usage - the bitwise OR of the Key Usage flags giving the
+     * allowed uses for the key.
+     * e.g. (KeyUsage.keyEncipherment | KeyUsage.dataEncipherment)
+     */
+    public KeyUsage(
+        int usage)
+    {
+        this.bitString = new DERBitString(usage);
+    }
+
+    private KeyUsage(
+        DERBitString bitString)
+    {
+        this.bitString = bitString;
+    }
+
+    /**
+     * Return true if a given usage bit is set, false otherwise.
+     *
+     * @param usages combination of usage flags.
+     * @return true if all bits are set, false otherwise.
+     */
+    public boolean hasUsages(int usages)
+    {
+        return (bitString.intValue() & usages) == usages;
+    }
+
+    public byte[] getBytes()
+    {
+        return bitString.getBytes();
+    }
+
+    public int getPadBits()
+    {
+        return bitString.getPadBits();
+    }
+
+    public String toString()
+    {
+        byte[] data = bitString.getBytes();
+
+        if (data.length == 1)
+        {
+            return "KeyUsage: 0x" + Integer.toHexString(data[0] & 0xff);
+        }
+        return "KeyUsage: 0x" + Integer.toHexString((data[1] & 0xff) << 8 | (data[0] & 0xff));
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return bitString;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/NameConstraintValidator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/NameConstraintValidator.java
new file mode 100644
index 0000000..54ad015
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/NameConstraintValidator.java
@@ -0,0 +1,22 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface NameConstraintValidator
+{
+    void checkPermitted(GeneralName name)
+        throws NameConstraintValidatorException;
+
+    void checkExcluded(GeneralName name)
+            throws NameConstraintValidatorException;
+
+    void intersectPermittedSubtree(GeneralSubtree permitted);
+
+    void intersectPermittedSubtree(GeneralSubtree[] permitted);
+
+    void intersectEmptyPermittedSubtree(int nameType);
+
+    void addExcludedSubtree(GeneralSubtree subtree);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/NameConstraintValidatorException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/NameConstraintValidatorException.java
new file mode 100644
index 0000000..3eb4810
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/NameConstraintValidatorException.java
@@ -0,0 +1,14 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class NameConstraintValidatorException
+    extends Exception
+{
+    public NameConstraintValidatorException(String msg)
+    {
+        super(msg);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/NameConstraints.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/NameConstraints.java
new file mode 100644
index 0000000..981226f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/NameConstraints.java
@@ -0,0 +1,131 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class NameConstraints
+    extends ASN1Object
+{
+    private GeneralSubtree[] permitted, excluded;
+
+    public static NameConstraints getInstance(Object obj)
+    {
+        if (obj instanceof NameConstraints)
+        {
+            return (NameConstraints)obj;
+        }
+        if (obj != null)
+        {
+            return new NameConstraints(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private NameConstraints(ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+        while (e.hasMoreElements())
+        {
+            ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement());
+            switch (o.getTagNo())
+            {
+            case 0:
+                permitted = createArray(ASN1Sequence.getInstance(o, false));
+                break;
+            case 1:
+                excluded = createArray(ASN1Sequence.getInstance(o, false));
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown tag encountered: " + o.getTagNo());
+            }
+        }
+    }
+
+    /**
+     * Constructor from a given details.
+     * 
+     * <p>
+     * permitted and excluded are arrays of GeneralSubtree objects.
+     * 
+     * @param permitted
+     *            Permitted subtrees
+     * @param excluded
+     *            Excludes subtrees
+     */
+    public NameConstraints(
+        GeneralSubtree[] permitted,
+        GeneralSubtree[] excluded)
+    {
+        this.permitted = cloneSubtree(permitted);
+        this.excluded = cloneSubtree(excluded);
+    }
+
+    private GeneralSubtree[] createArray(ASN1Sequence subtree)
+    {
+        GeneralSubtree[] ar = new GeneralSubtree[subtree.size()];
+
+        for (int i = 0; i != ar.length; i++)
+        {
+            ar[i] = GeneralSubtree.getInstance(subtree.getObjectAt(i));
+        }
+
+        return ar;
+    }
+
+    public GeneralSubtree[] getPermittedSubtrees()
+    {
+        return cloneSubtree(permitted);
+    }
+
+    public GeneralSubtree[] getExcludedSubtrees()
+    {
+        return cloneSubtree(excluded);
+    }
+
+    /*
+     * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees
+     * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        if (permitted != null)
+        {
+            v.add(new DERTaggedObject(false, 0, new DERSequence(permitted)));
+        }
+
+        if (excluded != null)
+        {
+            v.add(new DERTaggedObject(false, 1, new DERSequence(excluded)));
+        }
+
+        return new DERSequence(v);
+    }
+
+    private static GeneralSubtree[] cloneSubtree(GeneralSubtree[] subtrees)
+    {
+        if (subtrees != null)
+        {
+            GeneralSubtree[] rv = new GeneralSubtree[subtrees.length];
+
+            System.arraycopy(subtrees, 0, rv, 0, rv.length);
+
+            return rv;
+        }
+
+        return null;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ObjectDigestInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ObjectDigestInfo.java
new file mode 100644
index 0000000..abe1fbb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ObjectDigestInfo.java
@@ -0,0 +1,192 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * ObjectDigestInfo ASN.1 structure used in v2 attribute certificates.
+ * 
+ * <pre>
+ *  
+ *    ObjectDigestInfo ::= SEQUENCE {
+ *         digestedObjectType  ENUMERATED {
+ *                 publicKey            (0),
+ *                 publicKeyCert        (1),
+ *                 otherObjectTypes     (2) },
+ *                         -- otherObjectTypes MUST NOT
+ *                         -- be used in this profile
+ *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,
+ *         digestAlgorithm     AlgorithmIdentifier,
+ *         objectDigest        BIT STRING
+ *    }
+ *   
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ * 
+ */
+public class ObjectDigestInfo
+    extends ASN1Object
+{
+    /**
+     * The public key is hashed.
+     */
+    public final static int publicKey = 0;
+
+    /**
+     * The public key certificate is hashed.
+     */
+    public final static int publicKeyCert = 1;
+
+    /**
+     * An other object is hashed.
+     */
+    public final static int otherObjectDigest = 2;
+
+    ASN1Enumerated digestedObjectType;
+
+    ASN1ObjectIdentifier otherObjectTypeID;
+
+    AlgorithmIdentifier digestAlgorithm;
+
+    DERBitString objectDigest;
+
+    public static ObjectDigestInfo getInstance(
+        Object obj)
+    {
+        if (obj instanceof ObjectDigestInfo)
+        {
+            return (ObjectDigestInfo)obj;
+        }
+
+        if (obj != null)
+        {
+            return new ObjectDigestInfo(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static ObjectDigestInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    /**
+     * Constructor from given details.
+     * <p>
+     * If <code>digestedObjectType</code> is not {@link #publicKeyCert} or
+     * {@link #publicKey} <code>otherObjectTypeID</code> must be given,
+     * otherwise it is ignored.
+     * 
+     * @param digestedObjectType The digest object type.
+     * @param otherObjectTypeID The object type ID for
+     *            <code>otherObjectDigest</code>.
+     * @param digestAlgorithm The algorithm identifier for the hash.
+     * @param objectDigest The hash value.
+     */
+    public ObjectDigestInfo(
+        int digestedObjectType,
+        ASN1ObjectIdentifier otherObjectTypeID,
+        AlgorithmIdentifier digestAlgorithm,
+        byte[] objectDigest)
+    {
+        this.digestedObjectType = new ASN1Enumerated(digestedObjectType);
+        if (digestedObjectType == otherObjectDigest)
+        {
+            this.otherObjectTypeID = otherObjectTypeID;
+        }
+
+        this.digestAlgorithm = digestAlgorithm;
+        this.objectDigest = new DERBitString(objectDigest);
+    }
+
+    private ObjectDigestInfo(
+        ASN1Sequence seq)
+    {
+        if (seq.size() > 4 || seq.size() < 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                + seq.size());
+        }
+
+        digestedObjectType = ASN1Enumerated.getInstance(seq.getObjectAt(0));
+
+        int offset = 0;
+
+        if (seq.size() == 4)
+        {
+            otherObjectTypeID = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(1));
+            offset++;
+        }
+
+        digestAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1 + offset));
+
+        objectDigest = DERBitString.getInstance(seq.getObjectAt(2 + offset));
+    }
+
+    public ASN1Enumerated getDigestedObjectType()
+    {
+        return digestedObjectType;
+    }
+
+    public ASN1ObjectIdentifier getOtherObjectTypeID()
+    {
+        return otherObjectTypeID;
+    }
+
+    public AlgorithmIdentifier getDigestAlgorithm()
+    {
+        return digestAlgorithm;
+    }
+
+    public DERBitString getObjectDigest()
+    {
+        return objectDigest;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * 
+     * <pre>
+     *  
+     *    ObjectDigestInfo ::= SEQUENCE {
+     *         digestedObjectType  ENUMERATED {
+     *                 publicKey            (0),
+     *                 publicKeyCert        (1),
+     *                 otherObjectTypes     (2) },
+     *                         -- otherObjectTypes MUST NOT
+     *                         -- be used in this profile
+     *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,
+     *         digestAlgorithm     AlgorithmIdentifier,
+     *         objectDigest        BIT STRING
+     *    }
+     *   
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(digestedObjectType);
+
+        if (otherObjectTypeID != null)
+        {
+            v.add(otherObjectTypeID);
+        }
+
+        v.add(digestAlgorithm);
+        v.add(objectDigest);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/OtherName.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/OtherName.java
new file mode 100644
index 0000000..a2c7e03
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/OtherName.java
@@ -0,0 +1,94 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * The OtherName object.
+ * <pre>
+ * OtherName ::= SEQUENCE {
+ *      type-id    OBJECT IDENTIFIER,
+ *      value      [0] EXPLICIT ANY DEFINED BY type-id }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OtherName
+    extends ASN1Object
+{
+    private final ASN1ObjectIdentifier typeID;
+    private final ASN1Encodable value;
+
+    /**
+     * OtherName factory method.
+     * @param obj the object used to construct an instance of <code>
+     * OtherName</code>. It must be an instance of <code>OtherName
+     * </code> or <code>ASN1Sequence</code>.
+     * @return the instance of <code>OtherName</code> built from the
+     * supplied object.
+     * @throws java.lang.IllegalArgumentException if the object passed
+     * to the factory is not an instance of <code>OtherName</code> or something that
+     * can be converted into an appropriate <code>ASN1Sequence</code>.
+     */
+    public static OtherName getInstance(
+        Object obj)
+    {
+
+        if (obj instanceof OtherName)
+        {
+            return (OtherName)obj;
+        }
+        else if (obj != null)
+        {
+            return new OtherName(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * Base constructor.
+     * @param typeID the type of the other name.
+     * @param value the ANY object that represents the value.
+     */
+    public OtherName(
+        ASN1ObjectIdentifier typeID,
+        ASN1Encodable value)
+    {
+        this.typeID = typeID;
+        this.value  = value;
+    }
+
+    private OtherName(ASN1Sequence seq)
+    {
+        this.typeID = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+        this.value = ASN1TaggedObject.getInstance(seq.getObjectAt(1)).getObject(); // explicitly tagged
+    }
+
+    public ASN1ObjectIdentifier getTypeID()
+    {
+        return typeID;
+    }
+
+    public ASN1Encodable getValue()
+    {
+        return value;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(typeID);
+        v.add(new DERTaggedObject(true, 0, value));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java
new file mode 100644
index 0000000..a5162a1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java
@@ -0,0 +1,2090 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Integers;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKIXNameConstraintValidator
+    implements NameConstraintValidator
+{
+    private Set excludedSubtreesDN = new HashSet();
+
+    private Set excludedSubtreesDNS = new HashSet();
+
+    private Set excludedSubtreesEmail = new HashSet();
+
+    private Set excludedSubtreesURI = new HashSet();
+
+    private Set excludedSubtreesIP = new HashSet();
+
+    private Set excludedSubtreesOtherName = new HashSet();
+
+    private Set permittedSubtreesDN;
+
+    private Set permittedSubtreesDNS;
+
+    private Set permittedSubtreesEmail;
+
+    private Set permittedSubtreesURI;
+
+    private Set permittedSubtreesIP;
+
+    private Set permittedSubtreesOtherName;
+
+    public PKIXNameConstraintValidator()
+    {
+    }
+
+    /**
+     * Checks if the given GeneralName is in the permitted set.
+     *
+     * @param name The GeneralName
+     * @throws NameConstraintValidatorException If the <code>name</code>
+     */
+    public void checkPermitted(GeneralName name)
+        throws NameConstraintValidatorException
+    {
+        switch (name.getTagNo())
+        {
+        case GeneralName.otherName:
+            checkPermittedOtherName(permittedSubtreesOtherName, OtherName.getInstance(name.getName()));
+            break;
+        case GeneralName.rfc822Name:
+            checkPermittedEmail(permittedSubtreesEmail,
+                extractNameAsString(name));
+            break;
+        case GeneralName.dNSName:
+            checkPermittedDNS(permittedSubtreesDNS, DERIA5String.getInstance(
+                name.getName()).getString());
+            break;
+        case GeneralName.directoryName:
+            checkPermittedDN(X500Name.getInstance(name.getName()));
+            break;
+        case GeneralName.uniformResourceIdentifier:
+            checkPermittedURI(permittedSubtreesURI, DERIA5String.getInstance(
+                name.getName()).getString());
+            break;
+        case GeneralName.iPAddress:
+            byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets();
+
+            checkPermittedIP(permittedSubtreesIP, ip);
+            break;
+        default:
+            throw new IllegalStateException("Unknown tag encountered: " + name.getTagNo());
+        }
+    }
+
+    /**
+     * Check if the given GeneralName is contained in the excluded set.
+     *
+     * @param name The GeneralName.
+     * @throws NameConstraintValidatorException If the <code>name</code> is
+     * excluded.
+     */
+    public void checkExcluded(GeneralName name)
+        throws NameConstraintValidatorException
+    {
+        switch (name.getTagNo())
+        {
+        case GeneralName.otherName:
+            checkExcludedOtherName(excludedSubtreesOtherName, OtherName.getInstance(name.getName()));
+            break;
+        case GeneralName.rfc822Name:
+            checkExcludedEmail(excludedSubtreesEmail, extractNameAsString(name));
+            break;
+        case GeneralName.dNSName:
+            checkExcludedDNS(excludedSubtreesDNS, DERIA5String.getInstance(
+                name.getName()).getString());
+            break;
+        case GeneralName.directoryName:
+            checkExcludedDN(X500Name.getInstance(name.getName()));
+            break;
+        case GeneralName.uniformResourceIdentifier:
+            checkExcludedURI(excludedSubtreesURI, DERIA5String.getInstance(
+                name.getName()).getString());
+            break;
+        case GeneralName.iPAddress:
+            byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets();
+
+            checkExcludedIP(excludedSubtreesIP, ip);
+            break;
+        default:
+            throw new IllegalStateException("Unknown tag encountered: " + name.getTagNo());
+        }
+    }
+
+    public void intersectPermittedSubtree(GeneralSubtree permitted)
+    {
+        intersectPermittedSubtree(new GeneralSubtree[]{permitted});
+    }
+
+    /**
+     * Updates the permitted set of these name constraints with the intersection
+     * with the given subtree.
+     *
+     * @param permitted The permitted subtrees
+     */
+    public void intersectPermittedSubtree(GeneralSubtree[] permitted)
+    {
+        Map subtreesMap = new HashMap();
+
+        // group in sets in a map ordered by tag no.
+        for (int i = 0; i != permitted.length; i++)
+        {
+            GeneralSubtree subtree = permitted[i];
+            Integer tagNo = Integers.valueOf(subtree.getBase().getTagNo());
+            if (subtreesMap.get(tagNo) == null)
+            {
+                subtreesMap.put(tagNo, new HashSet());
+            }
+            ((Set)subtreesMap.get(tagNo)).add(subtree);
+        }
+
+        for (Iterator it = subtreesMap.entrySet().iterator(); it.hasNext(); )
+        {
+            Map.Entry entry = (Map.Entry)it.next();
+
+            // go through all subtree groups
+            int nameType = ((Integer)entry.getKey()).intValue();
+            switch (nameType)
+            {
+            case GeneralName.otherName:
+                permittedSubtreesOtherName = intersectOtherName(permittedSubtreesOtherName,
+                    (Set)entry.getValue());
+                break;
+            case GeneralName.rfc822Name:
+                permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail,
+                    (Set)entry.getValue());
+                break;
+            case GeneralName.dNSName:
+                permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS,
+                    (Set)entry.getValue());
+                break;
+            case GeneralName.directoryName:
+                permittedSubtreesDN = intersectDN(permittedSubtreesDN,
+                    (Set)entry.getValue());
+                break;
+            case GeneralName.uniformResourceIdentifier:
+                permittedSubtreesURI = intersectURI(permittedSubtreesURI,
+                    (Set)entry.getValue());
+                break;
+            case GeneralName.iPAddress:
+                permittedSubtreesIP = intersectIP(permittedSubtreesIP,
+                    (Set)entry.getValue());
+                break;
+            default:
+                throw new IllegalStateException("Unknown tag encountered: " + nameType);
+            }
+        }
+    }
+
+    public void intersectEmptyPermittedSubtree(int nameType)
+    {
+        switch (nameType)
+        {
+        case GeneralName.otherName:
+            permittedSubtreesOtherName = new HashSet();
+            break;
+        case GeneralName.rfc822Name:
+            permittedSubtreesEmail = new HashSet();
+            break;
+        case GeneralName.dNSName:
+            permittedSubtreesDNS = new HashSet();
+            break;
+        case GeneralName.directoryName:
+            permittedSubtreesDN = new HashSet();
+            break;
+        case GeneralName.uniformResourceIdentifier:
+            permittedSubtreesURI = new HashSet();
+            break;
+        case GeneralName.iPAddress:
+            permittedSubtreesIP = new HashSet();
+            break;
+        default:
+            throw new IllegalStateException("Unknown tag encountered: " + nameType);
+        }
+    }
+
+    /**
+     * Adds a subtree to the excluded set of these name constraints.
+     *
+     * @param subtree A subtree with an excluded GeneralName.
+     */
+    public void addExcludedSubtree(GeneralSubtree subtree)
+    {
+        GeneralName base = subtree.getBase();
+
+        switch (base.getTagNo())
+        {
+        case GeneralName.otherName:
+            excludedSubtreesOtherName = unionOtherName(excludedSubtreesOtherName,
+                OtherName.getInstance(base.getName()));
+            break;
+        case GeneralName.rfc822Name:
+            excludedSubtreesEmail = unionEmail(excludedSubtreesEmail,
+                extractNameAsString(base));
+            break;
+        case GeneralName.dNSName:
+            excludedSubtreesDNS = unionDNS(excludedSubtreesDNS,
+                extractNameAsString(base));
+            break;
+        case GeneralName.directoryName:
+            excludedSubtreesDN = unionDN(excludedSubtreesDN,
+                (ASN1Sequence)base.getName().toASN1Primitive());
+            break;
+        case GeneralName.uniformResourceIdentifier:
+            excludedSubtreesURI = unionURI(excludedSubtreesURI,
+                extractNameAsString(base));
+            break;
+        case GeneralName.iPAddress:
+            excludedSubtreesIP = unionIP(excludedSubtreesIP, ASN1OctetString
+                .getInstance(base.getName()).getOctets());
+            break;
+        default:
+            throw new IllegalStateException("Unknown tag encountered: " + base.getTagNo());
+        }
+    }
+
+    public int hashCode()
+    {
+        return hashCollection(excludedSubtreesDN)
+            + hashCollection(excludedSubtreesDNS)
+            + hashCollection(excludedSubtreesEmail)
+            + hashCollection(excludedSubtreesIP)
+            + hashCollection(excludedSubtreesURI)
+            + hashCollection(excludedSubtreesOtherName)
+            + hashCollection(permittedSubtreesDN)
+            + hashCollection(permittedSubtreesDNS)
+            + hashCollection(permittedSubtreesEmail)
+            + hashCollection(permittedSubtreesIP)
+            + hashCollection(permittedSubtreesURI)
+            + hashCollection(permittedSubtreesOtherName);
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof PKIXNameConstraintValidator))
+        {
+            return false;
+        }
+        PKIXNameConstraintValidator constraintValidator = (PKIXNameConstraintValidator)o;
+        return collectionsAreEqual(constraintValidator.excludedSubtreesDN, excludedSubtreesDN)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesDNS, excludedSubtreesDNS)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesEmail, excludedSubtreesEmail)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesIP, excludedSubtreesIP)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesURI, excludedSubtreesURI)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesOtherName, excludedSubtreesOtherName)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesDN, permittedSubtreesDN)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesDNS, permittedSubtreesDNS)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesEmail, permittedSubtreesEmail)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesIP, permittedSubtreesIP)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesOtherName, permittedSubtreesOtherName);
+    }
+
+    public String toString()
+    {
+        String temp = "";
+        temp += "permitted:\n";
+        if (permittedSubtreesDN != null)
+        {
+            temp += "DN:\n";
+            temp += permittedSubtreesDN.toString() + "\n";
+        }
+        if (permittedSubtreesDNS != null)
+        {
+            temp += "DNS:\n";
+            temp += permittedSubtreesDNS.toString() + "\n";
+        }
+        if (permittedSubtreesEmail != null)
+        {
+            temp += "Email:\n";
+            temp += permittedSubtreesEmail.toString() + "\n";
+        }
+        if (permittedSubtreesURI != null)
+        {
+            temp += "URI:\n";
+            temp += permittedSubtreesURI.toString() + "\n";
+        }
+        if (permittedSubtreesIP != null)
+        {
+            temp += "IP:\n";
+            temp += stringifyIPCollection(permittedSubtreesIP) + "\n";
+        }
+        if (permittedSubtreesOtherName != null)
+        {
+            temp += "OtherName:\n";
+            temp += stringifyOtherNameCollection(permittedSubtreesOtherName) + "\n";
+        }
+        temp += "excluded:\n";
+        if (!excludedSubtreesDN.isEmpty())
+        {
+            temp += "DN:\n";
+            temp += excludedSubtreesDN.toString() + "\n";
+        }
+        if (!excludedSubtreesDNS.isEmpty())
+        {
+            temp += "DNS:\n";
+            temp += excludedSubtreesDNS.toString() + "\n";
+        }
+        if (!excludedSubtreesEmail.isEmpty())
+        {
+            temp += "Email:\n";
+            temp += excludedSubtreesEmail.toString() + "\n";
+        }
+        if (!excludedSubtreesURI.isEmpty())
+        {
+            temp += "URI:\n";
+            temp += excludedSubtreesURI.toString() + "\n";
+        }
+        if (!excludedSubtreesIP.isEmpty())
+        {
+            temp += "IP:\n";
+            temp += stringifyIPCollection(excludedSubtreesIP) + "\n";
+        }
+        if (!excludedSubtreesOtherName.isEmpty())
+        {
+            temp += "OtherName:\n";
+            temp += stringifyOtherNameCollection(excludedSubtreesOtherName) + "\n";
+        }
+        return temp;
+    }
+
+    private void checkPermittedDN(X500Name dns)
+        throws NameConstraintValidatorException
+    {
+        checkPermittedDN(permittedSubtreesDN, ASN1Sequence.getInstance(dns.toASN1Primitive()));
+    }
+
+    private void checkExcludedDN(X500Name dns)
+        throws NameConstraintValidatorException
+    {
+        checkExcludedDN(excludedSubtreesDN, ASN1Sequence.getInstance(dns));
+    }
+
+    private static boolean withinDNSubtree(
+        ASN1Sequence dns,
+        ASN1Sequence subtree)
+    {
+        if (subtree.size() < 1)
+        {
+            return false;
+        }
+
+        if (subtree.size() > dns.size())
+        {
+            return false;
+        }
+
+        for (int j = subtree.size() - 1; j >= 0; j--)
+        {
+            if (!subtree.getObjectAt(j).equals(dns.getObjectAt(j)))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private void checkPermittedDN(Set permitted, ASN1Sequence dns)
+        throws NameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        if (permitted.isEmpty() && dns.size() == 0)
+        {
+            return;
+        }
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+            if (withinDNSubtree(dns, subtree))
+            {
+                return;
+            }
+        }
+
+        throw new NameConstraintValidatorException(
+            "Subject distinguished name is not from a permitted subtree");
+    }
+
+    private void checkExcludedDN(Set excluded, ASN1Sequence dns)
+        throws NameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+            if (withinDNSubtree(dns, subtree))
+            {
+                throw new NameConstraintValidatorException(
+                    "Subject distinguished name is from an excluded subtree");
+            }
+        }
+    }
+
+    private Set intersectDN(Set permitted, Set dns)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = dns.iterator(); it.hasNext(); )
+        {
+            ASN1Sequence dn = ASN1Sequence.getInstance(((GeneralSubtree)it
+                .next()).getBase().getName().toASN1Primitive());
+            if (permitted == null)
+            {
+                if (dn != null)
+                {
+                    intersect.add(dn);
+                }
+            }
+            else
+            {
+                Iterator _iter = permitted.iterator();
+                while (_iter.hasNext())
+                {
+                    ASN1Sequence subtree = (ASN1Sequence)_iter.next();
+
+                    if (withinDNSubtree(dn, subtree))
+                    {
+                        intersect.add(dn);
+                    }
+                    else if (withinDNSubtree(subtree, dn))
+                    {
+                        intersect.add(subtree);
+                    }
+                }
+            }
+        }
+        return intersect;
+    }
+
+    private Set unionDN(Set excluded, ASN1Sequence dn)
+    {
+        if (excluded.isEmpty())
+        {
+            if (dn == null)
+            {
+                return excluded;
+            }
+            excluded.add(dn);
+
+            return excluded;
+        }
+        else
+        {
+            Set intersect = new HashSet();
+
+            Iterator it = excluded.iterator();
+            while (it.hasNext())
+            {
+                ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+                if (withinDNSubtree(dn, subtree))
+                {
+                    intersect.add(subtree);
+                }
+                else if (withinDNSubtree(subtree, dn))
+                {
+                    intersect.add(dn);
+                }
+                else
+                {
+                    intersect.add(subtree);
+                    intersect.add(dn);
+                }
+            }
+
+            return intersect;
+        }
+    }
+
+    private Set intersectOtherName(Set permitted, Set otherNames)
+    {
+        Set intersect = new HashSet(permitted);
+
+        intersect.retainAll(otherNames);
+
+        return intersect;
+    }
+
+
+    private Set unionOtherName(Set permitted, OtherName otherName)
+    {
+        Set union = new HashSet(permitted);
+
+        union.add(otherName);
+
+        return union;
+    }
+
+    private Set intersectEmail(Set permitted, Set emails)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = emails.iterator(); it.hasNext(); )
+        {
+            String email = extractNameAsString(((GeneralSubtree)it.next())
+                .getBase());
+
+            if (permitted == null)
+            {
+                if (email != null)
+                {
+                    intersect.add(email);
+                }
+            }
+            else
+            {
+                Iterator it2 = permitted.iterator();
+                while (it2.hasNext())
+                {
+                    String _permitted = (String)it2.next();
+
+                    intersectEmail(email, _permitted, intersect);
+                }
+            }
+        }
+        return intersect;
+    }
+
+    private Set unionEmail(Set excluded, String email)
+    {
+        if (excluded.isEmpty())
+        {
+            if (email == null)
+            {
+                return excluded;
+            }
+            excluded.add(email);
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator it = excluded.iterator();
+            while (it.hasNext())
+            {
+                String _excluded = (String)it.next();
+
+                unionEmail(_excluded, email, union);
+            }
+
+            return union;
+        }
+    }
+
+    /**
+     * Returns the intersection of the permitted IP ranges in
+     * <code>permitted</code> with <code>ip</code>.
+     *
+     * @param permitted A <code>Set</code> of permitted IP addresses with
+     *                  their subnet mask as byte arrays.
+     * @param ips       The IP address with its subnet mask.
+     * @return The <code>Set</code> of permitted IP ranges intersected with
+     * <code>ip</code>.
+     */
+    private Set intersectIP(Set permitted, Set ips)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = ips.iterator(); it.hasNext(); )
+        {
+            byte[] ip = ASN1OctetString.getInstance(
+                ((GeneralSubtree)it.next()).getBase().getName()).getOctets();
+            if (permitted == null)
+            {
+                if (ip != null)
+                {
+                    intersect.add(ip);
+                }
+            }
+            else
+            {
+                Iterator it2 = permitted.iterator();
+                while (it2.hasNext())
+                {
+                    byte[] _permitted = (byte[])it2.next();
+                    intersect.addAll(intersectIPRange(_permitted, ip));
+                }
+            }
+        }
+        return intersect;
+    }
+
+    /**
+     * Returns the union of the excluded IP ranges in <code>excluded</code>
+     * with <code>ip</code>.
+     *
+     * @param excluded A <code>Set</code> of excluded IP addresses with their
+     *                 subnet mask as byte arrays.
+     * @param ip       The IP address with its subnet mask.
+     * @return The <code>Set</code> of excluded IP ranges unified with
+     * <code>ip</code> as byte arrays.
+     */
+    private Set unionIP(Set excluded, byte[] ip)
+    {
+        if (excluded.isEmpty())
+        {
+            if (ip == null)
+            {
+                return excluded;
+            }
+            excluded.add(ip);
+
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator it = excluded.iterator();
+            while (it.hasNext())
+            {
+                byte[] _excluded = (byte[])it.next();
+                union.addAll(unionIPRange(_excluded, ip));
+            }
+
+            return union;
+        }
+    }
+
+    /**
+     * Calculates the union if two IP ranges.
+     *
+     * @param ipWithSubmask1 The first IP address with its subnet mask.
+     * @param ipWithSubmask2 The second IP address with its subnet mask.
+     * @return A <code>Set</code> with the union of both addresses.
+     */
+    private Set unionIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+    {
+        Set set = new HashSet();
+
+        // difficult, adding always all IPs is not wrong
+        if (Arrays.areEqual(ipWithSubmask1, ipWithSubmask2))
+        {
+            set.add(ipWithSubmask1);
+        }
+        else
+        {
+            set.add(ipWithSubmask1);
+            set.add(ipWithSubmask2);
+        }
+        return set;
+    }
+
+    /**
+     * Calculates the interesction if two IP ranges.
+     *
+     * @param ipWithSubmask1 The first IP address with its subnet mask.
+     * @param ipWithSubmask2 The second IP address with its subnet mask.
+     * @return A <code>Set</code> with the single IP address with its subnet
+     * mask as a byte array or an empty <code>Set</code>.
+     */
+    private Set intersectIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+    {
+        if (ipWithSubmask1.length != ipWithSubmask2.length)
+        {
+            return Collections.EMPTY_SET;
+        }
+        byte[][] temp = extractIPsAndSubnetMasks(ipWithSubmask1, ipWithSubmask2);
+        byte ip1[] = temp[0];
+        byte subnetmask1[] = temp[1];
+        byte ip2[] = temp[2];
+        byte subnetmask2[] = temp[3];
+
+        byte minMax[][] = minMaxIPs(ip1, subnetmask1, ip2, subnetmask2);
+        byte[] min;
+        byte[] max;
+        max = min(minMax[1], minMax[3]);
+        min = max(minMax[0], minMax[2]);
+
+        // minimum IP address must be bigger than max
+        if (compareTo(min, max) == 1)
+        {
+            return Collections.EMPTY_SET;
+        }
+        // OR keeps all significant bits
+        byte[] ip = or(minMax[0], minMax[2]);
+        byte[] subnetmask = or(subnetmask1, subnetmask2);
+        return Collections.singleton(ipWithSubnetMask(ip, subnetmask));
+    }
+
+    /**
+     * Concatenates the IP address with its subnet mask.
+     *
+     * @param ip         The IP address.
+     * @param subnetMask Its subnet mask.
+     * @return The concatenated IP address with its subnet mask.
+     */
+    private byte[] ipWithSubnetMask(byte[] ip, byte[] subnetMask)
+    {
+        int ipLength = ip.length;
+        byte[] temp = new byte[ipLength * 2];
+        System.arraycopy(ip, 0, temp, 0, ipLength);
+        System.arraycopy(subnetMask, 0, temp, ipLength, ipLength);
+        return temp;
+    }
+
+    /**
+     * Splits the IP addresses and their subnet mask.
+     *
+     * @param ipWithSubmask1 The first IP address with the subnet mask.
+     * @param ipWithSubmask2 The second IP address with the subnet mask.
+     * @return An array with two elements. Each element contains the IP address
+     * and the subnet mask in this order.
+     */
+    private byte[][] extractIPsAndSubnetMasks(
+        byte[] ipWithSubmask1,
+        byte[] ipWithSubmask2)
+    {
+        int ipLength = ipWithSubmask1.length / 2;
+        byte ip1[] = new byte[ipLength];
+        byte subnetmask1[] = new byte[ipLength];
+        System.arraycopy(ipWithSubmask1, 0, ip1, 0, ipLength);
+        System.arraycopy(ipWithSubmask1, ipLength, subnetmask1, 0, ipLength);
+
+        byte ip2[] = new byte[ipLength];
+        byte subnetmask2[] = new byte[ipLength];
+        System.arraycopy(ipWithSubmask2, 0, ip2, 0, ipLength);
+        System.arraycopy(ipWithSubmask2, ipLength, subnetmask2, 0, ipLength);
+        return new byte[][]
+            {ip1, subnetmask1, ip2, subnetmask2};
+    }
+
+    /**
+     * Based on the two IP addresses and their subnet masks the IP range is
+     * computed for each IP address - subnet mask pair and returned as the
+     * minimum IP address and the maximum address of the range.
+     *
+     * @param ip1         The first IP address.
+     * @param subnetmask1 The subnet mask of the first IP address.
+     * @param ip2         The second IP address.
+     * @param subnetmask2 The subnet mask of the second IP address.
+     * @return A array with two elements. The first/second element contains the
+     * min and max IP address of the first/second IP address and its
+     * subnet mask.
+     */
+    private byte[][] minMaxIPs(
+        byte[] ip1,
+        byte[] subnetmask1,
+        byte[] ip2,
+        byte[] subnetmask2)
+    {
+        int ipLength = ip1.length;
+        byte[] min1 = new byte[ipLength];
+        byte[] max1 = new byte[ipLength];
+
+        byte[] min2 = new byte[ipLength];
+        byte[] max2 = new byte[ipLength];
+
+        for (int i = 0; i < ipLength; i++)
+        {
+            min1[i] = (byte)(ip1[i] & subnetmask1[i]);
+            max1[i] = (byte)(ip1[i] & subnetmask1[i] | ~subnetmask1[i]);
+
+            min2[i] = (byte)(ip2[i] & subnetmask2[i]);
+            max2[i] = (byte)(ip2[i] & subnetmask2[i] | ~subnetmask2[i]);
+        }
+
+        return new byte[][]{min1, max1, min2, max2};
+    }
+
+    private void checkPermittedEmail(Set permitted, String email)
+        throws NameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            if (emailIsConstrained(email, str))
+            {
+                return;
+            }
+        }
+
+        if (email.length() == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+
+        throw new NameConstraintValidatorException(
+            "Subject email address is not from a permitted subtree.");
+    }
+
+    private void checkPermittedOtherName(Set permitted, OtherName name)
+        throws NameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            OtherName str = ((OtherName)it.next());
+
+            if (otherNameIsConstrained(name, str))
+            {
+                return;
+            }
+        }
+
+        throw new NameConstraintValidatorException(
+            "Subject OtherName is not from a permitted subtree.");
+    }
+
+    private void checkExcludedOtherName(Set excluded, OtherName name)
+        throws NameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            OtherName str = OtherName.getInstance(it.next());
+
+            if (otherNameIsConstrained(name, str))
+            {
+                throw new NameConstraintValidatorException(
+                    "OtherName is from an excluded subtree.");
+            }
+        }
+    }
+
+    private void checkExcludedEmail(Set excluded, String email)
+        throws NameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            String str = (String)it.next();
+
+            if (emailIsConstrained(email, str))
+            {
+                throw new NameConstraintValidatorException(
+                    "Email address is from an excluded subtree.");
+            }
+        }
+    }
+
+    /**
+     * Checks if the IP <code>ip</code> is included in the permitted set
+     * <code>permitted</code>.
+     *
+     * @param permitted A <code>Set</code> of permitted IP addresses with
+     *                  their subnet mask as byte arrays.
+     * @param ip        The IP address.
+     * @throws NameConstraintValidatorException if the IP is not permitted.
+     */
+    private void checkPermittedIP(Set permitted, byte[] ip)
+        throws NameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            byte[] ipWithSubnet = (byte[])it.next();
+
+            if (isIPConstrained(ip, ipWithSubnet))
+            {
+                return;
+            }
+        }
+        if (ip.length == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+        throw new NameConstraintValidatorException(
+            "IP is not from a permitted subtree.");
+    }
+
+    /**
+     * Checks if the IP <code>ip</code> is included in the excluded set
+     * <code>excluded</code>.
+     *
+     * @param excluded A <code>Set</code> of excluded IP addresses with their
+     *                 subnet mask as byte arrays.
+     * @param ip       The IP address.
+     * @throws NameConstraintValidatorException if the IP is excluded.
+     */
+    private void checkExcludedIP(Set excluded, byte[] ip)
+        throws NameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            byte[] ipWithSubnet = (byte[])it.next();
+
+            if (isIPConstrained(ip, ipWithSubnet))
+            {
+                throw new NameConstraintValidatorException(
+                    "IP is from an excluded subtree.");
+            }
+        }
+    }
+
+    /**
+     * Checks if the IP address <code>ip</code> is constrained by
+     * <code>constraint</code>.
+     *
+     * @param ip         The IP address.
+     * @param constraint The constraint. This is an IP address concatenated with
+     *                   its subnetmask.
+     * @return <code>true</code> if constrained, <code>false</code>
+     * otherwise.
+     */
+    private boolean isIPConstrained(byte ip[], byte[] constraint)
+    {
+        int ipLength = ip.length;
+
+        if (ipLength != (constraint.length / 2))
+        {
+            return false;
+        }
+
+        byte[] subnetMask = new byte[ipLength];
+        System.arraycopy(constraint, ipLength, subnetMask, 0, ipLength);
+
+        byte[] permittedSubnetAddress = new byte[ipLength];
+
+        byte[] ipSubnetAddress = new byte[ipLength];
+
+        // the resulting IP address by applying the subnet mask
+        for (int i = 0; i < ipLength; i++)
+        {
+            permittedSubnetAddress[i] = (byte)(constraint[i] & subnetMask[i]);
+            ipSubnetAddress[i] = (byte)(ip[i] & subnetMask[i]);
+        }
+
+        return Arrays.areEqual(permittedSubnetAddress, ipSubnetAddress);
+    }
+
+    private boolean otherNameIsConstrained(OtherName name, OtherName constraint)
+    {
+        if (constraint.equals(name))
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    private boolean emailIsConstrained(String email, String constraint)
+    {
+        String sub = email.substring(email.indexOf('@') + 1);
+        // a particular mailbox
+        if (constraint.indexOf('@') != -1)
+        {
+            if (email.equalsIgnoreCase(constraint))
+            {
+                return true;
+            }
+        }
+        // on particular host
+        else if (!(constraint.charAt(0) == '.'))
+        {
+            if (sub.equalsIgnoreCase(constraint))
+            {
+                return true;
+            }
+        }
+        // address in sub domain
+        else if (withinDomain(sub, constraint))
+        {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean withinDomain(String testDomain, String domain)
+    {
+        String tempDomain = domain;
+        if (tempDomain.startsWith("."))
+        {
+            tempDomain = tempDomain.substring(1);
+        }
+        String[] domainParts = Strings.split(tempDomain, '.');
+        String[] testDomainParts = Strings.split(testDomain, '.');
+        // must have at least one subdomain
+        if (testDomainParts.length <= domainParts.length)
+        {
+            return false;
+        }
+        int d = testDomainParts.length - domainParts.length;
+        for (int i = -1; i < domainParts.length; i++)
+        {
+            if (i == -1)
+            {
+                if (testDomainParts[i + d].equals(""))
+                {
+                    return false;
+                }
+            }
+            else if (!domainParts[i].equalsIgnoreCase(testDomainParts[i + d]))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void checkPermittedDNS(Set permitted, String dns)
+        throws NameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            // is sub domain
+            if (withinDomain(dns, str) || dns.equalsIgnoreCase(str))
+            {
+                return;
+            }
+        }
+        if (dns.length() == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+        throw new NameConstraintValidatorException(
+            "DNS is not from a permitted subtree.");
+    }
+
+    private void checkExcludedDNS(Set excluded, String dns)
+        throws NameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            // is sub domain or the same
+            if (withinDomain(dns, str) || dns.equalsIgnoreCase(str))
+            {
+                throw new NameConstraintValidatorException(
+                    "DNS is from an excluded subtree.");
+            }
+        }
+    }
+
+    /**
+     * The common part of <code>email1</code> and <code>email2</code> is
+     * added to the union <code>union</code>. If <code>email1</code> and
+     * <code>email2</code> have nothing in common they are added both.
+     *
+     * @param email1 Email address constraint 1.
+     * @param email2 Email address constraint 2.
+     * @param union  The union.
+     */
+    private void unionEmail(String email1, String email2, Set union)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email1 specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+    }
+
+    private void unionURI(String email1, String email2, Set union)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email1 specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+    }
+
+    private Set intersectDNS(Set permitted, Set dnss)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = dnss.iterator(); it.hasNext(); )
+        {
+            String dns = extractNameAsString(((GeneralSubtree)it.next())
+                .getBase());
+            if (permitted == null)
+            {
+                if (dns != null)
+                {
+                    intersect.add(dns);
+                }
+            }
+            else
+            {
+                Iterator _iter = permitted.iterator();
+                while (_iter.hasNext())
+                {
+                    String _permitted = (String)_iter.next();
+
+                    if (withinDomain(_permitted, dns))
+                    {
+                        intersect.add(_permitted);
+                    }
+                    else if (withinDomain(dns, _permitted))
+                    {
+                        intersect.add(dns);
+                    }
+                }
+            }
+        }
+
+        return intersect;
+    }
+
+    private Set unionDNS(Set excluded, String dns)
+    {
+        if (excluded.isEmpty())
+        {
+            if (dns == null)
+            {
+                return excluded;
+            }
+            excluded.add(dns);
+
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator _iter = excluded.iterator();
+            while (_iter.hasNext())
+            {
+                String _permitted = (String)_iter.next();
+
+                if (withinDomain(_permitted, dns))
+                {
+                    union.add(dns);
+                }
+                else if (withinDomain(dns, _permitted))
+                {
+                    union.add(_permitted);
+                }
+                else
+                {
+                    union.add(_permitted);
+                    union.add(dns);
+                }
+            }
+
+            return union;
+        }
+    }
+
+    /**
+     * The most restricting part from <code>email1</code> and
+     * <code>email2</code> is added to the intersection <code>intersect</code>.
+     *
+     * @param email1    Email address constraint 1.
+     * @param email2    Email address constraint 2.
+     * @param intersect The intersection.
+     */
+    private void intersectEmail(String email1, String email2, Set intersect)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+        // email specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+        }
+        // email1 specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email2.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+    }
+
+    private void checkExcludedURI(Set excluded, String uri)
+        throws NameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            if (isUriConstrained(uri, str))
+            {
+                throw new NameConstraintValidatorException(
+                    "URI is from an excluded subtree.");
+            }
+        }
+    }
+
+    private Set intersectURI(Set permitted, Set uris)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = uris.iterator(); it.hasNext(); )
+        {
+            String uri = extractNameAsString(((GeneralSubtree)it.next())
+                .getBase());
+            if (permitted == null)
+            {
+                if (uri != null)
+                {
+                    intersect.add(uri);
+                }
+            }
+            else
+            {
+                Iterator _iter = permitted.iterator();
+                while (_iter.hasNext())
+                {
+                    String _permitted = (String)_iter.next();
+                    intersectURI(_permitted, uri, intersect);
+                }
+            }
+        }
+        return intersect;
+    }
+
+    private Set unionURI(Set excluded, String uri)
+    {
+        if (excluded.isEmpty())
+        {
+            if (uri == null)
+            {
+                return excluded;
+            }
+            excluded.add(uri);
+
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator _iter = excluded.iterator();
+            while (_iter.hasNext())
+            {
+                String _excluded = (String)_iter.next();
+
+                unionURI(_excluded, uri, union);
+            }
+
+            return union;
+        }
+    }
+
+    private void intersectURI(String email1, String email2, Set intersect)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+        // email specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+        }
+        // email1 specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email2.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+    }
+
+    private void checkPermittedURI(Set permitted, String uri)
+        throws NameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            if (isUriConstrained(uri, str))
+            {
+                return;
+            }
+        }
+        if (uri.length() == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+        throw new NameConstraintValidatorException(
+            "URI is not from a permitted subtree.");
+    }
+
+    private boolean isUriConstrained(String uri, String constraint)
+    {
+        String host = extractHostFromURL(uri);
+        // a host
+        if (!constraint.startsWith("."))
+        {
+            if (host.equalsIgnoreCase(constraint))
+            {
+                return true;
+            }
+        }
+
+        // in sub domain or domain
+        else if (withinDomain(host, constraint))
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    private static String extractHostFromURL(String url)
+    {
+        // see RFC 1738
+        // remove ':' after protocol, e.g. http:
+        String sub = url.substring(url.indexOf(':') + 1);
+        // extract host from Common Internet Scheme Syntax, e.g. http://
+        if (sub.indexOf("//") != -1)
+        {
+            sub = sub.substring(sub.indexOf("//") + 2);
+        }
+        // first remove port, e.g. http://test.com:21
+        if (sub.lastIndexOf(':') != -1)
+        {
+            sub = sub.substring(0, sub.lastIndexOf(':'));
+        }
+        // remove user and password, e.g. http://john:password@test.com
+        sub = sub.substring(sub.indexOf(':') + 1);
+        sub = sub.substring(sub.indexOf('@') + 1);
+        // remove local parts, e.g. http://test.com/bla
+        if (sub.indexOf('/') != -1)
+        {
+            sub = sub.substring(0, sub.indexOf('/'));
+        }
+        return sub;
+    }
+
+    private String extractNameAsString(GeneralName name)
+    {
+        return DERIA5String.getInstance(name.getName()).getString();
+    }
+
+    /**
+     * Returns the maximum IP address.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return The maximum IP address.
+     */
+    private static byte[] max(byte[] ip1, byte[] ip2)
+    {
+        for (int i = 0; i < ip1.length; i++)
+        {
+            if ((ip1[i] & 0xFFFF) > (ip2[i] & 0xFFFF))
+            {
+                return ip1;
+            }
+        }
+        return ip2;
+    }
+
+    /**
+     * Returns the minimum IP address.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return The minimum IP address.
+     */
+    private static byte[] min(byte[] ip1, byte[] ip2)
+    {
+        for (int i = 0; i < ip1.length; i++)
+        {
+            if ((ip1[i] & 0xFFFF) < (ip2[i] & 0xFFFF))
+            {
+                return ip1;
+            }
+        }
+        return ip2;
+    }
+
+    /**
+     * Compares IP address <code>ip1</code> with <code>ip2</code>. If ip1
+     * is equal to ip2 0 is returned. If ip1 is bigger 1 is returned, -1
+     * otherwise.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return 0 if ip1 is equal to ip2, 1 if ip1 is bigger, -1 otherwise.
+     */
+    private static int compareTo(byte[] ip1, byte[] ip2)
+    {
+        if (Arrays.areEqual(ip1, ip2))
+        {
+            return 0;
+        }
+        if (Arrays.areEqual(max(ip1, ip2), ip1))
+        {
+            return 1;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the logical OR of the IP addresses <code>ip1</code> and
+     * <code>ip2</code>.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return The OR of <code>ip1</code> and <code>ip2</code>.
+     */
+    private static byte[] or(byte[] ip1, byte[] ip2)
+    {
+        byte[] temp = new byte[ip1.length];
+        for (int i = 0; i < ip1.length; i++)
+        {
+            temp[i] = (byte)(ip1[i] | ip2[i]);
+        }
+        return temp;
+    }
+
+    private int hashCollection(Collection coll)
+    {
+        if (coll == null)
+        {
+            return 0;
+        }
+        int hash = 0;
+        Iterator it1 = coll.iterator();
+        while (it1.hasNext())
+        {
+            Object o = it1.next();
+            if (o instanceof byte[])
+            {
+                hash += Arrays.hashCode((byte[])o);
+            }
+            else
+            {
+                hash += o.hashCode();
+            }
+        }
+        return hash;
+    }
+
+    private boolean collectionsAreEqual(Collection coll1, Collection coll2)
+    {
+        if (coll1 == coll2)
+        {
+            return true;
+        }
+        if (coll1 == null || coll2 == null)
+        {
+            return false;
+        }
+        if (coll1.size() != coll2.size())
+        {
+            return false;
+        }
+        Iterator it1 = coll1.iterator();
+
+        while (it1.hasNext())
+        {
+            Object a = it1.next();
+            Iterator it2 = coll2.iterator();
+            boolean found = false;
+            while (it2.hasNext())
+            {
+                Object b = it2.next();
+                if (equals(a, b))
+                {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean equals(Object o1, Object o2)
+    {
+        if (o1 == o2)
+        {
+            return true;
+        }
+        if (o1 == null || o2 == null)
+        {
+            return false;
+        }
+        if (o1 instanceof byte[] && o2 instanceof byte[])
+        {
+            return Arrays.areEqual((byte[])o1, (byte[])o2);
+        }
+        else
+        {
+            return o1.equals(o2);
+        }
+    }
+
+    /**
+     * Stringifies an IPv4 or v6 address with subnet mask.
+     *
+     * @param ip The IP with subnet mask.
+     * @return The stringified IP address.
+     */
+    private String stringifyIP(byte[] ip)
+    {
+        StringBuilder temp = new StringBuilder();
+        for (int i = 0; i < ip.length / 2; i++)
+        {
+            if (temp.length() > 0)
+            {
+                temp.append(".");
+            }
+            temp.append(Integer.toString(ip[i] & 0x00FF));
+        }
+
+        temp.append("/");
+        boolean first = true;
+        for (int i = ip.length / 2; i < ip.length; i++)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                temp.append(".");
+            }
+            temp.append(Integer.toString(ip[i] & 0x00FF));
+        }
+
+        return temp.toString();
+    }
+
+    private String stringifyIPCollection(Set ips)
+    {
+        StringBuilder temp = new StringBuilder();
+        temp.append("[");
+        for (Iterator it = ips.iterator(); it.hasNext(); )
+        {
+            if (temp.length() > 1)
+            {
+                temp.append(",");
+            }
+            temp.append(stringifyIP((byte[])it.next()));
+        }
+        temp.append("]");
+        return temp.toString();
+    }
+
+    private String stringifyOtherNameCollection(Set otherNames)
+    {
+        StringBuilder temp = new StringBuilder();
+        temp.append("[");
+        for (Iterator it = otherNames.iterator(); it.hasNext(); )
+        {
+            if (temp.length() > 1)
+            {
+                temp.append(",");
+            }
+            OtherName name = OtherName.getInstance(it.next());
+            temp.append(name.getTypeID().getId());
+            temp.append(":");
+            try
+            {
+                temp.append(Hex.toHexString(name.getValue().toASN1Primitive().getEncoded()));
+            }
+            catch (IOException e)
+            {
+                temp.append(e.toString());
+            }
+        }
+        temp.append("]");
+        return temp.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyConstraints.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyConstraints.java
new file mode 100644
index 0000000..3a81af5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyConstraints.java
@@ -0,0 +1,108 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * PKIX RFC 5280
+ * <pre>
+ * id-ce-policyConstraints OBJECT IDENTIFIER ::=  { id-ce 36 }
+ *
+ * PolicyConstraints ::= SEQUENCE {
+ *      requireExplicitPolicy           [0] SkipCerts OPTIONAL,
+ *      inhibitPolicyMapping            [1] SkipCerts OPTIONAL }
+ *
+ * SkipCerts ::= INTEGER (0..MAX)
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PolicyConstraints
+    extends ASN1Object
+{
+    private BigInteger requireExplicitPolicyMapping;
+    private BigInteger inhibitPolicyMapping;
+
+    public PolicyConstraints(BigInteger requireExplicitPolicyMapping, BigInteger inhibitPolicyMapping)
+    {
+        this.requireExplicitPolicyMapping = requireExplicitPolicyMapping;
+        this.inhibitPolicyMapping = inhibitPolicyMapping;
+    }
+
+    private PolicyConstraints(ASN1Sequence seq)
+    {
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject to = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+
+            if (to.getTagNo() == 0)
+            {
+                requireExplicitPolicyMapping = ASN1Integer.getInstance(to, false).getValue();
+            }
+            else if (to.getTagNo() == 1)
+            {
+                inhibitPolicyMapping = ASN1Integer.getInstance(to, false).getValue();
+            }
+            else
+            {
+                throw new IllegalArgumentException("Unknown tag encountered.");
+            }
+        }
+    }
+
+    public static PolicyConstraints getInstance(
+        Object  obj)
+    {
+        if (obj instanceof PolicyConstraints)
+        {
+            return (PolicyConstraints)obj;
+        }
+
+        if (obj != null)
+        {
+            return new PolicyConstraints(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static PolicyConstraints fromExtensions(Extensions extensions)
+    {
+        return PolicyConstraints.getInstance(extensions.getExtensionParsedValue(Extension.policyConstraints));
+    }
+
+    public BigInteger getRequireExplicitPolicyMapping()
+    {
+        return requireExplicitPolicyMapping;
+    }
+
+    public BigInteger getInhibitPolicyMapping()
+    {
+        return inhibitPolicyMapping;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        if (requireExplicitPolicyMapping != null)
+        {
+            v.add(new DERTaggedObject(false,0, new ASN1Integer(requireExplicitPolicyMapping)));
+        }
+
+        if (inhibitPolicyMapping != null)
+        {
+            v.add(new DERTaggedObject(false, 1, new ASN1Integer(inhibitPolicyMapping)));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyInformation.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyInformation.java
new file mode 100644
index 0000000..aee5ef8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyInformation.java
@@ -0,0 +1,120 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PolicyInformation
+    extends ASN1Object
+{
+    private ASN1ObjectIdentifier   policyIdentifier;
+    private ASN1Sequence          policyQualifiers;
+
+    private PolicyInformation(
+        ASN1Sequence seq)
+    {
+        if (seq.size() < 1 || seq.size() > 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        policyIdentifier = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+
+        if (seq.size() > 1)
+        {
+            policyQualifiers = ASN1Sequence.getInstance(seq.getObjectAt(1));
+        }
+    }
+
+    public PolicyInformation(
+        ASN1ObjectIdentifier policyIdentifier)
+    {
+        this.policyIdentifier = policyIdentifier;
+    }
+
+    public PolicyInformation(
+        ASN1ObjectIdentifier policyIdentifier,
+        ASN1Sequence        policyQualifiers)
+    {
+        this.policyIdentifier = policyIdentifier;
+        this.policyQualifiers = policyQualifiers;
+    }
+
+    public static PolicyInformation getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof PolicyInformation)
+        {
+            return (PolicyInformation)obj;
+        }
+
+        return new PolicyInformation(ASN1Sequence.getInstance(obj));
+    }
+
+    public ASN1ObjectIdentifier getPolicyIdentifier()
+    {
+        return policyIdentifier;
+    }
+    
+    public ASN1Sequence getPolicyQualifiers()
+    {
+        return policyQualifiers;
+    }
+    
+    /*
+     * <pre>
+     * PolicyInformation ::= SEQUENCE {
+     *      policyIdentifier   CertPolicyId,
+     *      policyQualifiers   SEQUENCE SIZE (1..MAX) OF
+     *              PolicyQualifierInfo OPTIONAL }
+     * </pre>
+     */ 
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        v.add(policyIdentifier);
+
+        if (policyQualifiers != null)
+        {
+            v.add(policyQualifiers);
+        }
+        
+        return new DERSequence(v);
+    }
+
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append("Policy information: ");
+        sb.append(policyIdentifier);
+
+        if (policyQualifiers != null)
+        {
+            StringBuffer p = new StringBuffer();
+            for (int i = 0; i < policyQualifiers.size(); i++)
+            {
+                if (p.length() != 0)
+                {
+                    p.append(", ");
+                }
+                p.append(PolicyQualifierInfo.getInstance(policyQualifiers.getObjectAt(i)));
+            }
+
+            sb.append("[");
+            sb.append(p);
+            sb.append("]");
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyQualifierId.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyQualifierId.java
new file mode 100644
index 0000000..e956144
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyQualifierId.java
@@ -0,0 +1,33 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * PolicyQualifierId, used in the CertificatePolicies
+ * X509V3 extension.
+ * 
+ * <pre>
+ *    id-qt          OBJECT IDENTIFIER ::=  { id-pkix 2 }
+ *    id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
+ *    id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }
+ *  PolicyQualifierId ::=
+ *       OBJECT IDENTIFIER (id-qt-cps | id-qt-unotice)
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PolicyQualifierId extends ASN1ObjectIdentifier 
+{
+   private static final String id_qt = "1.3.6.1.5.5.7.2";
+
+   private PolicyQualifierId(String id) 
+      {
+         super(id);
+      }
+   
+   public static final PolicyQualifierId id_qt_cps =
+       new PolicyQualifierId(id_qt + ".1");
+   public static final PolicyQualifierId id_qt_unotice =
+       new PolicyQualifierId(id_qt + ".2");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java
new file mode 100644
index 0000000..8126c4c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java
@@ -0,0 +1,119 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * Policy qualifiers, used in the X509V3 CertificatePolicies
+ * extension.
+ * 
+ * <pre>
+ *   PolicyQualifierInfo ::= SEQUENCE {
+ *       policyQualifierId  PolicyQualifierId,
+ *       qualifier          ANY DEFINED BY policyQualifierId }
+ *
+ *  PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PolicyQualifierInfo
+    extends ASN1Object
+{
+   private ASN1ObjectIdentifier policyQualifierId;
+   private ASN1Encodable        qualifier;
+
+   /**
+    * Creates a new <code>PolicyQualifierInfo</code> instance.
+    *
+    * @param policyQualifierId a <code>PolicyQualifierId</code> value
+    * @param qualifier the qualifier, defined by the above field.
+    */
+   public PolicyQualifierInfo(
+       ASN1ObjectIdentifier policyQualifierId,
+       ASN1Encodable qualifier) 
+   {
+      this.policyQualifierId = policyQualifierId;
+      this.qualifier = qualifier;
+   }
+
+   /**
+    * Creates a new <code>PolicyQualifierInfo</code> containing a
+    * cPSuri qualifier.
+    *
+    * @param cps the CPS (certification practice statement) uri as a
+    * <code>String</code>.
+    */
+   public PolicyQualifierInfo(
+       String cps) 
+   {
+      policyQualifierId = PolicyQualifierId.id_qt_cps;
+      qualifier = new DERIA5String (cps);
+   }
+
+   /**
+    * Creates a new <code>PolicyQualifierInfo</code> instance.
+    *
+    * @param as <code>PolicyQualifierInfo</code> X509 structure
+    * encoded as an ASN1Sequence.
+    * @deprecated use PolicyQualifierInfo.getInstance()
+    */
+   public PolicyQualifierInfo(
+       ASN1Sequence as)
+   {
+        if (as.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + as.size());
+        }
+
+        policyQualifierId = ASN1ObjectIdentifier.getInstance(as.getObjectAt(0));
+        qualifier = as.getObjectAt(1);
+   }
+
+   public static PolicyQualifierInfo getInstance(
+       Object obj)
+   {
+        if (obj instanceof PolicyQualifierInfo)
+        {
+            return (PolicyQualifierInfo)obj;
+        }
+        else if (obj != null)
+        {
+            return new PolicyQualifierInfo(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+   }
+
+
+   public ASN1ObjectIdentifier getPolicyQualifierId()
+   {
+       return policyQualifierId;
+   }
+
+   public ASN1Encodable getQualifier()
+   {
+       return qualifier;
+   }
+   
+   /**
+    * Returns a DER-encodable representation of this instance. 
+    *
+    * @return a <code>ASN1Primitive</code> value
+    */
+   public ASN1Primitive toASN1Primitive()
+   {
+      ASN1EncodableVector dev = new ASN1EncodableVector();
+      dev.add(policyQualifierId);
+      dev.add(qualifier);
+
+      return new DERSequence(dev);
+   }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
new file mode 100644
index 0000000..bd676a1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
@@ -0,0 +1,100 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @deprecated use org.bouncycastle.asn1.pkcs.RSAPublicKey
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSAPublicKeyStructure
+    extends ASN1Object
+{
+    private BigInteger  modulus;
+    private BigInteger  publicExponent;
+
+    public static RSAPublicKeyStructure getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static RSAPublicKeyStructure getInstance(
+        Object obj)
+    {
+        if(obj == null || obj instanceof RSAPublicKeyStructure) 
+        {
+            return (RSAPublicKeyStructure)obj;
+        }
+        
+        if(obj instanceof ASN1Sequence) 
+        {
+            return new RSAPublicKeyStructure((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid RSAPublicKeyStructure: " + obj.getClass().getName());
+    }
+    
+    public RSAPublicKeyStructure(
+        BigInteger  modulus,
+        BigInteger  publicExponent)
+    {
+        this.modulus = modulus;
+        this.publicExponent = publicExponent;
+    }
+
+    public RSAPublicKeyStructure(
+        ASN1Sequence  seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        Enumeration e = seq.getObjects();
+
+        modulus = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
+        publicExponent = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
+    }
+
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    /**
+     * This outputs the key in PKCS1v2 format.
+     * <pre>
+     *      RSAPublicKey ::= SEQUENCE {
+     *                          modulus INTEGER, -- n
+     *                          publicExponent INTEGER, -- e
+     *                      }
+     * </pre>
+     * <p>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(getModulus()));
+        v.add(new ASN1Integer(getPublicExponent()));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ReasonFlags.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ReasonFlags.java
new file mode 100644
index 0000000..ecb4416
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/ReasonFlags.java
@@ -0,0 +1,87 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+
+/**
+ * The ReasonFlags object.
+ * <pre>
+ * ReasonFlags ::= BIT STRING {
+ *      unused                  (0),
+ *      keyCompromise           (1),
+ *      cACompromise            (2),
+ *      affiliationChanged      (3),
+ *      superseded              (4),
+ *      cessationOfOperation    (5),
+ *      certificateHold         (6),
+ *      privilegeWithdrawn      (7),
+ *      aACompromise            (8) }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ReasonFlags
+    extends DERBitString
+{
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int UNUSED                  = (1 << 7);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int KEY_COMPROMISE          = (1 << 6);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CA_COMPROMISE           = (1 << 5);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int AFFILIATION_CHANGED     = (1 << 4);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int SUPERSEDED              = (1 << 3);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CESSATION_OF_OPERATION  = (1 << 2);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CERTIFICATE_HOLD        = (1 << 1);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int PRIVILEGE_WITHDRAWN     = (1 << 0);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int AA_COMPROMISE           = (1 << 15);
+    
+    public static final int unused                  = (1 << 7);
+    public static final int keyCompromise           = (1 << 6);
+    public static final int cACompromise            = (1 << 5);
+    public static final int affiliationChanged      = (1 << 4);
+    public static final int superseded              = (1 << 3);
+    public static final int cessationOfOperation    = (1 << 2);
+    public static final int certificateHold         = (1 << 1);
+    public static final int privilegeWithdrawn      = (1 << 0);
+    public static final int aACompromise            = (1 << 15);
+
+    /**
+     * @param reasons - the bitwise OR of the Key Reason flags giving the
+     * allowed uses for the key.
+     */
+    public ReasonFlags(
+        int reasons)
+    {
+        super(getBytes(reasons), getPadBits(reasons));
+    }
+
+    public ReasonFlags(
+        DERBitString reasons)
+    {
+        super(reasons.getBytes(), reasons.getPadBits());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
new file mode 100644
index 0000000..b940379
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
@@ -0,0 +1,71 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * The SubjectKeyIdentifier object.
+ * <pre>
+ * SubjectKeyIdentifier::= OCTET STRING
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SubjectKeyIdentifier
+    extends ASN1Object
+{
+    private byte[] keyidentifier;
+
+    public static SubjectKeyIdentifier getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1OctetString.getInstance(obj, explicit));
+    }
+
+    public static SubjectKeyIdentifier getInstance(
+        Object obj)
+    {
+        if (obj instanceof SubjectKeyIdentifier)
+        {
+            return (SubjectKeyIdentifier)obj;
+        }
+        else if (obj != null)
+        {
+            return new SubjectKeyIdentifier(ASN1OctetString.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static SubjectKeyIdentifier fromExtensions(Extensions extensions)
+    {
+        return SubjectKeyIdentifier.getInstance(extensions.getExtensionParsedValue(Extension.subjectKeyIdentifier));
+    }
+
+    public SubjectKeyIdentifier(
+        byte[] keyid)
+    {
+        this.keyidentifier = Arrays.clone(keyid);
+    }
+
+    protected SubjectKeyIdentifier(
+        ASN1OctetString keyid)
+    {
+        this(keyid.getOctets());
+    }
+
+    public byte[] getKeyIdentifier()
+    {
+        return Arrays.clone(keyidentifier);
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return new DEROctetString(getKeyIdentifier());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
new file mode 100644
index 0000000..f36e5c0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
@@ -0,0 +1,156 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The object that contains the public key stored in a certificate.
+ * <p>
+ * The getEncoded() method in the public keys in the JCE produces a DER
+ * encoded one of these.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SubjectPublicKeyInfo
+    extends ASN1Object
+{
+    private AlgorithmIdentifier     algId;
+    private DERBitString            keyData;
+
+    public static SubjectPublicKeyInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static SubjectPublicKeyInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof SubjectPublicKeyInfo)
+        {
+            return (SubjectPublicKeyInfo)obj;
+        }
+        else if (obj != null)
+        {
+            return new SubjectPublicKeyInfo(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public SubjectPublicKeyInfo(
+        AlgorithmIdentifier algId,
+        ASN1Encodable       publicKey)
+        throws IOException
+    {
+        this.keyData = new DERBitString(publicKey);
+        this.algId = algId;
+    }
+
+    public SubjectPublicKeyInfo(
+        AlgorithmIdentifier algId,
+        byte[]              publicKey)
+    {
+        this.keyData = new DERBitString(publicKey);
+        this.algId = algId;
+    }
+
+    /**
+     @deprecated use SubjectPublicKeyInfo.getInstance()
+     */
+    public SubjectPublicKeyInfo(
+        ASN1Sequence  seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        Enumeration         e = seq.getObjects();
+
+        this.algId = AlgorithmIdentifier.getInstance(e.nextElement());
+        this.keyData = DERBitString.getInstance(e.nextElement());
+    }
+
+    public AlgorithmIdentifier getAlgorithm()
+    {
+        return algId;
+    }
+
+    /**
+     * @deprecated use getAlgorithm()
+     * @return    alg ID.
+     */
+    public AlgorithmIdentifier getAlgorithmId()
+    {
+        return algId;
+    }
+
+    /**
+     * for when the public key is an encoded object - if the bitstring
+     * can't be decoded this routine throws an IOException.
+     *
+     * @exception IOException - if the bit string doesn't represent a DER
+     * encoded object.
+     * @return the public key as an ASN.1 primitive.
+     */
+    public ASN1Primitive parsePublicKey()
+        throws IOException
+    {
+        return ASN1Primitive.fromByteArray(keyData.getOctets());
+    }
+
+    /**
+     * for when the public key is an encoded object - if the bitstring
+     * can't be decoded this routine throws an IOException.
+     *
+     * @exception IOException - if the bit string doesn't represent a DER
+     * encoded object.
+     * @deprecated use parsePublicKey
+     * @return the public key as an ASN.1 primitive.
+     */
+    public ASN1Primitive getPublicKey()
+        throws IOException
+    {
+        return ASN1Primitive.fromByteArray(keyData.getOctets());
+    }
+
+    /**
+     * for when the public key is raw bits.
+     *
+     * @return the public key as the raw bit string...
+     */
+    public DERBitString getPublicKeyData()
+    {
+        return keyData;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * SubjectPublicKeyInfo ::= SEQUENCE {
+     *                          algorithm AlgorithmIdentifier,
+     *                          publicKey BIT STRING }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(algId);
+        v.add(keyData);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/TBSCertList.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/TBSCertList.java
new file mode 100644
index 0000000..d0df1bb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/TBSCertList.java
@@ -0,0 +1,315 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1GeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.ASN1UTCTime;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * PKIX RFC-2459 - TBSCertList object.
+ * <pre>
+ * TBSCertList  ::=  SEQUENCE  {
+ *      version                 Version OPTIONAL,
+ *                                   -- if present, shall be v2
+ *      signature               AlgorithmIdentifier,
+ *      issuer                  Name,
+ *      thisUpdate              Time,
+ *      nextUpdate              Time OPTIONAL,
+ *      revokedCertificates     SEQUENCE OF SEQUENCE  {
+ *           userCertificate         CertificateSerialNumber,
+ *           revocationDate          Time,
+ *           crlEntryExtensions      Extensions OPTIONAL
+ *                                         -- if present, shall be v2
+ *                                }  OPTIONAL,
+ *      crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
+ *                                         -- if present, shall be v2
+ *                                }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TBSCertList
+    extends ASN1Object
+{
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class CRLEntry
+        extends ASN1Object
+    {
+        ASN1Sequence  seq;
+
+        Extensions    crlEntryExtensions;
+
+        private CRLEntry(
+            ASN1Sequence  seq)
+        {
+            if (seq.size() < 2 || seq.size() > 3)
+            {
+                throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+            }
+            
+            this.seq = seq;
+        }
+
+        public static CRLEntry getInstance(Object o)
+        {
+            if (o instanceof CRLEntry)
+            {
+                return ((CRLEntry)o);
+            }
+            else if (o != null)
+            {
+                return new CRLEntry(ASN1Sequence.getInstance(o));
+            }
+
+            return null;
+        }
+
+        public ASN1Integer getUserCertificate()
+        {
+            return ASN1Integer.getInstance(seq.getObjectAt(0));
+        }
+
+        public Time getRevocationDate()
+        {
+            return Time.getInstance(seq.getObjectAt(1));
+        }
+
+        public Extensions getExtensions()
+        {
+            if (crlEntryExtensions == null && seq.size() == 3)
+            {
+                crlEntryExtensions = Extensions.getInstance(seq.getObjectAt(2));
+            }
+            
+            return crlEntryExtensions;
+        }
+
+        public ASN1Primitive toASN1Primitive()
+        {
+            return seq;
+        }
+
+        public boolean hasExtensions()
+        {
+            return seq.size() == 3;
+        }
+    }
+
+    private class RevokedCertificatesEnumeration
+        implements Enumeration
+    {
+        private final Enumeration en;
+
+        RevokedCertificatesEnumeration(Enumeration en)
+        {
+            this.en = en;
+        }
+
+        public boolean hasMoreElements()
+        {
+            return en.hasMoreElements();
+        }
+
+        public Object nextElement()
+        {
+            return CRLEntry.getInstance(en.nextElement());
+        }
+    }
+
+    private class EmptyEnumeration
+        implements Enumeration
+    {
+        public boolean hasMoreElements()
+        {
+            return false;
+        }
+
+        public Object nextElement()
+        {
+            throw new NoSuchElementException("Empty Enumeration");
+        }
+    }
+
+    ASN1Integer             version;
+    AlgorithmIdentifier     signature;
+    X500Name                issuer;
+    Time                    thisUpdate;
+    Time                    nextUpdate;
+    ASN1Sequence            revokedCertificates;
+    Extensions              crlExtensions;
+
+    public static TBSCertList getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static TBSCertList getInstance(
+        Object  obj)
+    {
+        if (obj instanceof TBSCertList)
+        {
+            return (TBSCertList)obj;
+        }
+        else if (obj != null)
+        {
+            return new TBSCertList(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public TBSCertList(
+        ASN1Sequence  seq)
+    {
+        if (seq.size() < 3 || seq.size() > 7)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        int seqPos = 0;
+
+        if (seq.getObjectAt(seqPos) instanceof ASN1Integer)
+        {
+            version = ASN1Integer.getInstance(seq.getObjectAt(seqPos++));
+        }
+        else
+        {
+            version = null;  // version is optional
+        }
+
+        signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqPos++));
+        issuer = X500Name.getInstance(seq.getObjectAt(seqPos++));
+        thisUpdate = Time.getInstance(seq.getObjectAt(seqPos++));
+
+        if (seqPos < seq.size()
+            && (seq.getObjectAt(seqPos) instanceof ASN1UTCTime
+               || seq.getObjectAt(seqPos) instanceof ASN1GeneralizedTime
+               || seq.getObjectAt(seqPos) instanceof Time))
+        {
+            nextUpdate = Time.getInstance(seq.getObjectAt(seqPos++));
+        }
+
+        if (seqPos < seq.size()
+            && !(seq.getObjectAt(seqPos) instanceof ASN1TaggedObject))
+        {
+            revokedCertificates = ASN1Sequence.getInstance(seq.getObjectAt(seqPos++));
+        }
+
+        if (seqPos < seq.size()
+            && seq.getObjectAt(seqPos) instanceof ASN1TaggedObject)
+        {
+            crlExtensions = Extensions.getInstance(ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(seqPos), true));
+        }
+    }
+
+    public int getVersionNumber()
+    {
+        if (version == null)
+        {
+            return 1;
+        }
+        return version.getValue().intValue() + 1;
+    }
+
+    public ASN1Integer getVersion()
+    {
+        return version;
+    }
+
+    public AlgorithmIdentifier getSignature()
+    {
+        return signature;
+    }
+
+    public X500Name getIssuer()
+    {
+        return issuer;
+    }
+
+    public Time getThisUpdate()
+    {
+        return thisUpdate;
+    }
+
+    public Time getNextUpdate()
+    {
+        return nextUpdate;
+    }
+
+    public CRLEntry[] getRevokedCertificates()
+    {
+        if (revokedCertificates == null)
+        {
+            return new CRLEntry[0];
+        }
+
+        CRLEntry[] entries = new CRLEntry[revokedCertificates.size()];
+
+        for (int i = 0; i < entries.length; i++)
+        {
+            entries[i] = CRLEntry.getInstance(revokedCertificates.getObjectAt(i));
+        }
+        
+        return entries;
+    }
+
+    public Enumeration getRevokedCertificateEnumeration()
+    {
+        if (revokedCertificates == null)
+        {
+            return new EmptyEnumeration();
+        }
+
+        return new RevokedCertificatesEnumeration(revokedCertificates.getObjects());
+    }
+
+    public Extensions getExtensions()
+    {
+        return crlExtensions;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        if (version != null)
+        {
+            v.add(version);
+        }
+        v.add(signature);
+        v.add(issuer);
+
+        v.add(thisUpdate);
+        if (nextUpdate != null)
+        {
+            v.add(nextUpdate);
+        }
+
+        // Add CRLEntries if they exist
+        if (revokedCertificates != null)
+        {
+            v.add(revokedCertificates);
+        }
+
+        if (crlExtensions != null)
+        {
+            v.add(new DERTaggedObject(0, crlExtensions));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/TBSCertificate.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/TBSCertificate.java
new file mode 100644
index 0000000..e8968fd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/TBSCertificate.java
@@ -0,0 +1,225 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * The TBSCertificate object.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ *      version          [ 0 ]  Version DEFAULT v1(0),
+ *      serialNumber            CertificateSerialNumber,
+ *      signature               AlgorithmIdentifier,
+ *      issuer                  Name,
+ *      validity                Validity,
+ *      subject                 Name,
+ *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+ *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      extensions        [ 3 ] Extensions OPTIONAL
+ *      }
+ * </pre>
+ * <p>
+ * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class
+ * will parse them, but you really shouldn't be creating new ones.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TBSCertificate
+    extends ASN1Object
+{
+    ASN1Sequence            seq;
+
+    ASN1Integer             version;
+    ASN1Integer             serialNumber;
+    AlgorithmIdentifier     signature;
+    X500Name                issuer;
+    Time                    startDate, endDate;
+    X500Name                subject;
+    SubjectPublicKeyInfo    subjectPublicKeyInfo;
+    DERBitString            issuerUniqueId;
+    DERBitString            subjectUniqueId;
+    Extensions              extensions;
+
+    public static TBSCertificate getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static TBSCertificate getInstance(
+        Object  obj)
+    {
+        if (obj instanceof TBSCertificate)
+        {
+            return (TBSCertificate)obj;
+        }
+        else if (obj != null)
+        {
+            return new TBSCertificate(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private TBSCertificate(
+        ASN1Sequence seq)
+    {
+        int         seqStart = 0;
+
+        this.seq = seq;
+
+        //
+        // some certficates don't include a version number - we assume v1
+        //
+        if (seq.getObjectAt(0) instanceof ASN1TaggedObject)
+        {
+            version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);
+        }
+        else
+        {
+            seqStart = -1;          // field 0 is missing!
+            version = new ASN1Integer(0);
+        }
+
+        boolean isV1 = false;
+        boolean isV2 = false;
+ 
+        if (version.getValue().equals(BigInteger.valueOf(0)))
+        {
+            isV1 = true;
+        }
+        else if (version.getValue().equals(BigInteger.valueOf(1)))
+        {
+            isV2 = true;
+        }
+        else if (!version.getValue().equals(BigInteger.valueOf(2)))
+        {
+            throw new IllegalArgumentException("version number not recognised");
+        }
+
+        serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1));
+
+        signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2));
+        issuer = X500Name.getInstance(seq.getObjectAt(seqStart + 3));
+
+        //
+        // before and after dates
+        //
+        ASN1Sequence  dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4);
+
+        startDate = Time.getInstance(dates.getObjectAt(0));
+        endDate = Time.getInstance(dates.getObjectAt(1));
+
+        subject = X500Name.getInstance(seq.getObjectAt(seqStart + 5));
+
+        //
+        // public key info.
+        //
+        subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6));
+
+        int extras = seq.size() - (seqStart + 6) - 1;
+        if (extras != 0 && isV1)
+        {
+            throw new IllegalArgumentException("version 1 certificate contains extra data");
+        }
+        
+        while (extras > 0)
+        {
+            ASN1TaggedObject extra = (ASN1TaggedObject)seq.getObjectAt(seqStart + 6 + extras);
+
+            switch (extra.getTagNo())
+            {
+            case 1:
+                issuerUniqueId = DERBitString.getInstance(extra, false);
+                break;
+            case 2:
+                subjectUniqueId = DERBitString.getInstance(extra, false);
+                break;
+            case 3:
+                if (isV2)
+                {
+                    throw new IllegalArgumentException("version 2 certificate cannot contain extensions");
+                }
+                extensions = Extensions.getInstance(ASN1Sequence.getInstance(extra, true));
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown tag encountered in structure: " + extra.getTagNo());
+            }
+            extras--;
+        }
+    }
+
+    public int getVersionNumber()
+    {
+        return version.getValue().intValue() + 1;
+    }
+
+    public ASN1Integer getVersion()
+    {
+        return version;
+    }
+
+    public ASN1Integer getSerialNumber()
+    {
+        return serialNumber;
+    }
+
+    public AlgorithmIdentifier getSignature()
+    {
+        return signature;
+    }
+
+    public X500Name getIssuer()
+    {
+        return issuer;
+    }
+
+    public Time getStartDate()
+    {
+        return startDate;
+    }
+
+    public Time getEndDate()
+    {
+        return endDate;
+    }
+
+    public X500Name getSubject()
+    {
+        return subject;
+    }
+
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+    {
+        return subjectPublicKeyInfo;
+    }
+
+    public DERBitString getIssuerUniqueId()
+    {
+        return issuerUniqueId;
+    }
+
+    public DERBitString getSubjectUniqueId()
+    {
+        return subjectUniqueId;
+    }
+
+    public Extensions getExtensions()
+    {
+        return extensions;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/TBSCertificateStructure.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
new file mode 100644
index 0000000..f98de72
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
@@ -0,0 +1,197 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * The TBSCertificate object.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ *      version          [ 0 ]  Version DEFAULT v1(0),
+ *      serialNumber            CertificateSerialNumber,
+ *      signature               AlgorithmIdentifier,
+ *      issuer                  Name,
+ *      validity                Validity,
+ *      subject                 Name,
+ *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+ *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      extensions        [ 3 ] Extensions OPTIONAL
+ *      }
+ * </pre>
+ * <p>
+ * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class
+ * will parse them, but you really shouldn't be creating new ones.
+ * @deprecated use TBSCertificate
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TBSCertificateStructure
+    extends ASN1Object
+    implements X509ObjectIdentifiers, PKCSObjectIdentifiers
+{
+    ASN1Sequence            seq;
+
+    ASN1Integer             version;
+    ASN1Integer             serialNumber;
+    AlgorithmIdentifier     signature;
+    X500Name                issuer;
+    Time                    startDate, endDate;
+    X500Name                subject;
+    SubjectPublicKeyInfo    subjectPublicKeyInfo;
+    DERBitString            issuerUniqueId;
+    DERBitString            subjectUniqueId;
+    X509Extensions          extensions;
+
+    public static TBSCertificateStructure getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static TBSCertificateStructure getInstance(
+        Object  obj)
+    {
+        if (obj instanceof TBSCertificateStructure)
+        {
+            return (TBSCertificateStructure)obj;
+        }
+        else if (obj != null)
+        {
+            return new TBSCertificateStructure(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public TBSCertificateStructure(
+        ASN1Sequence  seq)
+    {
+        int         seqStart = 0;
+
+        this.seq = seq;
+
+        //
+        // some certficates don't include a version number - we assume v1
+        //
+        if (seq.getObjectAt(0) instanceof DERTaggedObject)
+        {
+            version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);
+        }
+        else
+        {
+            seqStart = -1;          // field 0 is missing!
+            version = new ASN1Integer(0);
+        }
+
+        serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1));
+
+        signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2));
+        issuer = X500Name.getInstance(seq.getObjectAt(seqStart + 3));
+
+        //
+        // before and after dates
+        //
+        ASN1Sequence  dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4);
+
+        startDate = Time.getInstance(dates.getObjectAt(0));
+        endDate = Time.getInstance(dates.getObjectAt(1));
+
+        subject = X500Name.getInstance(seq.getObjectAt(seqStart + 5));
+
+        //
+        // public key info.
+        //
+        subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6));
+
+        for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--)
+        {
+            DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras);
+
+            switch (extra.getTagNo())
+            {
+            case 1:
+                issuerUniqueId = DERBitString.getInstance(extra, false);
+                break;
+            case 2:
+                subjectUniqueId = DERBitString.getInstance(extra, false);
+                break;
+            case 3:
+                extensions = X509Extensions.getInstance(extra);
+            }
+        }
+    }
+
+    public int getVersion()
+    {
+        return version.getValue().intValue() + 1;
+    }
+
+    public ASN1Integer getVersionNumber()
+    {
+        return version;
+    }
+
+    public ASN1Integer getSerialNumber()
+    {
+        return serialNumber;
+    }
+
+    public AlgorithmIdentifier getSignature()
+    {
+        return signature;
+    }
+
+    public X500Name getIssuer()
+    {
+        return issuer;
+    }
+
+    public Time getStartDate()
+    {
+        return startDate;
+    }
+
+    public Time getEndDate()
+    {
+        return endDate;
+    }
+
+    public X500Name getSubject()
+    {
+        return subject;
+    }
+
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+    {
+        return subjectPublicKeyInfo;
+    }
+
+    public DERBitString getIssuerUniqueId()
+    {
+        return issuerUniqueId;
+    }
+
+    public DERBitString getSubjectUniqueId()
+    {
+        return subjectUniqueId;
+    }
+
+    public X509Extensions getExtensions()
+    {
+        return extensions;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Time.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Time.java
new file mode 100644
index 0000000..eb98713
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/Time.java
@@ -0,0 +1,181 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+// Android-added: Localization support
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.SimpleTimeZone;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Choice;
+import com.android.internal.org.bouncycastle.asn1.ASN1GeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.ASN1UTCTime;
+import com.android.internal.org.bouncycastle.asn1.DERGeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.DERUTCTime;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Time
+    extends ASN1Object
+    implements ASN1Choice
+{
+    ASN1Primitive time;
+
+    public static Time getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject()); // must be explicitly tagged
+    }
+
+    public Time(
+        ASN1Primitive   time)
+    {
+        if (!(time instanceof ASN1UTCTime)
+            && !(time instanceof ASN1GeneralizedTime))
+        {
+            throw new IllegalArgumentException("unknown object passed to Time");
+        }
+
+        this.time = time; 
+    }
+
+    /**
+     * Creates a time object from a given date - if the date is between 1950
+     * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime
+     * is used.
+     *
+     * @param time a date object representing the time of interest.
+     */
+    public Time(
+        Date    time)
+    {
+        SimpleTimeZone      tz = new SimpleTimeZone(0, "Z");
+        // Android-changed: Use localized version
+        // SimpleDateFormat    dateF = new SimpleDateFormat("yyyyMMddHHmmss");
+        SimpleDateFormat    dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
+
+        dateF.setTimeZone(tz);
+
+        String  d = dateF.format(time) + "Z";
+        int     year = Integer.parseInt(d.substring(0, 4));
+
+        if (year < 1950 || year > 2049)
+        {
+            this.time = new DERGeneralizedTime(d);
+        }
+        else
+        {
+            this.time = new DERUTCTime(d.substring(2));
+        }
+    }
+
+    /**
+     * Creates a time object from a given date and locale - if the date is between 1950
+     * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime
+     * is used. You may need to use this constructor if the default locale
+     * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations.
+     *
+     * @param time a date object representing the time of interest.
+     * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value.
+     */
+    public Time(
+        Date    time,
+        Locale locale)
+    {
+        SimpleTimeZone      tz = new SimpleTimeZone(0, "Z");
+        // BEGIN Android-changed: Use localized version
+        // SimpleDateFormat    dateF = new SimpleDateFormat("yyyyMMddHHmmss", locale);
+        SimpleDateFormat    dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
+        dateF.setCalendar(Calendar.getInstance(locale));
+        // END android-changed
+
+        dateF.setTimeZone(tz);
+
+        String  d = dateF.format(time) + "Z";
+        int     year = Integer.parseInt(d.substring(0, 4));
+
+        if (year < 1950 || year > 2049)
+        {
+            this.time = new DERGeneralizedTime(d);
+        }
+        else
+        {
+            this.time = new DERUTCTime(d.substring(2));
+        }
+    }
+
+    public static Time getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof Time)
+        {
+            return (Time)obj;
+        }
+        else if (obj instanceof ASN1UTCTime)
+        {
+            return new Time((ASN1UTCTime)obj);
+        }
+        else if (obj instanceof ASN1GeneralizedTime)
+        {
+            return new Time((ASN1GeneralizedTime)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+    }
+
+    public String getTime()
+    {
+        if (time instanceof ASN1UTCTime)
+        {
+            return ((ASN1UTCTime)time).getAdjustedTime();
+        }
+        else
+        {
+            return ((ASN1GeneralizedTime)time).getTime();
+        }
+    }
+
+    public Date getDate()
+    {
+        try
+        {
+            if (time instanceof ASN1UTCTime)
+            {
+                return ((ASN1UTCTime)time).getAdjustedDate();
+            }
+            else
+            {
+                return ((ASN1GeneralizedTime)time).getDate();
+            }
+        }
+        catch (ParseException e)
+        {         // this should never happen
+            throw new IllegalStateException("invalid date string: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Time ::= CHOICE {
+     *             utcTime        UTCTime,
+     *             generalTime    GeneralizedTime }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return time;
+    }
+
+    public String toString()
+    {
+        return getTime();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
new file mode 100644
index 0000000..1771988
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
@@ -0,0 +1,146 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1UTCTime;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * Generator for Version 1 TBSCertificateStructures.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ *      version          [ 0 ]  Version DEFAULT v1(0),
+ *      serialNumber            CertificateSerialNumber,
+ *      signature               AlgorithmIdentifier,
+ *      issuer                  Name,
+ *      validity                Validity,
+ *      subject                 Name,
+ *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+ *      }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ *
+ */
+public class V1TBSCertificateGenerator
+{
+    DERTaggedObject         version = new DERTaggedObject(true, 0, new ASN1Integer(0));
+
+    ASN1Integer              serialNumber;
+    AlgorithmIdentifier     signature;
+    X500Name                issuer;
+    Time                    startDate, endDate;
+    X500Name                subject;
+    SubjectPublicKeyInfo    subjectPublicKeyInfo;
+
+    public V1TBSCertificateGenerator()
+    {
+    }
+
+    public void setSerialNumber(
+        ASN1Integer  serialNumber)
+    {
+        this.serialNumber = serialNumber;
+    }
+
+    public void setSignature(
+        AlgorithmIdentifier    signature)
+    {
+        this.signature = signature;
+    }
+
+        /**
+     * @deprecated use X500Name method
+     */
+    public void setIssuer(
+        X509Name    issuer)
+    {
+        this.issuer = X500Name.getInstance(issuer.toASN1Primitive());
+    }
+
+    public void setIssuer(
+        X500Name issuer)
+    {
+        this.issuer = issuer;
+    }
+
+    public void setStartDate(
+        Time startDate)
+    {
+        this.startDate = startDate;
+    }
+
+    public void setStartDate(
+        ASN1UTCTime startDate)
+    {
+        this.startDate = new Time(startDate);
+    }
+
+    public void setEndDate(
+        Time endDate)
+    {
+        this.endDate = endDate;
+    }
+
+    public void setEndDate(
+        ASN1UTCTime endDate)
+    {
+        this.endDate = new Time(endDate);
+    }
+
+    /**
+     * @deprecated use X500Name method
+     */
+    public void setSubject(
+        X509Name    subject)
+    {
+        this.subject = X500Name.getInstance(subject.toASN1Primitive());
+    }
+
+    public void setSubject(
+        X500Name subject)
+    {
+        this.subject = subject;
+    }
+
+    public void setSubjectPublicKeyInfo(
+        SubjectPublicKeyInfo    pubKeyInfo)
+    {
+        this.subjectPublicKeyInfo = pubKeyInfo;
+    }
+
+    public TBSCertificate generateTBSCertificate()
+    {
+        if ((serialNumber == null) || (signature == null)
+            || (issuer == null) || (startDate == null) || (endDate == null)
+            || (subject == null) || (subjectPublicKeyInfo == null))
+        {
+            throw new IllegalStateException("not all mandatory fields set in V1 TBScertificate generator");
+        }
+
+        ASN1EncodableVector  seq = new ASN1EncodableVector();
+
+        // seq.add(version); - not required as default value.
+        seq.add(serialNumber);
+        seq.add(signature);
+        seq.add(issuer);
+
+        //
+        // before and after dates
+        //
+        ASN1EncodableVector  validity = new ASN1EncodableVector();
+
+        validity.add(startDate);
+        validity.add(endDate);
+
+        seq.add(new DERSequence(validity));
+
+        seq.add(subject);
+
+        seq.add(subjectPublicKeyInfo);
+
+        return TBSCertificate.getInstance(new DERSequence(seq));
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/V2Form.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/V2Form.java
new file mode 100644
index 0000000..6724b50
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/V2Form.java
@@ -0,0 +1,161 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class V2Form
+    extends ASN1Object
+{
+    GeneralNames        issuerName;
+    IssuerSerial        baseCertificateID;
+    ObjectDigestInfo    objectDigestInfo;
+
+    public static V2Form getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static V2Form getInstance(
+        Object  obj)
+    {
+        if (obj instanceof V2Form)
+        {
+            return (V2Form)obj;
+        }
+        else if (obj != null)
+        {
+            return new V2Form(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+    
+    public V2Form(
+        GeneralNames    issuerName)
+    {
+        this(issuerName, null, null);
+    }
+
+    public V2Form(
+        GeneralNames    issuerName,
+        IssuerSerial    baseCertificateID)
+    {
+        this(issuerName, baseCertificateID, null);
+    }
+
+    public V2Form(
+        GeneralNames    issuerName,
+        ObjectDigestInfo objectDigestInfo)
+    {
+        this(issuerName, null, objectDigestInfo);
+    }
+
+    public V2Form(
+        GeneralNames    issuerName,
+        IssuerSerial    baseCertificateID,
+        ObjectDigestInfo objectDigestInfo)
+    {
+        this.issuerName = issuerName;
+        this.baseCertificateID = baseCertificateID;
+        this.objectDigestInfo = objectDigestInfo;
+    }
+
+    /**
+     * @deprecated use getInstance().
+     */
+    public V2Form(
+        ASN1Sequence seq)
+    {
+        if (seq.size() > 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+        
+        int    index = 0;
+
+        if (!(seq.getObjectAt(0) instanceof ASN1TaggedObject))
+        {
+            index++;
+            this.issuerName = GeneralNames.getInstance(seq.getObjectAt(0));
+        }
+
+        for (int i = index; i != seq.size(); i++)
+        {
+            ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+            if (o.getTagNo() == 0)
+            {
+                baseCertificateID = IssuerSerial.getInstance(o, false);
+            }
+            else if (o.getTagNo() == 1)
+            {
+                objectDigestInfo = ObjectDigestInfo.getInstance(o, false);
+            }
+            else 
+            {
+                throw new IllegalArgumentException("Bad tag number: "
+                        + o.getTagNo());
+            }
+        }
+    }
+    
+    public GeneralNames getIssuerName()
+    {
+        return issuerName;
+    }
+
+    public IssuerSerial getBaseCertificateID()
+    {
+        return baseCertificateID;
+    }
+
+    public ObjectDigestInfo getObjectDigestInfo()
+    {
+        return objectDigestInfo;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  V2Form ::= SEQUENCE {
+     *       issuerName            GeneralNames  OPTIONAL,
+     *       baseCertificateID     [0] IssuerSerial  OPTIONAL,
+     *       objectDigestInfo      [1] ObjectDigestInfo  OPTIONAL
+     *         -- issuerName MUST be present in this profile
+     *         -- baseCertificateID and objectDigestInfo MUST NOT
+     *         -- be present in this profile
+     *  }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (issuerName != null)
+        {
+            v.add(issuerName);
+        }
+
+        if (baseCertificateID != null)
+        {
+            v.add(new DERTaggedObject(false, 0, baseCertificateID));
+        }
+
+        if (objectDigestInfo != null)
+        {
+            v.add(new DERTaggedObject(false, 1, objectDigestInfo));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
new file mode 100644
index 0000000..f9ec8b9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
@@ -0,0 +1,214 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1UTCTime;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERTaggedObject;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * Generator for Version 3 TBSCertificateStructures.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ *      version          [ 0 ]  Version DEFAULT v1(0),
+ *      serialNumber            CertificateSerialNumber,
+ *      signature               AlgorithmIdentifier,
+ *      issuer                  Name,
+ *      validity                Validity,
+ *      subject                 Name,
+ *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+ *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      extensions        [ 3 ] Extensions OPTIONAL
+ *      }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ *
+ */
+public class V3TBSCertificateGenerator
+{
+    DERTaggedObject         version = new DERTaggedObject(true, 0, new ASN1Integer(2));
+
+    ASN1Integer              serialNumber;
+    AlgorithmIdentifier     signature;
+    X500Name                issuer;
+    Time                    startDate, endDate;
+    X500Name                subject;
+    SubjectPublicKeyInfo    subjectPublicKeyInfo;
+    Extensions              extensions;
+
+    private boolean altNamePresentAndCritical;
+    private DERBitString issuerUniqueID;
+    private DERBitString subjectUniqueID;
+
+    public V3TBSCertificateGenerator()
+    {
+    }
+
+    public void setSerialNumber(
+        ASN1Integer  serialNumber)
+    {
+        this.serialNumber = serialNumber;
+    }
+
+    public void setSignature(
+        AlgorithmIdentifier    signature)
+    {
+        this.signature = signature;
+    }
+
+        /**
+     * @deprecated use X500Name method
+     */
+    public void setIssuer(
+        X509Name    issuer)
+    {
+        this.issuer = X500Name.getInstance(issuer);
+    }
+
+    public void setIssuer(
+        X500Name issuer)
+    {
+        this.issuer = issuer;
+    }
+    
+    public void setStartDate(
+        ASN1UTCTime startDate)
+    {
+        this.startDate = new Time(startDate);
+    }
+
+    public void setStartDate(
+        Time startDate)
+    {
+        this.startDate = startDate;
+    }
+
+    public void setEndDate(
+        ASN1UTCTime endDate)
+    {
+        this.endDate = new Time(endDate);
+    }
+
+    public void setEndDate(
+        Time endDate)
+    {
+        this.endDate = endDate;
+    }
+
+        /**
+     * @deprecated use X500Name method
+     */
+    public void setSubject(
+        X509Name    subject)
+    {
+        this.subject = X500Name.getInstance(subject.toASN1Primitive());
+    }
+
+    public void setSubject(
+        X500Name subject)
+    {
+        this.subject = subject;
+    }
+
+    public void setIssuerUniqueID(
+        DERBitString uniqueID)
+    {
+        this.issuerUniqueID = uniqueID;
+    }
+
+    public void setSubjectUniqueID(
+        DERBitString uniqueID)
+    {
+        this.subjectUniqueID = uniqueID;
+    }
+
+    public void setSubjectPublicKeyInfo(
+        SubjectPublicKeyInfo    pubKeyInfo)
+    {
+        this.subjectPublicKeyInfo = pubKeyInfo;
+    }
+
+    /**
+     * @deprecated use method taking Extensions
+     * @param extensions
+     */
+    public void setExtensions(
+        X509Extensions    extensions)
+    {
+        setExtensions(Extensions.getInstance(extensions));
+    }
+
+    public void setExtensions(
+        Extensions    extensions)
+    {
+        this.extensions = extensions;
+        if (extensions != null)
+        {
+            Extension altName = extensions.getExtension(Extension.subjectAlternativeName);
+
+            if (altName != null && altName.isCritical())
+            {
+                altNamePresentAndCritical = true;
+            }
+        }
+    }
+
+    public TBSCertificate generateTBSCertificate()
+    {
+        if ((serialNumber == null) || (signature == null)
+            || (issuer == null) || (startDate == null) || (endDate == null)
+            || (subject == null && !altNamePresentAndCritical) || (subjectPublicKeyInfo == null))
+        {
+            throw new IllegalStateException("not all mandatory fields set in V3 TBScertificate generator");
+        }
+
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(serialNumber);
+        v.add(signature);
+        v.add(issuer);
+
+        //
+        // before and after dates
+        //
+        ASN1EncodableVector  validity = new ASN1EncodableVector();
+
+        validity.add(startDate);
+        validity.add(endDate);
+
+        v.add(new DERSequence(validity));
+
+        if (subject != null)
+        {
+            v.add(subject);
+        }
+        else
+        {
+            v.add(new DERSequence());
+        }
+
+        v.add(subjectPublicKeyInfo);
+
+        if (issuerUniqueID != null)
+        {
+            v.add(new DERTaggedObject(false, 1, issuerUniqueID));
+        }
+
+        if (subjectUniqueID != null)
+        {
+            v.add(new DERTaggedObject(false, 2, subjectUniqueID));
+        }
+
+        if (extensions != null)
+        {
+            v.add(new DERTaggedObject(true, 3, extensions));
+        }
+
+        return TBSCertificate.getInstance(new DERSequence(v));
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509CertificateStructure.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509CertificateStructure.java
new file mode 100644
index 0000000..34afe36
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509CertificateStructure.java
@@ -0,0 +1,131 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * an X509Certificate structure.
+ * <pre>
+ *  Certificate ::= SEQUENCE {
+ *      tbsCertificate          TBSCertificate,
+ *      signatureAlgorithm      AlgorithmIdentifier,
+ *      signature               BIT STRING
+ *  }
+ * </pre>
+ * @deprecated use org.bouncycastle.asn1.x509.Certificate
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509CertificateStructure
+    extends ASN1Object
+    implements X509ObjectIdentifiers, PKCSObjectIdentifiers
+{
+    ASN1Sequence  seq;
+    TBSCertificateStructure tbsCert;
+    AlgorithmIdentifier     sigAlgId;
+    DERBitString            sig;
+
+    public static X509CertificateStructure getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static X509CertificateStructure getInstance(
+        Object  obj)
+    {
+        if (obj instanceof X509CertificateStructure)
+        {
+            return (X509CertificateStructure)obj;
+        }
+        else if (obj != null)
+        {
+            return new X509CertificateStructure(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public X509CertificateStructure(
+        ASN1Sequence  seq)
+    {
+        this.seq = seq;
+
+        //
+        // correct x509 certficate
+        //
+        if (seq.size() == 3)
+        {
+            tbsCert = TBSCertificateStructure.getInstance(seq.getObjectAt(0));
+            sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+
+            sig = DERBitString.getInstance(seq.getObjectAt(2));
+        }
+        else
+        {
+            throw new IllegalArgumentException("sequence wrong size for a certificate");
+        }
+    }
+
+    public TBSCertificateStructure getTBSCertificate()
+    {
+        return tbsCert;
+    }
+
+    public int getVersion()
+    {
+        return tbsCert.getVersion();
+    }
+
+    public ASN1Integer getSerialNumber()
+    {
+        return tbsCert.getSerialNumber();
+    }
+
+    public X500Name getIssuer()
+    {
+        return tbsCert.getIssuer();
+    }
+
+    public Time getStartDate()
+    {
+        return tbsCert.getStartDate();
+    }
+
+    public Time getEndDate()
+    {
+        return tbsCert.getEndDate();
+    }
+
+    public X500Name getSubject()
+    {
+        return tbsCert.getSubject();
+    }
+
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+    {
+        return tbsCert.getSubjectPublicKeyInfo();
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return sigAlgId;
+    }
+
+    public DERBitString getSignature()
+    {
+        return sig;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        return seq;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java
new file mode 100644
index 0000000..582ebdd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java
@@ -0,0 +1,67 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.DERGeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.DERPrintableString;
+import com.android.internal.org.bouncycastle.asn1.DERUTF8String;
+
+/**
+ * The default converter for X509 DN entries when going from their
+ * string value to ASN.1 strings.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509DefaultEntryConverter
+    extends X509NameEntryConverter
+{
+    /**
+     * Apply default coversion for the given value depending on the oid
+     * and the character range of the value.
+     * 
+     * @param oid the object identifier for the DN entry
+     * @param value the value associated with it
+     * @return the ASN.1 equivalent for the string value.
+     */
+    public ASN1Primitive getConvertedValue(
+        ASN1ObjectIdentifier  oid,
+        String               value)
+    {
+        if (value.length() != 0 && value.charAt(0) == '#')
+        {
+            try
+            {
+                return convertHexEncoded(value, 1);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("can't recode value for oid " + oid.getId());
+            }
+        }
+        else
+        {
+            if (value.length() != 0 && value.charAt(0) == '\\')
+            {
+                value = value.substring(1);
+            }
+            if (oid.equals(X509Name.EmailAddress) || oid.equals(X509Name.DC))
+            {
+                return new DERIA5String(value);
+            }
+            else if (oid.equals(X509Name.DATE_OF_BIRTH))  // accept time string as well as # (for compatibility)
+            {
+                return new DERGeneralizedTime(value);
+            }
+            else if (oid.equals(X509Name.C) || oid.equals(X509Name.SN) || oid.equals(X509Name.DN_QUALIFIER)
+                || oid.equals(X509Name.TELEPHONE_NUMBER))
+            {
+                 return new DERPrintableString(value);
+            }
+        }
+        
+        return new DERUTF8String(value);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509Extension.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509Extension.java
new file mode 100644
index 0000000..8bdf57b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509Extension.java
@@ -0,0 +1,251 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Boolean;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+
+/**
+ * an object for the elements in the X.509 V3 extension block.
+ * @deprecated use Extension
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509Extension
+{
+    /**
+     * Subject Directory Attributes
+     */
+    public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9");
+    
+    /**
+     * Subject Key Identifier 
+     */
+    public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14");
+
+    /**
+     * Key Usage 
+     */
+    public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier("2.5.29.15");
+
+    /**
+     * Private Key Usage Period 
+     */
+    public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16");
+
+    /**
+     * Subject Alternative Name 
+     */
+    public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17");
+
+    /**
+     * Issuer Alternative Name 
+     */
+    public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18");
+
+    /**
+     * Basic Constraints 
+     */
+    public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19");
+
+    /**
+     * CRL Number 
+     */
+    public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier("2.5.29.20");
+
+    /**
+     * Reason code 
+     */
+    public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier("2.5.29.21");
+
+    /**
+     * Hold Instruction Code 
+     */
+    public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier("2.5.29.23");
+
+    /**
+     * Invalidity Date 
+     */
+    public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier("2.5.29.24");
+
+    /**
+     * Delta CRL indicator 
+     */
+    public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27");
+
+    /**
+     * Issuing Distribution Point 
+     */
+    public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28");
+
+    /**
+     * Certificate Issuer 
+     */
+    public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier("2.5.29.29");
+
+    /**
+     * Name Constraints 
+     */
+    public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier("2.5.29.30");
+
+    /**
+     * CRL Distribution Points 
+     */
+    public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31");
+
+    /**
+     * Certificate Policies 
+     */
+    public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier("2.5.29.32");
+
+    /**
+     * Policy Mappings 
+     */
+    public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier("2.5.29.33");
+
+    /**
+     * Authority Key Identifier 
+     */
+    public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35");
+
+    /**
+     * Policy Constraints 
+     */
+    public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier("2.5.29.36");
+
+    /**
+     * Extended Key Usage 
+     */
+    public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37");
+
+    /**
+     * Freshest CRL
+     */
+    public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier("2.5.29.46");
+     
+    /**
+     * Inhibit Any Policy
+     */
+    public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54");
+
+    /**
+     * Authority Info Access
+     */
+    public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1");
+
+    /**
+     * Subject Info Access
+     */
+    public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11");
+    
+    /**
+     * Logo Type
+     */
+    public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12");
+
+    /**
+     * BiometricInfo
+     */
+    public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2");
+    
+    /**
+     * QCStatements
+     */
+    public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3");
+
+    /**
+     * Audit identity extension in attribute certificates.
+     */
+    public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4");
+    
+    /**
+     * NoRevAvail extension in attribute certificates.
+     */
+    public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier("2.5.29.56");
+
+    /**
+     * TargetInformation extension in attribute certificates.
+     */
+    public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55");
+        
+    boolean             critical;
+    ASN1OctetString     value;
+
+    public X509Extension(
+        ASN1Boolean             critical,
+        ASN1OctetString         value)
+    {
+        this.critical = critical.isTrue();
+        this.value = value;
+    }
+
+    public X509Extension(
+        boolean                 critical,
+        ASN1OctetString         value)
+    {
+        this.critical = critical;
+        this.value = value;
+    }
+
+    public boolean isCritical()
+    {
+        return critical;
+    }
+
+    public ASN1OctetString getValue()
+    {
+        return value;
+    }
+
+    public ASN1Encodable getParsedValue()
+    {
+        return convertValueToObject(this);
+    }
+
+    public int hashCode()
+    {
+        if (this.isCritical())
+        {
+            return this.getValue().hashCode();
+        }
+
+        return ~this.getValue().hashCode();
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof X509Extension))
+        {
+            return false;
+        }
+
+        X509Extension   other = (X509Extension)o;
+
+        return other.getValue().equals(this.getValue())
+            && (other.isCritical() == this.isCritical());
+    }
+
+    /**
+     * Convert the value of the passed in extension to an object
+     * @param ext the extension to parse
+     * @return the object the value string contains
+     * @exception IllegalArgumentException if conversion is not possible
+     */
+    public static ASN1Primitive convertValueToObject(
+        X509Extension ext)
+        throws IllegalArgumentException
+    {
+        try
+        {
+            return ASN1Primitive.fromByteArray(ext.getValue().getOctets());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't convert extension: " +  e);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509Extensions.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509Extensions.java
new file mode 100644
index 0000000..f099dd8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509Extensions.java
@@ -0,0 +1,479 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Boolean;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @deprecated use Extensions
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509Extensions
+    extends ASN1Object
+{
+    /**
+     * Subject Directory Attributes
+     * @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier SubjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9");
+    
+    /**
+     * Subject Key Identifier
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier SubjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14");
+
+    /**
+     * Key Usage
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier KeyUsage = new ASN1ObjectIdentifier("2.5.29.15");
+
+    /**
+     * Private Key Usage Period
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier PrivateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16");
+
+    /**
+     * Subject Alternative Name
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier SubjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17");
+
+    /**
+     * Issuer Alternative Name
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier IssuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18");
+
+    /**
+     * Basic Constraints
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier BasicConstraints = new ASN1ObjectIdentifier("2.5.29.19");
+
+    /**
+     * CRL Number
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier CRLNumber = new ASN1ObjectIdentifier("2.5.29.20");
+
+    /**
+     * Reason code
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier ReasonCode = new ASN1ObjectIdentifier("2.5.29.21");
+
+    /**
+     * Hold Instruction Code
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier InstructionCode = new ASN1ObjectIdentifier("2.5.29.23");
+
+    /**
+     * Invalidity Date
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier InvalidityDate = new ASN1ObjectIdentifier("2.5.29.24");
+
+    /**
+     * Delta CRL indicator
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier DeltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27");
+
+    /**
+     * Issuing Distribution Point
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier IssuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28");
+
+    /**
+     * Certificate Issuer
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier CertificateIssuer = new ASN1ObjectIdentifier("2.5.29.29");
+
+    /**
+     * Name Constraints
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier NameConstraints = new ASN1ObjectIdentifier("2.5.29.30");
+
+    /**
+     * CRL Distribution Points
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier CRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31");
+
+    /**
+     * Certificate Policies
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier CertificatePolicies = new ASN1ObjectIdentifier("2.5.29.32");
+
+    /**
+     * Policy Mappings
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier PolicyMappings = new ASN1ObjectIdentifier("2.5.29.33");
+
+    /**
+     * Authority Key Identifier
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier AuthorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35");
+
+    /**
+     * Policy Constraints
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier PolicyConstraints = new ASN1ObjectIdentifier("2.5.29.36");
+
+    /**
+     * Extended Key Usage
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier ExtendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37");
+
+    /**
+     * Freshest CRL
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier FreshestCRL = new ASN1ObjectIdentifier("2.5.29.46");
+     
+    /**
+     * Inhibit Any Policy
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier InhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54");
+
+    /**
+     * Authority Info Access
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier AuthorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1");
+
+    /**
+     * Subject Info Access
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier SubjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11");
+    
+    /**
+     * Logo Type
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier LogoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12");
+
+    /**
+     * BiometricInfo
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier BiometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2");
+    
+    /**
+     * QCStatements
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier QCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3");
+
+    /**
+     * Audit identity extension in attribute certificates.
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier AuditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4");
+    
+    /**
+     * NoRevAvail extension in attribute certificates.
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier NoRevAvail = new ASN1ObjectIdentifier("2.5.29.56");
+
+    /**
+     * TargetInformation extension in attribute certificates.
+     *  @deprecated use X509Extension value.
+     */
+    public static final ASN1ObjectIdentifier TargetInformation = new ASN1ObjectIdentifier("2.5.29.55");
+    
+    private Hashtable               extensions = new Hashtable();
+    private Vector                  ordering = new Vector();
+
+    public static X509Extensions getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static X509Extensions getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof X509Extensions)
+        {
+            return (X509Extensions)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new X509Extensions((ASN1Sequence)obj);
+        }
+
+        if (obj instanceof Extensions)
+        {
+            return new X509Extensions((ASN1Sequence)((Extensions)obj).toASN1Primitive());
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Constructor from ASN1Sequence.
+     *
+     * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)
+     */
+    public X509Extensions(
+        ASN1Sequence  seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1Sequence            s = ASN1Sequence.getInstance(e.nextElement());
+
+            if (s.size() == 3)
+            {
+                extensions.put(s.getObjectAt(0), new X509Extension(ASN1Boolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2))));
+            }
+            else if (s.size() == 2)
+            {
+                extensions.put(s.getObjectAt(0), new X509Extension(false, ASN1OctetString.getInstance(s.getObjectAt(1))));
+            }
+            else
+            {
+                throw new IllegalArgumentException("Bad sequence size: " + s.size());
+            }
+
+            ordering.addElement(s.getObjectAt(0));
+        }
+    }
+
+    /**
+     * constructor from a table of extensions.
+     * <p>
+     * it's is assumed the table contains OID/String pairs.
+     */
+    public X509Extensions(
+        Hashtable  extensions)
+    {
+        this(null, extensions);
+    }
+
+    /**
+     * Constructor from a table of extensions with ordering.
+     * <p>
+     * It's is assumed the table contains OID/String pairs.
+     * @deprecated use Extensions
+     */
+    public X509Extensions(
+        Vector      ordering,
+        Hashtable   extensions)
+    {
+        Enumeration e;
+
+        if (ordering == null)
+        {
+            e = extensions.keys();
+        }
+        else
+        {
+            e = ordering.elements();
+        }
+
+        while (e.hasMoreElements())
+        {
+            this.ordering.addElement(ASN1ObjectIdentifier.getInstance(e.nextElement()));
+        }
+
+        e = this.ordering.elements();
+
+        while (e.hasMoreElements())
+        {
+            ASN1ObjectIdentifier     oid = ASN1ObjectIdentifier.getInstance(e.nextElement());
+            X509Extension           ext = (X509Extension)extensions.get(oid);
+
+            this.extensions.put(oid, ext);
+        }
+    }
+
+    /**
+     * Constructor from two vectors
+     * 
+     * @param objectIDs a vector of the object identifiers.
+     * @param values a vector of the extension values.
+     * @deprecated use Extensions
+     */
+    public X509Extensions(
+        Vector      objectIDs,
+        Vector      values)
+    {
+        Enumeration e = objectIDs.elements();
+
+        while (e.hasMoreElements())
+        {
+            this.ordering.addElement(e.nextElement()); 
+        }
+
+        int count = 0;
+        
+        e = this.ordering.elements();
+
+        while (e.hasMoreElements())
+        {
+            ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)e.nextElement();
+            X509Extension           ext = (X509Extension)values.elementAt(count);
+
+            this.extensions.put(oid, ext);
+            count++;
+        }
+    }
+    
+    /**
+     * return an Enumeration of the extension field's object ids.
+     */
+    public Enumeration oids()
+    {
+        return ordering.elements();
+    }
+
+    /**
+     * return the extension represented by the object identifier
+     * passed in.
+     *
+     * @return the extension if it's present, null otherwise.
+     */
+    public X509Extension getExtension(
+        ASN1ObjectIdentifier oid)
+    {
+        return (X509Extension)extensions.get(oid);
+    }
+
+    /**
+     * <pre>
+     *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
+     *
+     *     Extension         ::=   SEQUENCE {
+     *        extnId            EXTENSION.&amp;id ({ExtensionSet}),
+     *        critical          BOOLEAN DEFAULT FALSE,
+     *        extnValue         OCTET STRING }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector     vec = new ASN1EncodableVector();
+        Enumeration             e = ordering.elements();
+
+        while (e.hasMoreElements())
+        {
+            ASN1ObjectIdentifier    oid = (ASN1ObjectIdentifier)e.nextElement();
+            X509Extension           ext = (X509Extension)extensions.get(oid);
+            ASN1EncodableVector     v = new ASN1EncodableVector();
+
+            v.add(oid);
+
+            if (ext.isCritical())
+            {
+                v.add(ASN1Boolean.TRUE);
+            }
+
+            v.add(ext.getValue());
+
+            vec.add(new DERSequence(v));
+        }
+
+        return new DERSequence(vec);
+    }
+
+    public boolean equivalent(
+        X509Extensions other)
+    {
+        if (extensions.size() != other.extensions.size())
+        {
+            return false;
+        }
+
+        Enumeration     e1 = extensions.keys();
+
+        while (e1.hasMoreElements())
+        {
+            Object  key = e1.nextElement();
+
+            if (!extensions.get(key).equals(other.extensions.get(key)))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public ASN1ObjectIdentifier[] getExtensionOIDs()
+    {
+        return toOidArray(ordering);
+    }
+    
+    public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(false);
+    }
+
+    public ASN1ObjectIdentifier[] getCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(true);
+    }
+
+    private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical)
+    {
+        Vector oidVec = new Vector();
+
+        for (int i = 0; i != ordering.size(); i++)
+        {
+            Object oid = ordering.elementAt(i);
+
+            if (((X509Extension)extensions.get(oid)).isCritical() == isCritical)
+            {
+                oidVec.addElement(oid);
+            }
+        }
+
+        return toOidArray(oidVec);
+    }
+
+    private ASN1ObjectIdentifier[] toOidArray(Vector oidVec)
+    {
+        ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()];
+
+        for (int i = 0; i != oids.length; i++)
+        {
+            oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i);
+        }
+        return oids;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java
new file mode 100644
index 0000000..04aa142
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java
@@ -0,0 +1,96 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+
+/**
+ * Generator for X.509 extensions
+ * @deprecated use org.bouncycastle.asn1.x509.ExtensionsGenerator
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509ExtensionsGenerator
+{
+    private Hashtable extensions = new Hashtable();
+    private Vector extOrdering = new Vector();
+
+    /**
+     * Reset the generator
+     */
+    public void reset()
+    {
+        extensions = new Hashtable();
+        extOrdering = new Vector();
+    }
+
+    /**
+     * Add an extension with the given oid and the passed in value to be included
+     * in the OCTET STRING associated with the extension.
+     *
+     * @param oid  OID for the extension.
+     * @param critical  true if critical, false otherwise.
+     * @param value the ASN.1 object to be included in the extension.
+     */
+    public void addExtension(
+        ASN1ObjectIdentifier oid,
+        boolean             critical,
+        ASN1Encodable       value)
+    {
+        try
+        {
+            this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("error encoding value: " + e);
+        }
+    }
+
+    /**
+     * Add an extension with the given oid and the passed in byte array to be wrapped in the
+     * OCTET STRING associated with the extension.
+     *
+     * @param oid OID for the extension.
+     * @param critical true if critical, false otherwise.
+     * @param value the byte array to be wrapped.
+     */
+    public void addExtension(
+        ASN1ObjectIdentifier oid,
+        boolean             critical,
+        byte[]              value)
+    {
+        if (extensions.containsKey(oid))
+        {
+            throw new IllegalArgumentException("extension " + oid + " already added");
+        }
+
+        extOrdering.addElement(oid);
+        extensions.put(oid, new X509Extension(critical, new DEROctetString(value)));
+    }
+
+    /**
+     * Return true if there are no extension present in this generator.
+     *
+     * @return true if empty, false otherwise
+     */
+    public boolean isEmpty()
+    {
+        return extOrdering.isEmpty();
+    }
+
+    /**
+     * Generate an X509Extensions object based on the current state of the generator.
+     *
+     * @return  an X09Extensions object.
+     */
+    public X509Extensions generate()
+    {
+        return new X509Extensions(extOrdering, extensions);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509Name.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509Name.java
new file mode 100644
index 0000000..b82fee6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509Name.java
@@ -0,0 +1,1383 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.ASN1String;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERSet;
+import com.android.internal.org.bouncycastle.asn1.DERUniversalString;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * <pre>
+ *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+ *
+ *     AttributeTypeAndValue ::= SEQUENCE {
+ *                                   type  OBJECT IDENTIFIER,
+ *                                   value ANY }
+ * </pre>
+ * @deprecated use org.bouncycastle.asn1.x500.X500Name.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509Name
+    extends ASN1Object
+{
+    /**
+     * country code - StringType(SIZE(2))
+     * @deprecated use a X500NameStyle
+     */
+    public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6");
+
+    /**
+     * organization - StringType(SIZE(1..64))
+     * @deprecated use a X500NameStyle
+     */
+    public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10");
+
+    /**
+     * organizational unit name - StringType(SIZE(1..64))
+     * @deprecated use a X500NameStyle
+     */
+    public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11");
+
+    /**
+     * Title
+     * @deprecated use a X500NameStyle
+     */
+    public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12");
+
+    /**
+     * common name - StringType(SIZE(1..64))
+     * @deprecated use a X500NameStyle
+     */
+    public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3");
+
+    /**
+     * device serial number name - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5");
+
+    /**
+     * street - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9");
+    
+    /**
+     * device serial number name - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier SERIALNUMBER = SN;
+
+    /**
+     * locality name - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7");
+
+    /**
+     * state, or province name - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8");
+
+    /**
+     * Naming attributes of type X520name
+     */
+    public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier("2.5.4.4");
+    public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier("2.5.4.42");
+    public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier("2.5.4.43");
+    public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier("2.5.4.44");
+    public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier("2.5.4.45");
+
+    /**
+     * businessCategory - DirectoryString(SIZE(1..128)
+     */
+    public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier(
+                    "2.5.4.15");
+
+    /**
+     * postalCode - DirectoryString(SIZE(1..40)
+     */
+    public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier(
+                    "2.5.4.17");
+    
+    /**
+     * dnQualifier - DirectoryString(SIZE(1..64)
+     */
+    public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier(
+                    "2.5.4.46");
+
+    /**
+     * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+     */
+    public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier(
+                    "2.5.4.65");
+
+
+    /**
+     * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+     */
+    public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier(
+                    "1.3.6.1.5.5.7.9.1");
+
+    /**
+     * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
+     */
+    public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier(
+                    "1.3.6.1.5.5.7.9.2");
+
+    /**
+     * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
+     */
+    public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier(
+                    "1.3.6.1.5.5.7.9.3");
+
+    /**
+     * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+     * codes only
+     */
+    public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier(
+                    "1.3.6.1.5.5.7.9.4");
+
+    /**
+     * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166
+     * codes only
+     */
+    public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier(
+                    "1.3.6.1.5.5.7.9.5");
+
+
+    /**
+     * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+     */
+    public static final ASN1ObjectIdentifier NAME_AT_BIRTH =  new ASN1ObjectIdentifier("1.3.36.8.3.14");
+
+    /**
+     * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+     * DirectoryString(SIZE(1..30))
+     */
+    public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16");
+
+    /**
+     * RFC 2256 dmdName
+     */
+    public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54");
+
+    /**
+     * id-at-telephoneNumber
+     */
+    public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber;
+
+    /**
+     * id-at-name
+     */
+    public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name;
+
+    /**
+     * Email address (RSA PKCS#9 extension) - IA5String.
+     * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
+     * @deprecated use a X500NameStyle
+     */
+    public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;
+    
+    /**
+     * more from PKCS#9
+     */
+    public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName;
+    public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress;
+    
+    /**
+     * email address in Verisign certificates
+     */
+    public static final ASN1ObjectIdentifier E = EmailAddress;
+    
+    /*
+     * others...
+     */
+    public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25");
+
+    /**
+     * LDAP User id.
+     */
+    public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1");
+
+    /**
+     * determines whether or not strings should be processed and printed
+     * from back to front.
+     */
+    public static boolean DefaultReverse = false;
+
+    /**
+     * default look up table translating OID values into their common symbols following
+     * the convention in RFC 2253 with a few extras
+     */
+    public static final Hashtable DefaultSymbols = new Hashtable();
+
+    /**
+     * look up table translating OID values into their common symbols following the convention in RFC 2253
+     * 
+     */
+    public static final Hashtable RFC2253Symbols = new Hashtable();
+
+    /**
+     * look up table translating OID values into their common symbols following the convention in RFC 1779
+     * 
+     */
+    public static final Hashtable RFC1779Symbols = new Hashtable();
+
+    /**
+     * look up table translating common symbols into their OIDS.
+     */
+    public static final Hashtable DefaultLookUp = new Hashtable();
+
+    /**
+     * look up table translating OID values into their common symbols
+     * @deprecated use DefaultSymbols
+     */
+    public static final Hashtable OIDLookUp = DefaultSymbols;
+
+    /**
+     * look up table translating string values into their OIDS -
+     * @deprecated use DefaultLookUp
+     */
+    public static final Hashtable SymbolLookUp = DefaultLookUp;
+
+    // BEGIN Android-changed: Use Boolean class constants instead of Boolean constructor
+    private static final Boolean TRUE = Boolean.TRUE;
+    private static final Boolean FALSE = Boolean.FALSE;
+    // END Android-changed: Use Boolean class constants instead of Boolean constructor
+
+    static
+    {
+        DefaultSymbols.put(C, "C");
+        DefaultSymbols.put(O, "O");
+        DefaultSymbols.put(T, "T");
+        DefaultSymbols.put(OU, "OU");
+        DefaultSymbols.put(CN, "CN");
+        DefaultSymbols.put(L, "L");
+        DefaultSymbols.put(ST, "ST");
+        DefaultSymbols.put(SN, "SERIALNUMBER");
+        DefaultSymbols.put(EmailAddress, "E");
+        DefaultSymbols.put(DC, "DC");
+        DefaultSymbols.put(UID, "UID");
+        DefaultSymbols.put(STREET, "STREET");
+        DefaultSymbols.put(SURNAME, "SURNAME");
+        DefaultSymbols.put(GIVENNAME, "GIVENNAME");
+        DefaultSymbols.put(INITIALS, "INITIALS");
+        DefaultSymbols.put(GENERATION, "GENERATION");
+        DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress");
+        DefaultSymbols.put(UnstructuredName, "unstructuredName");
+        DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier");
+        DefaultSymbols.put(DN_QUALIFIER, "DN");
+        DefaultSymbols.put(PSEUDONYM, "Pseudonym");
+        DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress");
+        DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth");
+        DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship");
+        DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence");
+        DefaultSymbols.put(GENDER, "Gender");
+        DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth");
+        DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth");
+        DefaultSymbols.put(POSTAL_CODE, "PostalCode");
+        DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory");
+        DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber");
+        DefaultSymbols.put(NAME, "Name");
+
+        RFC2253Symbols.put(C, "C");
+        RFC2253Symbols.put(O, "O");
+        RFC2253Symbols.put(OU, "OU");
+        RFC2253Symbols.put(CN, "CN");
+        RFC2253Symbols.put(L, "L");
+        RFC2253Symbols.put(ST, "ST");
+        RFC2253Symbols.put(STREET, "STREET");
+        RFC2253Symbols.put(DC, "DC");
+        RFC2253Symbols.put(UID, "UID");
+
+        RFC1779Symbols.put(C, "C");
+        RFC1779Symbols.put(O, "O");
+        RFC1779Symbols.put(OU, "OU");
+        RFC1779Symbols.put(CN, "CN");
+        RFC1779Symbols.put(L, "L");
+        RFC1779Symbols.put(ST, "ST");
+        RFC1779Symbols.put(STREET, "STREET");
+
+        DefaultLookUp.put("c", C);
+        DefaultLookUp.put("o", O);
+        DefaultLookUp.put("t", T);
+        DefaultLookUp.put("ou", OU);
+        DefaultLookUp.put("cn", CN);
+        DefaultLookUp.put("l", L);
+        DefaultLookUp.put("st", ST);
+        DefaultLookUp.put("sn", SN);
+        DefaultLookUp.put("serialnumber", SN);
+        DefaultLookUp.put("street", STREET);
+        DefaultLookUp.put("emailaddress", E);
+        DefaultLookUp.put("dc", DC);
+        DefaultLookUp.put("e", E);
+        DefaultLookUp.put("uid", UID);
+        DefaultLookUp.put("surname", SURNAME);
+        DefaultLookUp.put("givenname", GIVENNAME);
+        DefaultLookUp.put("initials", INITIALS);
+        DefaultLookUp.put("generation", GENERATION);
+        DefaultLookUp.put("unstructuredaddress", UnstructuredAddress);
+        DefaultLookUp.put("unstructuredname", UnstructuredName);
+        DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER);
+        DefaultLookUp.put("dn", DN_QUALIFIER);
+        DefaultLookUp.put("pseudonym", PSEUDONYM);
+        DefaultLookUp.put("postaladdress", POSTAL_ADDRESS);
+        DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH);
+        DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP);
+        DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE);
+        DefaultLookUp.put("gender", GENDER);
+        DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH);
+        DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH);
+        DefaultLookUp.put("postalcode", POSTAL_CODE);
+        DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY);
+        DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER);
+        DefaultLookUp.put("name", NAME);
+    }
+
+    private X509NameEntryConverter  converter = null;
+    private Vector                  ordering = new Vector();
+    private Vector                  values = new Vector();
+    private Vector                  added = new Vector();
+
+    private ASN1Sequence            seq;
+
+    private boolean                 isHashCodeCalculated;
+    private int                     hashCodeValue;
+
+    /**
+     * Return a X509Name based on the passed in tagged object.
+     * 
+     * @param obj tag object holding name.
+     * @param explicit true if explicitly tagged false otherwise.
+     * @return the X509Name
+     */
+    public static X509Name getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static X509Name getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof X509Name)
+        {
+            return (X509Name)obj;
+        }
+        else if (obj instanceof X500Name)
+        {
+            return new X509Name(ASN1Sequence.getInstance(((X500Name)obj).toASN1Primitive()));
+        }
+        else if (obj != null)
+        {
+            return new X509Name(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    protected X509Name()
+    {
+        // constructure use by new X500 Name class
+    }
+    /**
+     * Constructor from ASN1Sequence
+     *
+     * the principal will be a list of constructed sets, each containing an (OID, String) pair.
+     * @deprecated use X500Name.getInstance()
+     */
+    public X509Name(
+        ASN1Sequence  seq)
+    {
+        this.seq = seq;
+
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1Set         set = ASN1Set.getInstance(((ASN1Encodable)e.nextElement()).toASN1Primitive());
+
+            for (int i = 0; i < set.size(); i++) 
+            {
+                   ASN1Sequence s = ASN1Sequence.getInstance(set.getObjectAt(i).toASN1Primitive());
+
+                   if (s.size() != 2)
+                   {
+                       throw new IllegalArgumentException("badly sized pair");
+                   }
+
+                   ordering.addElement(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0)));
+                   
+                   ASN1Encodable value = s.getObjectAt(1);
+                   if (value instanceof ASN1String && !(value instanceof DERUniversalString))
+                   {
+                       String v = ((ASN1String)value).getString();
+                       if (v.length() > 0 && v.charAt(0) == '#')
+                       {
+                           values.addElement("\\" + v);
+                       }
+                       else
+                       {
+                           values.addElement(v);
+                       }
+                   }
+                   else
+                   {
+                       try
+                       {
+                           values.addElement("#" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER))));
+                       }
+                       catch (IOException e1)
+                       {
+                           throw new IllegalArgumentException("cannot encode value");
+                       }
+                   }
+                   added.addElement((i != 0) ? TRUE : FALSE);  // to allow earlier JDK compatibility
+            }
+        }
+    }
+
+    /**
+     * constructor from a table of attributes.
+     * <p>
+     * it's is assumed the table contains OID/String pairs, and the contents
+     * of the table are copied into an internal table as part of the
+     * construction process.
+     * <p>
+     * <b>Note:</b> if the name you are trying to generate should be
+     * following a specific ordering, you should use the constructor
+     * with the ordering specified below.
+     * @deprecated use an ordered constructor! The hashtable ordering is rarely correct
+     */
+    public X509Name(
+        Hashtable  attributes)
+    {
+        this(null, attributes);
+    }
+
+    /**
+     * Constructor from a table of attributes with ordering.
+     * <p>
+     * it's is assumed the table contains OID/String pairs, and the contents
+     * of the table are copied into an internal table as part of the
+     * construction process. The ordering vector should contain the OIDs
+     * in the order they are meant to be encoded or printed in toString.
+     */
+    public X509Name(
+        Vector      ordering,
+        Hashtable   attributes)
+    {
+        this(ordering, attributes, new X509DefaultEntryConverter());
+    }
+
+    /**
+     * Constructor from a table of attributes with ordering.
+     * <p>
+     * it's is assumed the table contains OID/String pairs, and the contents
+     * of the table are copied into an internal table as part of the
+     * construction process. The ordering vector should contain the OIDs
+     * in the order they are meant to be encoded or printed in toString.
+     * <p>
+     * The passed in converter will be used to convert the strings into their
+     * ASN.1 counterparts.
+     * @deprecated use X500Name, X500NameBuilder
+     */
+    public X509Name(
+        Vector                   ordering,
+        Hashtable                attributes,
+        X509NameEntryConverter   converter)
+    {
+        this.converter = converter;
+
+        if (ordering != null)
+        {
+            for (int i = 0; i != ordering.size(); i++)
+            {
+                this.ordering.addElement(ordering.elementAt(i));
+                this.added.addElement(FALSE);
+            }
+        }
+        else
+        {
+            Enumeration     e = attributes.keys();
+
+            while (e.hasMoreElements())
+            {
+                this.ordering.addElement(e.nextElement());
+                this.added.addElement(FALSE);
+            }
+        }
+
+        for (int i = 0; i != this.ordering.size(); i++)
+        {
+            ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)this.ordering.elementAt(i);
+
+            if (attributes.get(oid) == null)
+            {
+                throw new IllegalArgumentException("No attribute for object id - " + oid.getId() + " - passed to distinguished name");
+            }
+
+            this.values.addElement(attributes.get(oid)); // copy the hash table
+        }
+    }
+
+    /**
+     * Takes two vectors one of the oids and the other of the values.
+     * @deprecated use X500Name, X500NameBuilder
+     */
+    public X509Name(
+        Vector  oids,
+        Vector  values)
+    {
+        this(oids, values, new X509DefaultEntryConverter());
+    }
+
+    /**
+     * Takes two vectors one of the oids and the other of the values.
+     * <p>
+     * The passed in converter will be used to convert the strings into their
+     * ASN.1 counterparts.
+     * @deprecated use X500Name, X500NameBuilder
+     */
+    public X509Name(
+        Vector                  oids,
+        Vector                  values,
+        X509NameEntryConverter  converter)
+    {
+        this.converter = converter;
+
+        if (oids.size() != values.size())
+        {
+            throw new IllegalArgumentException("oids vector must be same length as values.");
+        }
+
+        for (int i = 0; i < oids.size(); i++)
+        {
+            this.ordering.addElement(oids.elementAt(i));
+            this.values.addElement(values.elementAt(i));
+            this.added.addElement(FALSE);
+        }
+    }
+
+//    private Boolean isEncoded(String s)
+//    {
+//        if (s.charAt(0) == '#')
+//        {
+//            return TRUE;
+//        }
+//
+//        return FALSE;
+//    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes.
+     * @deprecated use X500Name, X500NameBuilder
+     */
+    public X509Name(
+        String  dirName)
+    {
+        this(DefaultReverse, DefaultLookUp, dirName);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes with each
+     * string value being converted to its associated ASN.1 type using the passed
+     * in converter.
+     * @deprecated use X500Name, X500NameBuilder
+     */
+    public X509Name(
+        String                  dirName,
+        X509NameEntryConverter  converter)
+    {
+        this(DefaultReverse, DefaultLookUp, dirName, converter);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes. If reverse
+     * is true, create the encoded version of the sequence starting from the
+     * last element in the string.
+     * @deprecated use X500Name, X500NameBuilder
+     */
+    public X509Name(
+        boolean reverse,
+        String  dirName)
+    {
+        this(reverse, DefaultLookUp, dirName);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes with each
+     * string value being converted to its associated ASN.1 type using the passed
+     * in converter. If reverse is true the ASN.1 sequence representing the DN will
+     * be built by starting at the end of the string, rather than the start.
+     * @deprecated use X500Name, X500NameBuilder
+     */
+    public X509Name(
+        boolean                 reverse,
+        String                  dirName,
+        X509NameEntryConverter  converter)
+    {
+        this(reverse, DefaultLookUp, dirName, converter);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes. lookUp
+     * should provide a table of lookups, indexed by lowercase only strings and
+     * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids
+     * will be processed automatically.
+     * <br>
+     * If reverse is true, create the encoded version of the sequence
+     * starting from the last element in the string.
+     * @param reverse true if we should start scanning from the end (RFC 2553).
+     * @param lookUp table of names and their oids.
+     * @param dirName the X.500 string to be parsed.
+     * @deprecated use X500Name, X500NameBuilder
+     */
+    public X509Name(
+        boolean     reverse,
+        Hashtable   lookUp,
+        String      dirName)
+    {
+        this(reverse, lookUp, dirName, new X509DefaultEntryConverter());
+    }
+
+    private ASN1ObjectIdentifier decodeOID(
+        String      name,
+        Hashtable   lookUp)
+    {
+        name = name.trim();
+        if (Strings.toUpperCase(name).startsWith("OID."))
+        {
+            return new ASN1ObjectIdentifier(name.substring(4));
+        }
+        else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')
+        {
+            return new ASN1ObjectIdentifier(name);
+        }
+
+        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
+        if (oid == null)
+        {
+            throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+        }
+
+        return oid;
+    }
+
+    private String unescape(String elt)
+    {
+        if (elt.length() == 0 || (elt.indexOf('\\') < 0 && elt.indexOf('"') < 0))
+        {
+            return elt.trim();
+        }
+
+        char[] elts = elt.toCharArray();
+        boolean escaped = false;
+        boolean quoted = false;
+        StringBuffer buf = new StringBuffer(elt.length());
+        int start = 0;
+
+        // if it's an escaped hash string and not an actual encoding in string form
+        // we need to leave it escaped.
+        if (elts[0] == '\\')
+        {
+            if (elts[1] == '#')
+            {
+                start = 2;
+                buf.append("\\#");
+            }
+        }
+
+        boolean nonWhiteSpaceEncountered = false;
+        int     lastEscaped = 0;
+
+        for (int i = start; i != elts.length; i++)
+        {
+            char c = elts[i];
+
+            if (c != ' ')
+            {
+                nonWhiteSpaceEncountered = true;
+            }
+
+            if (c == '"')
+            {
+                if (!escaped)
+                {
+                    quoted = !quoted;
+                }
+                else
+                {
+                    buf.append(c);
+                }
+                escaped = false;
+            }
+            else if (c == '\\' && !(escaped || quoted))
+            {
+                escaped = true;
+                lastEscaped = buf.length();
+            }
+            else
+            {
+                if (c == ' ' && !escaped && !nonWhiteSpaceEncountered)
+                {
+                    continue;
+                }
+                buf.append(c);
+                escaped = false;
+            }
+        }
+
+        if (buf.length() > 0)
+        {
+            while (buf.charAt(buf.length() - 1) == ' ' && lastEscaped != (buf.length() - 1))
+            {
+                buf.setLength(buf.length() - 1);
+            }
+        }
+
+        return buf.toString();
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes. lookUp
+     * should provide a table of lookups, indexed by lowercase only strings and
+     * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids
+     * will be processed automatically. The passed in converter is used to convert the
+     * string values to the right of each equals sign to their ASN.1 counterparts.
+     * <br>
+     * @param reverse true if we should start scanning from the end, false otherwise.
+     * @param lookUp table of names and oids.
+     * @param dirName the string dirName
+     * @param converter the converter to convert string values into their ASN.1 equivalents
+     */
+    public X509Name(
+        boolean                 reverse,
+        Hashtable               lookUp,
+        String                  dirName,
+        X509NameEntryConverter  converter)
+    {
+        this.converter = converter;
+        X509NameTokenizer   nTok = new X509NameTokenizer(dirName);
+
+        while (nTok.hasMoreTokens())
+        {
+            String  token = nTok.nextToken();
+
+            if (token.indexOf('+') > 0)
+            {
+                X509NameTokenizer   pTok = new X509NameTokenizer(token, '+');
+
+                addEntry(lookUp, pTok.nextToken(), FALSE);
+
+                while (pTok.hasMoreTokens())
+                {
+                    addEntry(lookUp, pTok.nextToken(), TRUE);
+                }
+            }
+            else
+            {
+                addEntry(lookUp, token, FALSE);
+            }
+        }
+
+        if (reverse)
+        {
+            Vector  o = new Vector();
+            Vector  v = new Vector();
+            Vector  a = new Vector();
+
+            int count = 1;
+
+            for (int i = 0; i < this.ordering.size(); i++)
+            {
+                if (((Boolean)this.added.elementAt(i)).booleanValue())
+                {
+                    o.insertElementAt(this.ordering.elementAt(i), count);
+                    v.insertElementAt(this.values.elementAt(i), count);
+                    a.insertElementAt(this.added.elementAt(i), count);
+                    count++;
+                }
+                else
+                {
+                    o.insertElementAt(this.ordering.elementAt(i), 0);
+                    v.insertElementAt(this.values.elementAt(i), 0);
+                    a.insertElementAt(this.added.elementAt(i), 0);
+                    count = 1;
+                }
+            }
+
+            this.ordering = o;
+            this.values = v;
+            this.added = a;
+        }
+    }
+
+    private void addEntry(Hashtable lookUp, String token, Boolean isAdded)
+    {
+        X509NameTokenizer vTok;
+        String name;
+        String value;ASN1ObjectIdentifier oid;
+        vTok = new X509NameTokenizer(token, '=');
+
+        name = vTok.nextToken();
+
+        if (!vTok.hasMoreTokens())
+        {
+           throw new IllegalArgumentException("badly formatted directory string");
+        }
+
+        value = vTok.nextToken();
+
+        oid = decodeOID(name, lookUp);
+
+        this.ordering.addElement(oid);
+        this.values.addElement(unescape(value));
+        this.added.addElement(isAdded);
+    }
+
+    /**
+     * return a vector of the oids in the name, in the order they were found.
+     */
+    public Vector getOIDs()
+    {
+        Vector  v = new Vector();
+
+        for (int i = 0; i != ordering.size(); i++)
+        {
+            v.addElement(ordering.elementAt(i));
+        }
+
+        return v;
+    }
+
+    /**
+     * return a vector of the values found in the name, in the order they
+     * were found.
+     */
+    public Vector getValues()
+    {
+        Vector  v = new Vector();
+
+        for (int i = 0; i != values.size(); i++)
+        {
+            v.addElement(values.elementAt(i));
+        }
+
+        return v;
+    }
+
+    /**
+     * return a vector of the values found in the name, in the order they
+     * were found, with the DN label corresponding to passed in oid.
+     */
+    public Vector getValues(
+        ASN1ObjectIdentifier oid)
+    {
+        Vector  v = new Vector();
+
+        for (int i = 0; i != values.size(); i++)
+        {
+            if (ordering.elementAt(i).equals(oid))
+            {
+                String val = (String)values.elementAt(i);
+
+                if (val.length() > 2 && val.charAt(0) == '\\' && val.charAt(1) == '#')
+                {
+                    v.addElement(val.substring(1));
+                }
+                else
+                {
+                    v.addElement(val);
+                }
+            }
+        }
+
+        return v;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        if (seq == null)
+        {
+            ASN1EncodableVector  vec = new ASN1EncodableVector();
+            ASN1EncodableVector  sVec = new ASN1EncodableVector();
+            ASN1ObjectIdentifier  lstOid = null;
+            
+            for (int i = 0; i != ordering.size(); i++)
+            {
+                ASN1EncodableVector     v = new ASN1EncodableVector();
+                ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
+
+                v.add(oid);
+
+                String  str = (String)values.elementAt(i);
+
+                v.add(converter.getConvertedValue(oid, str));
+ 
+                if (lstOid == null 
+                    || ((Boolean)this.added.elementAt(i)).booleanValue())
+                {
+                    sVec.add(new DERSequence(v));
+                }
+                else
+                {
+                    vec.add(new DERSet(sVec));
+                    sVec = new ASN1EncodableVector();
+                    
+                    sVec.add(new DERSequence(v));
+                }
+                
+                lstOid = oid;
+            }
+            
+            vec.add(new DERSet(sVec));
+            
+            seq = new DERSequence(vec);
+        }
+
+        return seq;
+    }
+
+    /**
+     * @param inOrder if true the order of both X509 names must be the same,
+     * as well as the values associated with each element.
+     */
+    public boolean equals(Object obj, boolean inOrder)
+    {
+        if (!inOrder)
+        {
+            return this.equals(obj);
+        }
+
+        if (obj == this)
+        {
+            return true;
+        }
+
+        if (!(obj instanceof X509Name || obj instanceof ASN1Sequence))
+        {
+            return false;
+        }
+
+        ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
+
+        if (this.toASN1Primitive().equals(derO))
+        {
+            return true;
+        }
+
+        X509Name other;
+
+        try
+        {
+            other = X509Name.getInstance(obj);
+        }
+        catch (IllegalArgumentException e)
+        {
+            return false;
+        }
+
+        int      orderingSize = ordering.size();
+
+        if (orderingSize != other.ordering.size())
+        {
+            return false;
+        }
+
+        for (int i = 0; i < orderingSize; i++)
+        {
+            ASN1ObjectIdentifier  oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
+            ASN1ObjectIdentifier  oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(i);
+
+            if (oid.equals(oOid))
+            {
+                String value = (String)values.elementAt(i);
+                String oValue = (String)other.values.elementAt(i);
+
+                if (!equivalentStrings(value, oValue))
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public int hashCode()
+    {
+        if (isHashCodeCalculated)
+        {
+            return hashCodeValue;
+        }
+
+        isHashCodeCalculated = true;
+
+        // this needs to be order independent, like equals
+        for (int i = 0; i != ordering.size(); i += 1)
+        {
+            String value = (String)values.elementAt(i);
+
+            value = canonicalize(value);
+            value = stripInternalSpaces(value);
+
+            hashCodeValue ^= ordering.elementAt(i).hashCode();
+            hashCodeValue ^= value.hashCode();
+        }
+
+        return hashCodeValue;
+    }
+
+    /**
+     * test for equality - note: case is ignored.
+     */
+    public boolean equals(Object obj)
+    {
+        if (obj == this)
+        {
+            return true;
+        }
+
+        if (!(obj instanceof X509Name || obj instanceof ASN1Sequence))
+        {
+            return false;
+        }
+        
+        ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
+        
+        if (this.toASN1Primitive().equals(derO))
+        {
+            return true;
+        }
+
+        X509Name other;
+
+        try
+        {
+            other = X509Name.getInstance(obj);
+        }
+        catch (IllegalArgumentException e)
+        { 
+            return false;
+        }
+
+        int      orderingSize = ordering.size();
+
+        if (orderingSize != other.ordering.size())
+        {
+            return false;
+        }
+        
+        boolean[] indexes = new boolean[orderingSize];
+        int       start, end, delta;
+
+        if (ordering.elementAt(0).equals(other.ordering.elementAt(0)))   // guess forward
+        {
+            start = 0;
+            end = orderingSize;
+            delta = 1;
+        }
+        else  // guess reversed - most common problem
+        {
+            start = orderingSize - 1;
+            end = -1;
+            delta = -1;
+        }
+
+        for (int i = start; i != end; i += delta)
+        {
+            boolean              found = false;
+            ASN1ObjectIdentifier  oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
+            String               value = (String)values.elementAt(i);
+
+            for (int j = 0; j < orderingSize; j++)
+            {
+                if (indexes[j])
+                {
+                    continue;
+                }
+
+                ASN1ObjectIdentifier oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(j);
+
+                if (oid.equals(oOid))
+                {
+                    String oValue = (String)other.values.elementAt(j);
+
+                    if (equivalentStrings(value, oValue))
+                    {
+                        indexes[j] = true;
+                        found      = true;
+                        break;
+                    }
+                }
+            }
+
+            if (!found)
+            {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+
+    private boolean equivalentStrings(String s1, String s2)
+    {
+        String value = canonicalize(s1);
+        String oValue = canonicalize(s2);
+        
+        if (!value.equals(oValue))
+        {
+            value = stripInternalSpaces(value);
+            oValue = stripInternalSpaces(oValue);
+
+            if (!value.equals(oValue))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private String canonicalize(String s)
+    {
+        String value = Strings.toLowerCase(s.trim());
+        
+        if (value.length() > 0 && value.charAt(0) == '#')
+        {
+            ASN1Primitive obj = decodeObject(value);
+
+            if (obj instanceof ASN1String)
+            {
+                value = Strings.toLowerCase(((ASN1String)obj).getString().trim());
+            }
+        }
+
+        return value;
+    }
+
+    private ASN1Primitive decodeObject(String oValue)
+    {
+        try
+        {
+            return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1)));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("unknown encoding in name: " + e);
+        }
+    }
+
+    private String stripInternalSpaces(
+        String str)
+    {
+        StringBuffer res = new StringBuffer();
+
+        if (str.length() != 0)
+        {
+            char    c1 = str.charAt(0);
+
+            res.append(c1);
+
+            for (int k = 1; k < str.length(); k++)
+            {
+                char    c2 = str.charAt(k);
+                if (!(c1 == ' ' && c2 == ' '))
+                {
+                    res.append(c2);
+                }
+                c1 = c2;
+            }
+        }
+
+        return res.toString();
+    }
+
+    private void appendValue(
+        StringBuffer        buf,
+        Hashtable           oidSymbols,
+        ASN1ObjectIdentifier oid,
+        String              value)
+    {
+        String  sym = (String)oidSymbols.get(oid);
+
+        if (sym != null)
+        {
+            buf.append(sym);
+        }
+        else
+        {
+            buf.append(oid.getId());
+        }
+
+        buf.append('=');
+
+        int start = buf.length();
+        buf.append(value);
+        int end = buf.length();
+
+        if (value.length() >= 2 && value.charAt(0) == '\\' && value.charAt(1) == '#')
+        {
+            start += 2;
+        }
+
+        while (start < end && buf.charAt(start) == ' ')
+        {
+            buf.insert(start, "\\");
+            start += 2;
+            ++end;
+        }
+
+        while (--end > start && buf.charAt(end) == ' ')
+        {
+            buf.insert(end, '\\');
+        }
+
+        while (start <= end)
+        {
+            switch (buf.charAt(start))
+            {
+            case ',':
+            case '"':
+            case '\\':
+            case '+':
+            case '=':
+            case '<':
+            case '>':
+            case ';':
+                buf.insert(start, "\\");
+                start += 2;
+                ++end;
+                break;
+            default:
+                ++start;
+                break;
+            }
+        }
+    }
+
+    /**
+     * convert the structure to a string - if reverse is true the
+     * oids and values are listed out starting with the last element
+     * in the sequence (ala RFC 2253), otherwise the string will begin
+     * with the first element of the structure. If no string definition
+     * for the oid is found in oidSymbols the string value of the oid is
+     * added. Two standard symbol tables are provided DefaultSymbols, and
+     * RFC2253Symbols as part of this class.
+     *
+     * @param reverse if true start at the end of the sequence and work back.
+     * @param oidSymbols look up table strings for oids.
+     */
+    public String toString(
+        boolean     reverse,
+        Hashtable   oidSymbols)
+    {
+        StringBuffer            buf = new StringBuffer();
+        Vector                  components = new Vector();
+        boolean                 first = true;
+
+        StringBuffer ava = null;
+
+        for (int i = 0; i < ordering.size(); i++)
+        {
+            if (((Boolean)added.elementAt(i)).booleanValue())
+            {
+                ava.append('+');
+                appendValue(ava, oidSymbols,
+                    (ASN1ObjectIdentifier)ordering.elementAt(i),
+                    (String)values.elementAt(i));
+            }
+            else
+            {
+                ava = new StringBuffer();
+                appendValue(ava, oidSymbols,
+                    (ASN1ObjectIdentifier)ordering.elementAt(i),
+                    (String)values.elementAt(i));
+                components.addElement(ava);
+            }
+        }
+
+        if (reverse)
+        {
+            for (int i = components.size() - 1; i >= 0; i--)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    buf.append(',');
+                }
+
+                buf.append(components.elementAt(i).toString());
+            }
+        }
+        else
+        {
+            for (int i = 0; i < components.size(); i++)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    buf.append(',');
+                }
+
+                buf.append(components.elementAt(i).toString());
+            }
+        }
+
+        return buf.toString();
+    }
+
+    private String bytesToString(
+        byte[] data)
+    {
+        char[]  cs = new char[data.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            cs[i] = (char)(data[i] & 0xff);
+        }
+
+        return new String(cs);
+    }
+    
+    public String toString()
+    {
+        return toString(DefaultReverse, DefaultSymbols);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509NameEntryConverter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509NameEntryConverter.java
new file mode 100644
index 0000000..e531f9f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509NameEntryConverter.java
@@ -0,0 +1,116 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.DERPrintableString;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * It turns out that the number of standard ways the fields in a DN should be 
+ * encoded into their ASN.1 counterparts is rapidly approaching the
+ * number of machines on the internet. By default the X509Name class 
+ * will produce UTF8Strings in line with the current recommendations (RFC 3280).
+ * <p>
+ * An example of an encoder look like below:
+ * <pre>
+ * public class X509DirEntryConverter
+ *     extends X509NameEntryConverter
+ * {
+ *     public ASN1Primitive getConvertedValue(
+ *         ASN1ObjectIdentifier  oid,
+ *         String               value)
+ *     {
+ *         if (str.length() != 0 &amp;&amp; str.charAt(0) == '#')
+ *         {
+ *             return convertHexEncoded(str, 1);
+ *         }
+ *         if (oid.equals(EmailAddress))
+ *         {
+ *             return new DERIA5String(str);
+ *         }
+ *         else if (canBePrintable(str))
+ *         {
+ *             return new DERPrintableString(str);
+ *         }
+ *         else if (canBeUTF8(str))
+ *         {
+ *             return new DERUTF8String(str);
+ *         }
+ *         else
+ *         {
+ *             return new DERBMPString(str);
+ *         }
+ *     }
+ * }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class X509NameEntryConverter
+{
+    /**
+     * Convert an inline encoded hex string rendition of an ASN.1
+     * object back into its corresponding ASN.1 object.
+     * 
+     * @param str the hex encoded object
+     * @param off the index at which the encoding starts
+     * @return the decoded object
+     */
+    protected ASN1Primitive convertHexEncoded(
+        String  str,
+        int     off)
+        throws IOException
+    {
+        str = Strings.toLowerCase(str);
+        byte[] data = new byte[(str.length() - off) / 2];
+        for (int index = 0; index != data.length; index++)
+        {
+            char left = str.charAt((index * 2) + off);
+            char right = str.charAt((index * 2) + off + 1);
+            
+            if (left < 'a')
+            {
+                data[index] = (byte)((left - '0') << 4);
+            }
+            else
+            {
+                data[index] = (byte)((left - 'a' + 10) << 4);
+            }
+            if (right < 'a')
+            {
+                data[index] |= (byte)(right - '0');
+            }
+            else
+            {
+                data[index] |= (byte)(right - 'a' + 10);
+            }
+        }
+
+        ASN1InputStream aIn = new ASN1InputStream(data);
+                                            
+        return aIn.readObject();
+    }
+    
+    /**
+     * return true if the passed in String can be represented without
+     * loss as a PrintableString, false otherwise.
+     */
+    protected boolean canBePrintable(
+        String  str)
+    {
+        return DERPrintableString.isPrintableString(str);
+    }
+    
+    /**
+     * Convert the passed in String value into the appropriate ASN.1
+     * encoded object.
+     * 
+     * @param oid the oid associated with the value in the DN.
+     * @param value the value of the particular DN component.
+     * @return the ASN.1 equivalent for the value.
+     */
+    public abstract ASN1Primitive getConvertedValue(ASN1ObjectIdentifier oid, String value);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509NameTokenizer.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509NameTokenizer.java
new file mode 100644
index 0000000..6f9a61e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509NameTokenizer.java
@@ -0,0 +1,106 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+/**
+ * class for breaking up an X500 Name into it's component tokens, ala
+ * java.util.StringTokenizer. We need this class as some of the
+ * lightweight Java environment don't support classes like
+ * StringTokenizer.
+ * @deprecated use X500NameTokenizer
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509NameTokenizer
+{
+    private String          value;
+    private int             index;
+    private char separator;
+    private StringBuffer    buf = new StringBuffer();
+
+    public X509NameTokenizer(
+        String  oid)
+    {
+        this(oid, ',');
+    }
+    
+    public X509NameTokenizer(
+        String  oid,
+        char separator)
+    {
+        this.value = oid;
+        this.index = -1;
+        this.separator = separator;
+    }
+
+    public boolean hasMoreTokens()
+    {
+        return (index != value.length());
+    }
+
+    public String nextToken()
+    {
+        if (index == value.length())
+        {
+            return null;
+        }
+
+        int     end = index + 1;
+        boolean quoted = false;
+        boolean escaped = false;
+
+        buf.setLength(0);
+
+        while (end != value.length())
+        {
+            char    c = value.charAt(end);
+
+            if (c == '"')
+            {
+                if (!escaped)
+                {
+                    quoted = !quoted;
+                }
+                buf.append(c);
+                escaped = false;
+            }
+            else
+            {
+                if (escaped || quoted)
+                {
+                    buf.append(c);
+                    escaped = false;
+                }
+                else if (c == '\\')
+                {
+                    buf.append(c);
+                    escaped = true;
+                }
+                else if (c == separator)
+                {
+                    break;
+                }
+                else
+                {
+                    // BEGIN Android-added: Unknown reason
+                    // This was previously marked with the comment "copied from a newer version
+                    // of BouncyCastle", but I couldn't find any evidence that it ever was included
+                    // in any version of BC
+                    if (c == '#' && buf.charAt(buf.length() - 1) == '=')
+                    {
+                        buf.append('\\');
+                    }
+                    else if (c == '+' && separator != '+')
+                    {
+                        buf.append('\\');
+                    }
+                    // END Android-added: Unknown reason
+                    buf.append(c);
+                }
+            }
+            end++;
+        }
+
+        index = end;
+
+        return buf.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
new file mode 100644
index 0000000..ad52e8a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
@@ -0,0 +1,87 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface X509ObjectIdentifiers
+{
+    
+    /** Subject RDN components: commonName = 2.5.4.3 */
+    static final ASN1ObjectIdentifier    commonName              = new ASN1ObjectIdentifier("2.5.4.3").intern();
+    /** Subject RDN components: countryName = 2.5.4.6 */
+    static final ASN1ObjectIdentifier    countryName             = new ASN1ObjectIdentifier("2.5.4.6").intern();
+    /** Subject RDN components: localityName = 2.5.4.7 */
+    static final ASN1ObjectIdentifier    localityName            = new ASN1ObjectIdentifier("2.5.4.7").intern();
+    /** Subject RDN components: stateOrProvinceName = 2.5.4.8 */
+    static final ASN1ObjectIdentifier    stateOrProvinceName     = new ASN1ObjectIdentifier("2.5.4.8").intern();
+    /** Subject RDN components: organization = 2.5.4.10 */
+    static final ASN1ObjectIdentifier    organization            = new ASN1ObjectIdentifier("2.5.4.10").intern();
+    /** Subject RDN components: organizationalUnitName = 2.5.4.11 */
+    static final ASN1ObjectIdentifier    organizationalUnitName  = new ASN1ObjectIdentifier("2.5.4.11").intern();
+
+    /** Subject RDN components: telephone_number = 2.5.4.20 */
+    static final ASN1ObjectIdentifier    id_at_telephoneNumber   = new ASN1ObjectIdentifier("2.5.4.20").intern();
+    /** Subject RDN components: name = 2.5.4.41 */
+    static final ASN1ObjectIdentifier    id_at_name              = new ASN1ObjectIdentifier("2.5.4.41").intern();
+
+    static final ASN1ObjectIdentifier    id_at_organizationIdentifier = new ASN1ObjectIdentifier("2.5.4.97").intern();
+
+    /**
+     * id-SHA1 OBJECT IDENTIFIER ::=    
+     *   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }
+     * <p>
+     * OID: 1.3.14.3.2.27
+     */
+    static final ASN1ObjectIdentifier    id_SHA1                 = new ASN1ObjectIdentifier("1.3.14.3.2.26").intern();
+
+    /**
+     * ripemd160 OBJECT IDENTIFIER ::=
+     *      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)}
+     * <p>
+     * OID: 1.3.36.3.2.1
+     */
+    static final ASN1ObjectIdentifier    ripemd160               = new ASN1ObjectIdentifier("1.3.36.3.2.1").intern();
+
+    /**
+     * ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=
+     *      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }
+     * <p>
+     * OID: 1.3.36.3.3.1.2
+     */
+    static final ASN1ObjectIdentifier    ripemd160WithRSAEncryption = new ASN1ObjectIdentifier("1.3.36.3.3.1.2").intern();
+
+
+    /** OID: 2.5.8.1.1  */
+    static final ASN1ObjectIdentifier    id_ea_rsa = new ASN1ObjectIdentifier("2.5.8.1.1").intern();
+    
+    /** id-pkix OID: 1.3.6.1.5.5.7
+     */
+    static final ASN1ObjectIdentifier  id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7");
+
+    /**
+     * private internet extensions; OID = 1.3.6.1.5.5.7.1
+     */
+    static final ASN1ObjectIdentifier  id_pe   = id_pkix.branch("1");
+
+    /**
+     * ISO ARC for standard certificate and CRL extensions
+     * <p>
+     * OID: 2.5.29
+     */
+    static final ASN1ObjectIdentifier id_ce = new ASN1ObjectIdentifier("2.5.29");
+
+    /** id-pkix OID:         1.3.6.1.5.5.7.48  */
+    static final ASN1ObjectIdentifier  id_ad           = id_pkix.branch("48");
+    /** id-ad-caIssuers OID: 1.3.6.1.5.5.7.48.2  */
+    static final ASN1ObjectIdentifier  id_ad_caIssuers = id_ad.branch("2").intern();
+    /** id-ad-ocsp OID:      1.3.6.1.5.5.7.48.1  */
+    static final ASN1ObjectIdentifier  id_ad_ocsp      = id_ad.branch("1").intern();
+
+    /** OID for ocsp uri in AuthorityInformationAccess extension */
+    static final ASN1ObjectIdentifier ocspAccessMethod = id_ad_ocsp;
+    /** OID for crl uri in AuthorityInformationAccess extension */
+    static final ASN1ObjectIdentifier crlAccessMethod  = id_ad_caIssuers;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DHDomainParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DHDomainParameters.java
new file mode 100644
index 0000000..6cd6c53
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DHDomainParameters.java
@@ -0,0 +1,168 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @deprecated use DomainParameters
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHDomainParameters
+    extends ASN1Object
+{
+    private ASN1Integer p, g, q, j;
+    private DHValidationParms validationParms;
+
+    public static DHDomainParameters getInstance(ASN1TaggedObject obj, boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static DHDomainParameters getInstance(Object obj)
+    {
+        if (obj == null || obj instanceof DHDomainParameters)
+        {
+            return (DHDomainParameters)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new DHDomainParameters((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("Invalid DHDomainParameters: "
+            + obj.getClass().getName());
+    }
+
+    public DHDomainParameters(BigInteger p, BigInteger g, BigInteger q, BigInteger j,
+        DHValidationParms validationParms)
+    {
+        if (p == null)
+        {
+            throw new IllegalArgumentException("'p' cannot be null");
+        }
+        if (g == null)
+        {
+            throw new IllegalArgumentException("'g' cannot be null");
+        }
+        if (q == null)
+        {
+            throw new IllegalArgumentException("'q' cannot be null");
+        }
+
+        this.p = new ASN1Integer(p);
+        this.g = new ASN1Integer(g);
+        this.q = new ASN1Integer(q);
+        this.j = new ASN1Integer(j);
+        this.validationParms = validationParms;
+    }
+
+    public DHDomainParameters(ASN1Integer p, ASN1Integer g, ASN1Integer q, ASN1Integer j,
+        DHValidationParms validationParms)
+    {
+        if (p == null)
+        {
+            throw new IllegalArgumentException("'p' cannot be null");
+        }
+        if (g == null)
+        {
+            throw new IllegalArgumentException("'g' cannot be null");
+        }
+        if (q == null)
+        {
+            throw new IllegalArgumentException("'q' cannot be null");
+        }
+
+        this.p = p;
+        this.g = g;
+        this.q = q;
+        this.j = j;
+        this.validationParms = validationParms;
+    }
+
+    private DHDomainParameters(ASN1Sequence seq)
+    {
+        if (seq.size() < 3 || seq.size() > 5)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        Enumeration e = seq.getObjects();
+        this.p = ASN1Integer.getInstance(e.nextElement());
+        this.g = ASN1Integer.getInstance(e.nextElement());
+        this.q = ASN1Integer.getInstance(e.nextElement());
+
+        ASN1Encodable next = getNext(e);
+
+        if (next != null && next instanceof ASN1Integer)
+        {
+            this.j = ASN1Integer.getInstance(next);
+            next = getNext(e);
+        }
+
+        if (next != null)
+        {
+            this.validationParms = DHValidationParms.getInstance(next.toASN1Primitive());
+        }
+    }
+
+    private static ASN1Encodable getNext(Enumeration e)
+    {
+        return e.hasMoreElements() ? (ASN1Encodable)e.nextElement() : null;
+    }
+
+    public ASN1Integer getP()
+    {
+        return this.p;
+    }
+
+    public ASN1Integer getG()
+    {
+        return this.g;
+    }
+
+    public ASN1Integer getQ()
+    {
+        return this.q;
+    }
+
+    public ASN1Integer getJ()
+    {
+        return this.j;
+    }
+
+    public DHValidationParms getValidationParms()
+    {
+        return this.validationParms;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        v.add(this.p);
+        v.add(this.g);
+        v.add(this.q);
+
+        if (this.j != null)
+        {
+            v.add(this.j);
+        }
+
+        if (this.validationParms != null)
+        {
+            v.add(this.validationParms);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DHPublicKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DHPublicKey.java
new file mode 100644
index 0000000..a3f5053
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DHPublicKey.java
@@ -0,0 +1,100 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+
+/**
+ * X9.42 definition of a DHPublicKey
+ * <pre>
+ *     DHPublicKey ::= INTEGER
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHPublicKey
+    extends ASN1Object
+{
+    private ASN1Integer y;
+
+    /**
+     * Return a DHPublicKey from the passed in tagged object.
+     *
+     * @param obj a tagged object.
+     * @param explicit true if the contents of the object is explictly tagged, false otherwise.
+     * @return a DHPublicKey
+     */
+    public static DHPublicKey getInstance(ASN1TaggedObject obj, boolean explicit)
+    {
+        return getInstance(ASN1Integer.getInstance(obj, explicit));
+    }
+
+    /**
+     * Return a DHPublicKey from the passed in object.
+     *
+     * @param obj an object for conversion or a byte[].
+     * @return a DHPublicKey
+     */
+    public static DHPublicKey getInstance(Object obj)
+    {
+        if (obj == null || obj instanceof DHPublicKey)
+        {
+            return (DHPublicKey)obj;
+        }
+
+        if (obj instanceof ASN1Integer)
+        {
+            return new DHPublicKey((ASN1Integer)obj);
+        }
+
+        throw new IllegalArgumentException("Invalid DHPublicKey: " + obj.getClass().getName());
+    }
+
+    private DHPublicKey(ASN1Integer y)
+    {
+        if (y == null)
+        {
+            throw new IllegalArgumentException("'y' cannot be null");
+        }
+
+        this.y = y;
+    }
+
+    /**
+     * Base constructor.
+     *
+     * @param y the public value Y.
+     */
+    public DHPublicKey(BigInteger y)
+    {
+        if (y == null)
+        {
+            throw new IllegalArgumentException("'y' cannot be null");
+        }
+
+        this.y = new ASN1Integer(y);
+    }
+
+    /**
+     * Return the public value Y for the key.
+     *
+     * @return the Y value.
+     */
+    public BigInteger getY()
+    {
+        return this.y.getPositiveValue();
+    }
+
+    /**
+     * Return an ASN.1 primitive representation of this object.
+     *
+     * @return an ASN1Integer.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return this.y;
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DHValidationParms.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DHValidationParms.java
new file mode 100644
index 0000000..72b8a57
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DHValidationParms.java
@@ -0,0 +1,84 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @deprecated use ValidationParams
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHValidationParms extends ASN1Object
+{
+    private DERBitString seed;
+    private ASN1Integer pgenCounter;
+
+    public static DHValidationParms getInstance(ASN1TaggedObject obj, boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static DHValidationParms getInstance(Object obj)
+    {
+        if (obj instanceof DHValidationParms)
+        {
+            return (DHValidationParms)obj;
+        }
+        else if (obj != null)
+        {
+            return new DHValidationParms(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public DHValidationParms(DERBitString seed, ASN1Integer pgenCounter)
+    {
+        if (seed == null)
+        {
+            throw new IllegalArgumentException("'seed' cannot be null");
+        }
+        if (pgenCounter == null)
+        {
+            throw new IllegalArgumentException("'pgenCounter' cannot be null");
+        }
+
+        this.seed = seed;
+        this.pgenCounter = pgenCounter;
+    }
+
+    private DHValidationParms(ASN1Sequence seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        this.seed = DERBitString.getInstance(seq.getObjectAt(0));
+        this.pgenCounter = ASN1Integer.getInstance(seq.getObjectAt(1));
+    }
+
+    public DERBitString getSeed()
+    {
+        return this.seed;
+    }
+
+    public ASN1Integer getPgenCounter()
+    {
+        return this.pgenCounter;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        v.add(this.seed);
+        v.add(this.pgenCounter);
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DomainParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DomainParameters.java
new file mode 100644
index 0000000..e87341b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/DomainParameters.java
@@ -0,0 +1,225 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * X9.44 Diffie-Hellman domain parameters.
+ * <pre>
+ *    DomainParameters ::= SEQUENCE {
+ *       p                INTEGER,           -- odd prime, p=jq +1
+ *       g                INTEGER,           -- generator, g
+ *       q                INTEGER,           -- factor of p-1
+ *       j                INTEGER OPTIONAL,  -- subgroup factor, j &gt;= 2
+ *       validationParams  ValidationParams OPTIONAL
+ *    }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DomainParameters
+    extends ASN1Object
+{
+    private final ASN1Integer p, g, q, j;
+    private final ValidationParams validationParams;
+
+    /**
+     * Return a DomainParameters object from the passed in tagged object.
+     *
+     * @param obj a tagged object.
+     * @param explicit true if the contents of the object is explictly tagged, false otherwise.
+     * @return a DomainParameters
+     */
+    public static DomainParameters getInstance(ASN1TaggedObject obj, boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    /**
+     * Return a DomainParameters object from the passed in object.
+     *
+     * @param obj an object for conversion or a byte[].
+     * @return a DomainParameters
+     */
+    public static DomainParameters getInstance(Object obj)
+    {
+        if (obj instanceof DomainParameters)
+        {
+            return (DomainParameters)obj;
+        }
+        else if (obj != null)
+        {
+            return new DomainParameters(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    /**
+     * Base constructor - the full domain parameter set.
+     *
+     * @param p the prime p defining the Galois field.
+     * @param g the generator of the multiplicative subgroup of order g.
+     * @param q specifies the prime factor of p - 1
+     * @param j optionally specifies the value that satisfies the equation p = jq+1
+     * @param validationParams parameters for validating these domain parameters.
+     */
+    public DomainParameters(BigInteger p, BigInteger g, BigInteger q, BigInteger j,
+                            ValidationParams validationParams)
+    {
+        if (p == null)
+        {
+            throw new IllegalArgumentException("'p' cannot be null");
+        }
+        if (g == null)
+        {
+            throw new IllegalArgumentException("'g' cannot be null");
+        }
+        if (q == null)
+        {
+            throw new IllegalArgumentException("'q' cannot be null");
+        }
+
+        this.p = new ASN1Integer(p);
+        this.g = new ASN1Integer(g);
+        this.q = new ASN1Integer(q);
+
+        if (j != null)
+        {
+            this.j = new ASN1Integer(j);
+        }
+        else
+        {
+            this.j = null;
+        }
+        this.validationParams = validationParams;
+    }
+
+    private DomainParameters(ASN1Sequence seq)
+    {
+        if (seq.size() < 3 || seq.size() > 5)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        Enumeration e = seq.getObjects();
+        this.p = ASN1Integer.getInstance(e.nextElement());
+        this.g = ASN1Integer.getInstance(e.nextElement());
+        this.q = ASN1Integer.getInstance(e.nextElement());
+
+        ASN1Encodable next = getNext(e);
+
+        if (next != null && next instanceof ASN1Integer)
+        {
+            this.j = ASN1Integer.getInstance(next);
+            next = getNext(e);
+        }
+        else
+        {
+            this.j = null;
+        }
+
+        if (next != null)
+        {
+            this.validationParams = ValidationParams.getInstance(next.toASN1Primitive());
+        }
+        else
+        {
+            this.validationParams = null;
+        }
+    }
+
+    private static ASN1Encodable getNext(Enumeration e)
+    {
+        return e.hasMoreElements() ? (ASN1Encodable)e.nextElement() : null;
+    }
+
+    /**
+     * Return the prime p defining the Galois field.
+     *
+     * @return the prime p.
+     */
+    public BigInteger getP()
+    {
+        return this.p.getPositiveValue();
+    }
+
+    /**
+     * Return the generator of the multiplicative subgroup of order g.
+     *
+     * @return the generator g.
+     */
+    public BigInteger getG()
+    {
+        return this.g.getPositiveValue();
+    }
+
+    /**
+     * Return q, the prime factor of p - 1
+     *
+     * @return q value
+     */
+    public BigInteger getQ()
+    {
+        return this.q.getPositiveValue();
+    }
+
+    /**
+     * Return the value that satisfies the equation p = jq+1 (if present).
+     *
+     * @return j value or null.
+     */
+    public BigInteger getJ()
+    {
+        if (this.j == null)
+        {
+            return null;
+        }
+
+        return this.j.getPositiveValue();
+    }
+
+    /**
+     * Return the validation parameters for this set (if present).
+     *
+     * @return validation parameters, or null if absent.
+     */
+    public ValidationParams getValidationParams()
+    {
+        return this.validationParams;
+    }
+
+    /**
+     * Return an ASN.1 primitive representation of this object.
+     *
+     * @return a DERSequence containing the parameter values.
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        v.add(this.p);
+        v.add(this.g);
+        v.add(this.q);
+
+        if (this.j != null)
+        {
+            v.add(this.j);
+        }
+
+        if (this.validationParams != null)
+        {
+            v.add(this.validationParams);
+        }
+
+        return new DERSequence(v);
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/ECNamedCurveTable.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/ECNamedCurveTable.java
new file mode 100644
index 0000000..b957e28
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/ECNamedCurveTable.java
@@ -0,0 +1,258 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+// Android-removed: Unsupported curves
+// import org.bouncycastle.asn1.anssi.ANSSINamedCurves;
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+// import org.bouncycastle.asn1.gm.GMNamedCurves;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTNamedCurves;
+import com.android.internal.org.bouncycastle.asn1.sec.SECNamedCurves;
+// Android-removed: Unsupported curves
+// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import com.android.internal.org.bouncycastle.crypto.ec.CustomNamedCurves;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+
+/**
+ * A general class that reads all X9.62 style EC curve tables.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECNamedCurveTable
+{
+    /**
+     * return a X9ECParameters object representing the passed in named
+     * curve. The routine returns null if the curve is not present.
+     *
+     * @param name the name of the curve requested
+     * @return an X9ECParameters object or null if the curve is not available.
+     */
+    public static X9ECParameters getByName(
+        String name)
+    {
+        X9ECParameters ecP = X962NamedCurves.getByName(name);
+
+        if (ecP == null)
+        {
+            ecP = SECNamedCurves.getByName(name);
+        }
+
+        if (ecP == null)
+        {
+            ecP = NISTNamedCurves.getByName(name);
+        }
+
+        // BEGIN Android-removed: Unsupported curves
+        /*
+        if (ecP == null)
+        {
+            ecP = TeleTrusTNamedCurves.getByName(name);
+        }
+
+        if (ecP == null)
+        {
+            ecP = ANSSINamedCurves.getByName(name);
+        }
+
+        if (ecP == null)
+        {
+            ecP = fromDomainParameters(ECGOST3410NamedCurves.getByName(name));
+        }
+
+        if (ecP == null)
+        {
+            ecP = GMNamedCurves.getByName(name);
+        }
+        */
+        // END Android-removed: Unsupported curves
+
+        return ecP;
+    }
+
+    /**
+     * return the object identifier signified by the passed in name. Null
+     * if there is no object identifier associated with name.
+     *
+     * @return the object identifier associated with name, if present.
+     */
+    public static ASN1ObjectIdentifier getOID(
+        String name)
+    {
+        ASN1ObjectIdentifier oid = X962NamedCurves.getOID(name);
+
+        if (oid == null)
+        {
+            oid = SECNamedCurves.getOID(name);
+        }
+
+        if (oid == null)
+        {
+            oid = NISTNamedCurves.getOID(name);
+        }
+
+        // BEGIN Android-removed: Unsupported curves
+        /*
+        if (oid == null)
+        {
+            oid = TeleTrusTNamedCurves.getOID(name);
+        }
+
+        if (oid == null)
+        {
+            oid = ANSSINamedCurves.getOID(name);
+        }
+
+        if (oid == null)
+        {
+            oid = ECGOST3410NamedCurves.getOID(name);
+        }
+
+        if (oid == null)
+        {
+            oid = GMNamedCurves.getOID(name);
+        }
+        */
+        // END Android-removed: Unsupported curves
+
+        return oid;
+    }
+
+    /**
+     * return a X9ECParameters object representing the passed in named
+     * curve.
+     *
+     * @param oid the object id of the curve requested
+     * @return a standard name for the curve.
+     */
+    public static String getName(
+        ASN1ObjectIdentifier oid)
+    {
+        String name = X962NamedCurves.getName(oid);
+
+        if (name == null)
+        {
+            name = SECNamedCurves.getName(oid);
+        }
+
+        if (name == null)
+        {
+            name = NISTNamedCurves.getName(oid);
+        }
+
+        // BEGIN Android-removed: Unsupported curves
+        /*
+        if (name == null)
+        {
+            name = TeleTrusTNamedCurves.getName(oid);
+        }
+
+        if (name == null)
+        {
+            name = ANSSINamedCurves.getName(oid);
+        }
+
+        if (name == null)
+        {
+            name = ECGOST3410NamedCurves.getName(oid);
+        }
+
+        if (name == null)
+        {
+            name = GMNamedCurves.getName(oid);
+        }
+
+        if (name == null)
+        {
+            name = CustomNamedCurves.getName(oid);
+        }
+        */
+        // END Android-removed: Unsupported curves
+
+        return name;
+    }
+
+    /**
+     * return a X9ECParameters object representing the passed in named
+     * curve.
+     *
+     * @param oid the object id of the curve requested
+     * @return an X9ECParameters object or null if the curve is not available.
+     */
+    public static X9ECParameters getByOID(
+        ASN1ObjectIdentifier oid)
+    {
+        X9ECParameters ecP = X962NamedCurves.getByOID(oid);
+
+        if (ecP == null)
+        {
+            ecP = SECNamedCurves.getByOID(oid);
+        }
+
+        // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup
+
+        // BEGIN Android-removed: Unsupported curves
+        /*
+        if (ecP == null)
+        {
+            ecP = TeleTrusTNamedCurves.getByOID(oid);
+        }
+
+        if (ecP == null)
+        {
+            ecP = ANSSINamedCurves.getByOID(oid);
+        }
+
+        if (ecP == null)
+        {
+            ecP = fromDomainParameters(ECGOST3410NamedCurves.getByOID(oid));
+        }
+
+        if (ecP == null)
+        {
+            ecP = GMNamedCurves.getByOID(oid);
+        }
+        */
+        // END Android-removed: Unsupported curves
+
+        return ecP;
+    }
+
+    /**
+     * return an enumeration of the names of the available curves.
+     *
+     * @return an enumeration of the names of the available curves.
+     */
+    public static Enumeration getNames()
+    {
+        Vector v = new Vector();
+
+        addEnumeration(v, X962NamedCurves.getNames());
+        addEnumeration(v, SECNamedCurves.getNames());
+        addEnumeration(v, NISTNamedCurves.getNames());
+        // BEGIN Android-removed: Unsupported curves
+        // addEnumeration(v, TeleTrusTNamedCurves.getNames());
+        // addEnumeration(v, ANSSINamedCurves.getNames());
+        // addEnumeration(v, ECGOST3410NamedCurves.getNames());
+        // addEnumeration(v, GMNamedCurves.getNames());
+        // END Android-removed: Unsupported curves
+
+        return v.elements();
+    }
+
+    private static void addEnumeration(
+        Vector v,
+        Enumeration e)
+    {
+        while (e.hasMoreElements())
+        {
+            v.addElement(e.nextElement());
+        }
+    }
+
+    private static X9ECParameters fromDomainParameters(ECDomainParameters dp)
+    {
+        return dp == null ? null : new X9ECParameters(dp.getCurve(), dp.getG(), dp.getN(), dp.getH(), dp.getSeed());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/ValidationParams.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/ValidationParams.java
new file mode 100644
index 0000000..4206c7d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/ValidationParams.java
@@ -0,0 +1,104 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * Diffie-Hellman domain validation parameters.
+ * <pre>
+ * ValidationParams ::= SEQUENCE {
+ *    seed         BIT STRING,
+ *    pgenCounter  INTEGER
+ * }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ValidationParams
+    extends ASN1Object
+{
+    private DERBitString seed;
+    private ASN1Integer pgenCounter;
+
+    public static ValidationParams getInstance(ASN1TaggedObject obj, boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static ValidationParams getInstance(Object obj)
+    {
+        if (obj instanceof ValidationParams)
+        {
+            return (ValidationParams)obj;
+        }
+        else if (obj != null)
+        {
+            return new ValidationParams(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public ValidationParams(byte[] seed, int pgenCounter)
+    {
+        if (seed == null)
+        {
+            throw new IllegalArgumentException("'seed' cannot be null");
+        }
+
+        this.seed = new DERBitString(seed);
+        this.pgenCounter = new ASN1Integer(pgenCounter);
+    }
+
+    public ValidationParams(DERBitString seed, ASN1Integer pgenCounter)
+    {
+        if (seed == null)
+        {
+            throw new IllegalArgumentException("'seed' cannot be null");
+        }
+        if (pgenCounter == null)
+        {
+            throw new IllegalArgumentException("'pgenCounter' cannot be null");
+        }
+
+        this.seed = seed;
+        this.pgenCounter = pgenCounter;
+    }
+
+    private ValidationParams(ASN1Sequence seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        this.seed = DERBitString.getInstance(seq.getObjectAt(0));
+        this.pgenCounter = ASN1Integer.getInstance(seq.getObjectAt(1));
+    }
+
+    public byte[] getSeed()
+    {
+        return this.seed.getBytes();
+    }
+
+    public BigInteger getPgenCounter()
+    {
+        return this.pgenCounter.getPositiveValue();
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        v.add(this.seed);
+        v.add(this.pgenCounter);
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X962NamedCurves.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X962NamedCurves.java
new file mode 100644
index 0000000..04e2b10
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X962NamedCurves.java
@@ -0,0 +1,644 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+
+/**
+ * Table of the current named curves defined in X.962 EC-DSA.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X962NamedCurves
+{
+    static X9ECParametersHolder prime192v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger n = new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16);
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve cFp192v1 = new ECCurve.Fp(
+                new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16),
+                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+                new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16),
+                n, h);
+
+            return new X9ECParameters(
+                cFp192v1,
+                new X9ECPoint(cFp192v1,
+                    Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")),
+                n, h,
+                Hex.decode("3045AE6FC8422f64ED579528D38120EAE12196D5"));
+        }
+    };
+
+    static X9ECParametersHolder prime192v2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger n = new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16);
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve cFp192v2 = new ECCurve.Fp(
+                new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16),
+                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+                new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16),
+                n, h);
+
+            return new X9ECParameters(
+                cFp192v2,
+                new X9ECPoint(cFp192v2,
+                    Hex.decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")),
+                n, h,
+                Hex.decode("31a92ee2029fd10d901b113e990710f0d21ac6b6"));
+        }
+    };
+
+    static X9ECParametersHolder prime192v3 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger n = new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16);
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve cFp192v3 = new ECCurve.Fp(
+                new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16),
+                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+                new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16),
+                n, h);
+
+            return new X9ECParameters(
+                cFp192v3,
+                new X9ECPoint(cFp192v3,
+                    Hex.decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")),
+                n, h,
+                Hex.decode("c469684435deb378c4b65ca9591e2a5763059a2e"));
+        }
+    };
+
+    static X9ECParametersHolder prime239v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger n = new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16);
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve cFp239v1 = new ECCurve.Fp(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16),
+                n, h);
+
+            return new X9ECParameters(
+                cFp239v1,
+                new X9ECPoint(cFp239v1,
+                    Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")),
+                n, h,
+                Hex.decode("e43bb460f0b80cc0c0b075798e948060f8321b7d"));
+        }
+    };
+
+    static X9ECParametersHolder prime239v2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger n = new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16);
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve cFp239v2 = new ECCurve.Fp(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+                new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16),
+                n, h);
+
+            return new X9ECParameters(
+                cFp239v2,
+                new X9ECPoint(cFp239v2,
+                    Hex.decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")),
+                n, h,
+                Hex.decode("e8b4011604095303ca3b8099982be09fcb9ae616"));
+        }
+    };
+
+    static X9ECParametersHolder prime239v3 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger n = new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16);
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve cFp239v3 = new ECCurve.Fp(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+                new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16),
+                n, h);
+
+            return new X9ECParameters(
+                cFp239v3,
+                new X9ECPoint(cFp239v3,
+                    Hex.decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")),
+                n, h,
+                Hex.decode("7d7374168ffe3471b60a857686a19475d3bfa2ff"));
+        }
+    };
+
+    static X9ECParametersHolder prime256v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger n = new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16);
+            BigInteger h = BigInteger.valueOf(1);
+
+            ECCurve cFp256v1 = new ECCurve.Fp(
+                new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"),
+                new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+                new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+                n, h);
+
+            return new X9ECParameters(
+                cFp256v1,
+                new X9ECPoint(cFp256v1,
+                    Hex.decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")),
+                n, h,
+                Hex.decode("c49d360886e704936a6678e1139d26b7819f7e90"));
+        }
+    };
+
+    /*
+     * F2m Curves
+     */
+    static X9ECParametersHolder c2pnb163v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m163v1n = new BigInteger("0400000000000000000001E60FC8821CC74DAEAFC1", 16);
+            BigInteger c2m163v1h = BigInteger.valueOf(2);
+
+            ECCurve c2m163v1 = new ECCurve.F2m(
+                163,
+                1, 2, 8,
+                new BigInteger("072546B5435234A422E0789675F432C89435DE5242", 16),
+                new BigInteger("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", 16),
+                c2m163v1n, c2m163v1h);
+
+            return new X9ECParameters(
+                c2m163v1,
+                new X9ECPoint(c2m163v1,
+                    Hex.decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")),
+                c2m163v1n, c2m163v1h,
+                Hex.decode("D2C0FB15760860DEF1EEF4D696E6768756151754"));
+        }
+    };
+
+    static X9ECParametersHolder c2pnb163v2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m163v2n = new BigInteger("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 16);
+            BigInteger c2m163v2h = BigInteger.valueOf(2);
+
+            ECCurve c2m163v2 = new ECCurve.F2m(
+                163,
+                1, 2, 8,
+                new BigInteger("0108B39E77C4B108BED981ED0E890E117C511CF072", 16),
+                new BigInteger("0667ACEB38AF4E488C407433FFAE4F1C811638DF20", 16),
+                c2m163v2n, c2m163v2h);
+
+            return new X9ECParameters(
+                c2m163v2,
+                new X9ECPoint(c2m163v2,
+                    Hex.decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")),
+                c2m163v2n, c2m163v2h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb163v3 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m163v3n = new BigInteger("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 16);
+            BigInteger c2m163v3h = BigInteger.valueOf(2);
+
+            ECCurve c2m163v3 = new ECCurve.F2m(
+                163,
+                1, 2, 8,
+                new BigInteger("07A526C63D3E25A256A007699F5447E32AE456B50E", 16),
+                new BigInteger("03F7061798EB99E238FD6F1BF95B48FEEB4854252B", 16),
+                c2m163v3n, c2m163v3h);
+
+            return new X9ECParameters(
+                c2m163v3,
+                new X9ECPoint(c2m163v3,
+                    Hex.decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")),
+                c2m163v3n, c2m163v3h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb176w1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m176w1n = new BigInteger("010092537397ECA4F6145799D62B0A19CE06FE26AD", 16);
+            BigInteger c2m176w1h = BigInteger.valueOf(0xFF6E);
+
+            ECCurve c2m176w1 = new ECCurve.F2m(
+                176,
+                1, 2, 43,
+                new BigInteger("00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", 16),
+                new BigInteger("005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", 16),
+                c2m176w1n, c2m176w1h);
+
+            return new X9ECParameters(
+                c2m176w1,
+                new X9ECPoint(c2m176w1,
+                    Hex.decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")),
+                c2m176w1n, c2m176w1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb191v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m191v1n = new BigInteger("40000000000000000000000004A20E90C39067C893BBB9A5", 16);
+            BigInteger c2m191v1h = BigInteger.valueOf(2);
+
+            ECCurve c2m191v1 = new ECCurve.F2m(
+                191,
+                9,
+                new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16),
+                new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16),
+                c2m191v1n, c2m191v1h);
+
+            return new X9ECParameters(
+                c2m191v1,
+                new X9ECPoint(c2m191v1,
+                    Hex.decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")),
+                c2m191v1n, c2m191v1h,
+                Hex.decode("4E13CA542744D696E67687561517552F279A8C84"));
+        }
+    };
+
+    static X9ECParametersHolder c2tnb191v2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m191v2n = new BigInteger("20000000000000000000000050508CB89F652824E06B8173", 16);
+            BigInteger c2m191v2h = BigInteger.valueOf(4);
+
+            ECCurve c2m191v2 = new ECCurve.F2m(
+                191,
+                9,
+                new BigInteger("401028774D7777C7B7666D1366EA432071274F89FF01E718", 16),
+                new BigInteger("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", 16),
+                c2m191v2n, c2m191v2h);
+
+            return new X9ECParameters(
+                c2m191v2,
+                new X9ECPoint(c2m191v2,
+                    Hex.decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")),
+                c2m191v2n, c2m191v2h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb191v3 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m191v3n = new BigInteger("155555555555555555555555610C0B196812BFB6288A3EA3", 16);
+            BigInteger c2m191v3h = BigInteger.valueOf(6);
+
+            ECCurve c2m191v3 = new ECCurve.F2m(
+                191,
+                9,
+                new BigInteger("6C01074756099122221056911C77D77E77A777E7E7E77FCB", 16),
+                new BigInteger("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", 16),
+                c2m191v3n, c2m191v3h);
+
+            return new X9ECParameters(
+                c2m191v3,
+                new X9ECPoint(c2m191v3,
+                    Hex.decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")),
+                c2m191v3n, c2m191v3h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb208w1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m208w1n = new BigInteger("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 16);
+            BigInteger c2m208w1h = BigInteger.valueOf(0xFE48);
+
+            ECCurve c2m208w1 = new ECCurve.F2m(
+                208,
+                1, 2, 83,
+                new BigInteger("0", 16),
+                new BigInteger("00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", 16),
+                c2m208w1n, c2m208w1h);
+
+            return new X9ECParameters(
+                c2m208w1,
+                new X9ECPoint(c2m208w1,
+                    Hex.decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")),
+                c2m208w1n, c2m208w1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb239v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m239v1n = new BigInteger("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 16);
+            BigInteger c2m239v1h = BigInteger.valueOf(4);
+
+            ECCurve c2m239v1 = new ECCurve.F2m(
+                239,
+                36,
+                new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16),
+                new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16),
+                c2m239v1n, c2m239v1h);
+
+            return new X9ECParameters(
+                c2m239v1,
+                new X9ECPoint(c2m239v1,
+                    Hex.decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")),
+                c2m239v1n, c2m239v1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb239v2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m239v2n = new BigInteger("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 16);
+            BigInteger c2m239v2h = BigInteger.valueOf(6);
+
+            ECCurve c2m239v2 = new ECCurve.F2m(
+                239,
+                36,
+                new BigInteger("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", 16),
+                new BigInteger("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", 16),
+                c2m239v2n, c2m239v2h);
+
+            return new X9ECParameters(
+                c2m239v2,
+                new X9ECPoint(c2m239v2,
+                    Hex.decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")),
+                c2m239v2n, c2m239v2h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb239v3 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m239v3n = new BigInteger("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 16);
+            BigInteger c2m239v3h = BigInteger.valueOf(10);
+
+            ECCurve c2m239v3 = new ECCurve.F2m(
+                239,
+                36,
+                new BigInteger("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", 16),
+                new BigInteger("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", 16),
+                c2m239v3n, c2m239v3h);
+
+            return new X9ECParameters(
+                c2m239v3,
+                new X9ECPoint(c2m239v3,
+                    Hex.decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")),
+                c2m239v3n, c2m239v3h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb272w1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m272w1n = new BigInteger("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", 16);
+            BigInteger c2m272w1h = BigInteger.valueOf(0xFF06);
+
+            ECCurve c2m272w1 = new ECCurve.F2m(
+                272,
+                1, 3, 56,
+                new BigInteger("0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", 16),
+                new BigInteger("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", 16),
+                c2m272w1n, c2m272w1h);
+
+            return new X9ECParameters(
+                c2m272w1,
+                new X9ECPoint(c2m272w1,
+                    Hex.decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")),
+                c2m272w1n, c2m272w1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb304w1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m304w1n = new BigInteger("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 16);
+            BigInteger c2m304w1h = BigInteger.valueOf(0xFE2E);
+
+            ECCurve c2m304w1 = new ECCurve.F2m(
+                304,
+                1, 2, 11,
+                new BigInteger("00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", 16),
+                new BigInteger("00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", 16),
+                c2m304w1n, c2m304w1h);
+
+            return new X9ECParameters(
+                c2m304w1,
+                new X9ECPoint(c2m304w1,
+                    Hex.decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")),
+                c2m304w1n, c2m304w1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb359v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m359v1n = new BigInteger("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 16);
+            BigInteger c2m359v1h = BigInteger.valueOf(0x4C);
+
+            ECCurve c2m359v1 = new ECCurve.F2m(
+                359,
+                68,
+                new BigInteger("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", 16),
+                new BigInteger("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", 16),
+                c2m359v1n, c2m359v1h);
+
+            return new X9ECParameters(
+                c2m359v1,
+                new X9ECPoint(c2m359v1,
+                    Hex.decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")),
+                c2m359v1n, c2m359v1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2pnb368w1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m368w1n = new BigInteger("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 16);
+            BigInteger c2m368w1h = BigInteger.valueOf(0xFF70);
+
+            ECCurve c2m368w1 = new ECCurve.F2m(
+                368,
+                1, 2, 85,
+                new BigInteger("00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", 16),
+                new BigInteger("00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", 16),
+                c2m368w1n, c2m368w1h);
+
+            return new X9ECParameters(
+                c2m368w1,
+                new X9ECPoint(c2m368w1,
+                    Hex.decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")),
+                c2m368w1n, c2m368w1h,
+                null);
+        }
+    };
+
+    static X9ECParametersHolder c2tnb431r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            BigInteger c2m431r1n = new BigInteger("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 16);
+            BigInteger c2m431r1h = BigInteger.valueOf(0x2760);
+
+            ECCurve c2m431r1 = new ECCurve.F2m(
+                431,
+                120,
+                new BigInteger("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", 16),
+                new BigInteger("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", 16),
+                c2m431r1n, c2m431r1h);
+
+            return new X9ECParameters(
+                c2m431r1,
+                new X9ECPoint(c2m431r1,
+                    Hex.decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")),
+                c2m431r1n, c2m431r1h,
+                null);
+        }
+    };
+
+    static final Hashtable objIds = new Hashtable();
+    static final Hashtable curves = new Hashtable();
+    static final Hashtable names = new Hashtable();
+
+    static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
+    {
+        objIds.put(name, oid);
+        names.put(oid, name);
+        curves.put(oid, holder);
+    }
+
+    static
+    {
+        defineCurve("prime192v1", X9ObjectIdentifiers.prime192v1, prime192v1);
+        defineCurve("prime192v2", X9ObjectIdentifiers.prime192v2, prime192v2);
+        defineCurve("prime192v3", X9ObjectIdentifiers.prime192v3, prime192v3);
+        defineCurve("prime239v1", X9ObjectIdentifiers.prime239v1, prime239v1);
+        defineCurve("prime239v2", X9ObjectIdentifiers.prime239v2, prime239v2);
+        defineCurve("prime239v3", X9ObjectIdentifiers.prime239v3, prime239v3);
+        defineCurve("prime256v1", X9ObjectIdentifiers.prime256v1, prime256v1);
+        defineCurve("c2pnb163v1", X9ObjectIdentifiers.c2pnb163v1, c2pnb163v1);
+        defineCurve("c2pnb163v2", X9ObjectIdentifiers.c2pnb163v2, c2pnb163v2);
+        defineCurve("c2pnb163v3", X9ObjectIdentifiers.c2pnb163v3, c2pnb163v3);
+        defineCurve("c2pnb176w1", X9ObjectIdentifiers.c2pnb176w1, c2pnb176w1);
+        defineCurve("c2tnb191v1", X9ObjectIdentifiers.c2tnb191v1, c2tnb191v1);
+        defineCurve("c2tnb191v2", X9ObjectIdentifiers.c2tnb191v2, c2tnb191v2);
+        defineCurve("c2tnb191v3", X9ObjectIdentifiers.c2tnb191v3, c2tnb191v3);
+        defineCurve("c2pnb208w1", X9ObjectIdentifiers.c2pnb208w1, c2pnb208w1);
+        defineCurve("c2tnb239v1", X9ObjectIdentifiers.c2tnb239v1, c2tnb239v1);
+        defineCurve("c2tnb239v2", X9ObjectIdentifiers.c2tnb239v2, c2tnb239v2);
+        defineCurve("c2tnb239v3", X9ObjectIdentifiers.c2tnb239v3, c2tnb239v3);
+        defineCurve("c2pnb272w1", X9ObjectIdentifiers.c2pnb272w1, c2pnb272w1);
+        defineCurve("c2pnb304w1", X9ObjectIdentifiers.c2pnb304w1, c2pnb304w1);
+        defineCurve("c2tnb359v1", X9ObjectIdentifiers.c2tnb359v1, c2tnb359v1);
+        defineCurve("c2pnb368w1", X9ObjectIdentifiers.c2pnb368w1, c2pnb368w1);
+        defineCurve("c2tnb431r1", X9ObjectIdentifiers.c2tnb431r1, c2tnb431r1);
+    }
+
+    public static X9ECParameters getByName(
+        String name)
+    {
+        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+
+        if (oid != null)
+        {
+            return getByOID(oid);
+        }
+
+        return null;
+    }
+
+    /**
+     * return the X9ECParameters object for the named curve represented by
+     * the passed in object identifier. Null if the curve isn't present.
+     *
+     * @param oid an object identifier representing a named curve, if present.
+     */
+    public static X9ECParameters getByOID(
+        ASN1ObjectIdentifier oid)
+    {
+        X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);
+
+        if (holder != null)
+        {
+            return holder.getParameters();
+        }
+
+        return null;
+    }
+
+    /**
+     * return the object identifier signified by the passed in name. Null
+     * if there is no object identifier associated with name.
+     *
+     * @return the object identifier associated with name, if present.
+     */
+    public static ASN1ObjectIdentifier getOID(
+        String name)
+    {
+        return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+    }
+
+    /**
+     * return the named curve name represented by the given object identifier.
+     */
+    public static String getName(
+        ASN1ObjectIdentifier oid)
+    {
+        return (String)names.get(oid);
+    }
+
+    /**
+     * returns an enumeration containing the name strings for curves
+     * contained in this structure.
+     */
+    public static Enumeration getNames()
+    {
+        return objIds.keys();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X962Parameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X962Parameters.java
new file mode 100644
index 0000000..d77c6ab
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X962Parameters.java
@@ -0,0 +1,114 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.io.IOException;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Choice;
+import com.android.internal.org.bouncycastle.asn1.ASN1Null;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+
+/**
+ * The Parameters ASN.1 CHOICE from X9.62.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X962Parameters
+    extends ASN1Object
+    implements ASN1Choice
+{
+    private ASN1Primitive           params = null;
+
+    public static X962Parameters getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof X962Parameters) 
+        {
+            return (X962Parameters)obj;
+        }
+        
+        if (obj instanceof ASN1Primitive) 
+        {
+            return new X962Parameters((ASN1Primitive)obj);
+        }
+
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return new X962Parameters(ASN1Primitive.fromByteArray((byte[])obj));
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("unable to parse encoded data: " + e.getMessage());
+            }
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance()");
+    }
+    
+    public static X962Parameters getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject()); // must be explicitly tagged
+    }
+    
+    public X962Parameters(
+        X9ECParameters      ecParameters)
+    {
+        this.params = ecParameters.toASN1Primitive();
+    }
+
+    public X962Parameters(
+        ASN1ObjectIdentifier  namedCurve)
+    {
+        this.params = namedCurve;
+    }
+
+    public X962Parameters(
+        ASN1Null           obj)
+    {
+        this.params = obj;
+    }
+
+    /**
+     * @deprecated use getInstance()
+     */
+    public X962Parameters(
+        ASN1Primitive           obj)
+    {
+        this.params = obj;
+    }
+
+    public boolean isNamedCurve()
+    {
+        return (params instanceof ASN1ObjectIdentifier);
+    }
+
+    public boolean isImplicitlyCA()
+    {
+        return (params instanceof ASN1Null);
+    }
+
+    public ASN1Primitive getParameters()
+    {
+        return params;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Parameters ::= CHOICE {
+     *    ecParameters ECParameters,
+     *    namedCurve   CURVES.&amp;id({CurveNames}),
+     *    implicitlyCA NULL
+     * }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return params;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9Curve.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9Curve.java
new file mode 100644
index 0000000..f2adedd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9Curve.java
@@ -0,0 +1,164 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.math.ec.ECAlgorithms;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * ASN.1 def for Elliptic-Curve Curve structure. See
+ * X9.62, for further details.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X9Curve
+    extends ASN1Object
+    implements X9ObjectIdentifiers
+{
+    private ECCurve     curve;
+    private byte[]      seed;
+    private ASN1ObjectIdentifier fieldIdentifier = null;
+
+    public X9Curve(
+        ECCurve     curve)
+    {
+        this(curve, null);
+    }
+
+    public X9Curve(
+        ECCurve     curve,
+        byte[]      seed)
+    {
+        this.curve = curve;
+        this.seed = Arrays.clone(seed);
+        setFieldIdentifier();
+    }
+
+    public X9Curve(
+        X9FieldID     fieldID,
+        BigInteger    order,
+        BigInteger    cofactor,
+        ASN1Sequence  seq)
+    {   
+        fieldIdentifier = fieldID.getIdentifier();
+        if (fieldIdentifier.equals(prime_field))
+        {   
+            BigInteger p = ((ASN1Integer)fieldID.getParameters()).getValue();
+            BigInteger A = new BigInteger(1, ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets());      
+            BigInteger B = new BigInteger(1, ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets());      
+            curve = new ECCurve.Fp(p, A, B, order, cofactor);
+        }
+        else if (fieldIdentifier.equals(characteristic_two_field))
+        {
+            // Characteristic two field
+            ASN1Sequence parameters = ASN1Sequence.getInstance(fieldID.getParameters());
+            int m = ((ASN1Integer)parameters.getObjectAt(0)).getValue().
+                intValue();
+            ASN1ObjectIdentifier representation
+                = (ASN1ObjectIdentifier)parameters.getObjectAt(1);
+
+            int k1 = 0;
+            int k2 = 0;
+            int k3 = 0;
+
+            if (representation.equals(tpBasis))
+            {
+                // Trinomial basis representation
+                k1 = ASN1Integer.getInstance(parameters.getObjectAt(2)).getValue().intValue();
+            }   
+            else if (representation.equals(ppBasis))
+            {
+                // Pentanomial basis representation
+                ASN1Sequence pentanomial = ASN1Sequence.getInstance(parameters.getObjectAt(2));
+                k1 = ASN1Integer.getInstance(pentanomial.getObjectAt(0)).getValue().intValue();
+                k2 = ASN1Integer.getInstance(pentanomial.getObjectAt(1)).getValue().intValue();
+                k3 = ASN1Integer.getInstance(pentanomial.getObjectAt(2)).getValue().intValue();
+            }   
+            else
+            {
+                throw new IllegalArgumentException("This type of EC basis is not implemented");
+            }   
+            BigInteger A = new BigInteger(1, ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets());      
+            BigInteger B = new BigInteger(1, ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets());      
+            curve = new ECCurve.F2m(m, k1, k2, k3, A, B, order, cofactor);
+        }   
+        else
+        {
+            throw new IllegalArgumentException("This type of ECCurve is not implemented");
+        }   
+
+        if (seq.size() == 3)
+        {
+            seed = Arrays.clone(((DERBitString)seq.getObjectAt(2)).getBytes());
+        }   
+    }   
+
+    private void setFieldIdentifier()
+    {
+        if (ECAlgorithms.isFpCurve(curve))
+        {
+            fieldIdentifier = prime_field;
+        }
+        else if (ECAlgorithms.isF2mCurve(curve))
+        {
+            fieldIdentifier = characteristic_two_field;
+        }
+        else
+        {
+            throw new IllegalArgumentException("This type of ECCurve is not implemented");
+        }
+    }
+
+    public ECCurve  getCurve()
+    {
+        return curve;
+    }
+
+    public byte[]   getSeed()
+    {
+        return Arrays.clone(seed);
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  Curve ::= SEQUENCE {
+     *      a               FieldElement,
+     *      b               FieldElement,
+     *      seed            BIT STRING      OPTIONAL
+     *  }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        if (fieldIdentifier.equals(prime_field)) 
+        { 
+            v.add(new X9FieldElement(curve.getA()).toASN1Primitive());
+            v.add(new X9FieldElement(curve.getB()).toASN1Primitive());
+        } 
+        else if (fieldIdentifier.equals(characteristic_two_field)) 
+        {
+            v.add(new X9FieldElement(curve.getA()).toASN1Primitive());
+            v.add(new X9FieldElement(curve.getB()).toASN1Primitive());
+        }
+
+        if (seed != null)
+        {
+            v.add(new DERBitString(seed));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ECParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ECParameters.java
new file mode 100644
index 0000000..2a5f2ec
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ECParameters.java
@@ -0,0 +1,248 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.math.ec.ECAlgorithms;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.field.PolynomialExtensionField;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * ASN.1 def for Elliptic-Curve ECParameters structure. See
+ * X9.62, for further details.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X9ECParameters
+    extends ASN1Object
+    implements X9ObjectIdentifiers
+{
+    private static final BigInteger   ONE = BigInteger.valueOf(1);
+
+    private X9FieldID           fieldID;
+    private ECCurve             curve;
+    private X9ECPoint           g;
+    private BigInteger          n;
+    private BigInteger          h;
+    private byte[]              seed;
+
+    private X9ECParameters(
+        ASN1Sequence  seq)
+    {
+        if (!(seq.getObjectAt(0) instanceof ASN1Integer)
+            || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE))
+        {
+            throw new IllegalArgumentException("bad version in X9ECParameters");
+        }
+
+        this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue();
+
+        if (seq.size() == 6)
+        {
+            this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue();
+        }
+
+        X9Curve x9c = new X9Curve(
+            X9FieldID.getInstance(seq.getObjectAt(1)), n, h,
+            ASN1Sequence.getInstance(seq.getObjectAt(2)));
+
+        this.curve = x9c.getCurve();
+        Object p = seq.getObjectAt(3);
+
+        if (p instanceof X9ECPoint)
+        {
+            this.g = (X9ECPoint)p;
+        }
+        else
+        {
+            this.g = new X9ECPoint(curve, (ASN1OctetString)p);
+        }
+
+        this.seed = x9c.getSeed();
+    }
+
+    public static X9ECParameters getInstance(Object obj)
+    {
+        if (obj instanceof X9ECParameters)
+        {
+            return (X9ECParameters)obj;
+        }
+
+        if (obj != null)
+        {
+            return new X9ECParameters(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public X9ECParameters(
+        ECCurve     curve,
+        ECPoint     g,
+        BigInteger  n)
+    {
+        this(curve, g, n, null, null);
+    }
+
+    public X9ECParameters(
+        ECCurve     curve,
+        X9ECPoint     g,
+        BigInteger  n,
+        BigInteger  h)
+    {
+        this(curve, g, n, h, null);
+    }
+
+    public X9ECParameters(
+        ECCurve     curve,
+        ECPoint     g,
+        BigInteger  n,
+        BigInteger  h)
+    {
+        this(curve, g, n, h, null);
+    }
+
+    public X9ECParameters(
+        ECCurve     curve,
+        ECPoint     g,
+        BigInteger  n,
+        BigInteger  h,
+        byte[]      seed)
+    {
+        this(curve, new X9ECPoint(g), n, h, seed);
+    }
+
+    public X9ECParameters(
+        ECCurve     curve,
+        X9ECPoint   g,
+        BigInteger  n,
+        BigInteger  h,
+        byte[]      seed)
+    {
+        this.curve = curve;
+        this.g = g;
+        this.n = n;
+        this.h = h;
+        this.seed = Arrays.clone(seed);
+
+        if (ECAlgorithms.isFpCurve(curve))
+        {
+            this.fieldID = new X9FieldID(curve.getField().getCharacteristic());
+        }
+        else if (ECAlgorithms.isF2mCurve(curve))
+        {
+            PolynomialExtensionField field = (PolynomialExtensionField)curve.getField();
+            int[] exponents = field.getMinimalPolynomial().getExponentsPresent();
+            if (exponents.length == 3)
+            {
+                this.fieldID = new X9FieldID(exponents[2], exponents[1]);
+            }
+            else if (exponents.length == 5)
+            {
+                this.fieldID = new X9FieldID(exponents[4], exponents[1], exponents[2], exponents[3]);
+            }
+            else
+            {
+                throw new IllegalArgumentException("Only trinomial and pentomial curves are supported");
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException("'curve' is of an unsupported type");
+        }
+    }
+
+    public ECCurve getCurve()
+    {
+        return curve;
+    }
+
+    public ECPoint getG()
+    {
+        return g.getPoint();
+    }
+
+    public BigInteger getN()
+    {
+        return n;
+    }
+
+    public BigInteger getH()
+    {
+        return h;
+    }
+
+    public byte[] getSeed()
+    {
+        return Arrays.clone(seed);
+    }
+
+    /**
+     * Return the ASN.1 entry representing the Curve.
+     *
+     * @return the X9Curve for the curve in these parameters.
+     */
+    public X9Curve getCurveEntry()
+    {
+        return new X9Curve(curve, seed);
+    }
+
+    /**
+     * Return the ASN.1 entry representing the FieldID.
+     *
+     * @return the X9FieldID for the FieldID in these parameters.
+     */
+    public X9FieldID getFieldIDEntry()
+    {
+        return fieldID;
+    }
+
+    /**
+     * Return the ASN.1 entry representing the base point G.
+     *
+     * @return the X9ECPoint for the base point in these parameters.
+     */
+    public X9ECPoint getBaseEntry()
+    {
+        return g;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  ECParameters ::= SEQUENCE {
+     *      version         INTEGER { ecpVer1(1) } (ecpVer1),
+     *      fieldID         FieldID {{FieldTypes}},
+     *      curve           X9Curve,
+     *      base            X9ECPoint,
+     *      order           INTEGER,
+     *      cofactor        INTEGER OPTIONAL
+     *  }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new ASN1Integer(ONE));
+        v.add(fieldID);
+        v.add(new X9Curve(curve, seed));
+        v.add(g);
+        v.add(new ASN1Integer(n));
+
+        if (h != null)
+        {
+            v.add(new ASN1Integer(h));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ECParametersHolder.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ECParametersHolder.java
new file mode 100644
index 0000000..4db5dd1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ECParametersHolder.java
@@ -0,0 +1,23 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+/**
+ * A holding class that allows for X9ECParameters to be lazily constructed.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class X9ECParametersHolder
+{
+    private X9ECParameters params;
+
+    public synchronized X9ECParameters getParameters()
+    {
+        if (params == null)
+        {
+            params = createParameters();
+        }
+
+        return params;
+    }
+
+    protected abstract X9ECParameters createParameters();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ECPoint.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ECPoint.java
new file mode 100644
index 0000000..d975a31
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ECPoint.java
@@ -0,0 +1,86 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * Class for describing an ECPoint as a DER object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X9ECPoint
+    extends ASN1Object
+{
+    private final ASN1OctetString encoding;
+
+    private ECCurve c;
+    private ECPoint p;
+
+    public X9ECPoint(
+        ECPoint p)
+    {
+        this(p, false);
+    }
+
+    public X9ECPoint(
+        ECPoint p,
+        boolean compressed)
+    {
+        this.p = p.normalize();
+        this.encoding = new DEROctetString(p.getEncoded(compressed));
+    }
+
+    public X9ECPoint(
+        ECCurve          c,
+        byte[]           encoding)
+    {
+        this.c = c;
+        this.encoding = new DEROctetString(Arrays.clone(encoding));
+    }
+
+    public X9ECPoint(
+        ECCurve          c,
+        ASN1OctetString  s)
+    {
+        this(c, s.getOctets());
+    }
+
+    public byte[] getPointEncoding()
+    {
+        return Arrays.clone(encoding.getOctets());
+    }
+
+    public synchronized ECPoint getPoint()
+    {
+        if (p == null)
+        {
+            p = c.decodePoint(encoding.getOctets()).normalize();
+        }
+
+        return p;
+    }
+
+    public boolean isPointCompressed()
+    {
+        byte[] octets = encoding.getOctets();
+        return octets != null && octets.length > 0 && (octets[0] == 2 || octets[0] == 3);
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  ECPoint ::= OCTET STRING
+     * </pre>
+     * <p>
+     * Octet string produced using ECPoint.getEncoded().
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        return encoding;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9FieldElement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9FieldElement.java
new file mode 100644
index 0000000..e9124a2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9FieldElement.java
@@ -0,0 +1,72 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+
+/**
+ * class for processing an FieldElement as a DER object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X9FieldElement
+    extends ASN1Object
+{
+    protected ECFieldElement  f;
+    
+    private static X9IntegerConverter converter = new X9IntegerConverter();
+
+    public X9FieldElement(ECFieldElement f)
+    {
+        this.f = f;
+    }
+
+    /**
+     * @deprecated Will be removed
+     */
+    public X9FieldElement(BigInteger p, ASN1OctetString s)
+    {
+        this(new ECFieldElement.Fp(p, new BigInteger(1, s.getOctets())));
+    }
+
+    /**
+     * @deprecated Will be removed
+     */
+    public X9FieldElement(int m, int k1, int k2, int k3, ASN1OctetString s)
+    {
+        this(new ECFieldElement.F2m(m, k1, k2, k3, new BigInteger(1, s.getOctets())));
+    }
+
+    public ECFieldElement getValue()
+    {
+        return f;
+    }
+    
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  FieldElement ::= OCTET STRING
+     * </pre>
+     * <p>
+     * <ol>
+     * <li> if <i>q</i> is an odd prime then the field element is
+     * processed as an Integer and converted to an octet string
+     * according to x 9.62 4.3.1.</li>
+     * <li> if <i>q</i> is 2<sup>m</sup> then the bit string
+     * contained in the field element is converted into an octet
+     * string with the same ordering padded at the front if necessary.
+     * </li>
+     * </ol>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        int byteCount = converter.getByteLength(f);
+        byte[] paddedBigInteger = converter.integerToBytes(f.toBigInteger(), byteCount);
+
+        return new DEROctetString(paddedBigInteger);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9FieldID.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9FieldID.java
new file mode 100644
index 0000000..aa0d3f7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9FieldID.java
@@ -0,0 +1,150 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+
+/**
+ * ASN.1 def for Elliptic-Curve Field ID structure. See
+ * X9.62, for further details.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X9FieldID
+    extends ASN1Object
+    implements X9ObjectIdentifiers
+{
+    private ASN1ObjectIdentifier     id;
+    private ASN1Primitive parameters;
+
+    /**
+     * Constructor for elliptic curves over prime fields
+     * <code>F<sub>2</sub></code>.
+     * @param primeP The prime <code>p</code> defining the prime field.
+     */
+    public X9FieldID(BigInteger primeP)
+    {
+        this.id = prime_field;
+        this.parameters = new ASN1Integer(primeP);
+    }
+
+    /**
+     * Constructor for elliptic curves over binary fields
+     * <code>F<sub>2<sup>m</sup></sub></code>.
+     * @param m  The exponent <code>m</code> of
+     * <code>F<sub>2<sup>m</sup></sub></code>.
+     * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+     * x<sup>k1</sup> + 1</code>
+     * represents the reduction polynomial <code>f(z)</code>.
+     */
+    public X9FieldID(int m, int k1)
+    {
+        this(m, k1, 0, 0);
+    }
+
+    /**
+     * Constructor for elliptic curves over binary fields
+     * <code>F<sub>2<sup>m</sup></sub></code>.
+     * @param m  The exponent <code>m</code> of
+     * <code>F<sub>2<sup>m</sup></sub></code>.
+     * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+     * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+     * represents the reduction polynomial <code>f(z)</code>.
+     * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+     * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+     * represents the reduction polynomial <code>f(z)</code>.
+     * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+     * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+     * represents the reduction polynomial <code>f(z)</code>..
+     */
+    public X9FieldID(int m, int k1, int k2, int k3)
+    {
+        this.id = characteristic_two_field;
+        ASN1EncodableVector fieldIdParams = new ASN1EncodableVector();
+        fieldIdParams.add(new ASN1Integer(m));
+        
+        if (k2 == 0) 
+        {
+            if (k3 != 0)
+            {
+                throw new IllegalArgumentException("inconsistent k values");
+            }
+
+            fieldIdParams.add(tpBasis);
+            fieldIdParams.add(new ASN1Integer(k1));
+        } 
+        else 
+        {
+            if (k2 <= k1 || k3 <= k2)
+            {
+                throw new IllegalArgumentException("inconsistent k values");
+            }
+
+            fieldIdParams.add(ppBasis);
+            ASN1EncodableVector pentanomialParams = new ASN1EncodableVector();
+            pentanomialParams.add(new ASN1Integer(k1));
+            pentanomialParams.add(new ASN1Integer(k2));
+            pentanomialParams.add(new ASN1Integer(k3));
+            fieldIdParams.add(new DERSequence(pentanomialParams));
+        }
+        
+        this.parameters = new DERSequence(fieldIdParams);
+    }
+
+    private X9FieldID(
+        ASN1Sequence  seq)
+    {
+        this.id = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+        this.parameters = seq.getObjectAt(1).toASN1Primitive();
+    }
+
+    public static X9FieldID getInstance(Object obj)
+    {
+        if (obj instanceof X9FieldID)
+        {
+            return (X9FieldID)obj;
+        }
+
+        if (obj != null)
+        {
+            return new X9FieldID(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public ASN1ObjectIdentifier getIdentifier()
+    {
+        return id;
+    }
+
+    public ASN1Primitive getParameters()
+    {
+        return parameters;
+    }
+
+    /**
+     * Produce a DER encoding of the following structure.
+     * <pre>
+     *  FieldID ::= SEQUENCE {
+     *      fieldType       FIELD-ID.&amp;id({IOSet}),
+     *      parameters      FIELD-ID.&amp;Type({IOSet}{&#64;fieldType})
+     *  }
+     * </pre>
+     */
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(this.id);
+        v.add(this.parameters);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9IntegerConverter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9IntegerConverter.java
new file mode 100644
index 0000000..b3e7857
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9IntegerConverter.java
@@ -0,0 +1,72 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+
+/**
+ * A class which converts integers to byte arrays, allowing padding and calculations
+ * to be done according the the filed size of the curve or field element involved.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X9IntegerConverter
+{
+    /**
+     * Return the curve's field size in bytes.
+     *
+     * @param c the curve of interest.
+     * @return the field size in bytes (rounded up).
+     */
+    public int getByteLength(
+        ECCurve c)
+    {
+        return (c.getFieldSize() + 7) / 8;
+    }
+
+    /**
+     * Return the field element's field size in bytes.
+     *
+     * @param fe the field element of interest.
+     * @return the field size in bytes (rounded up).
+     */
+    public int getByteLength(
+        ECFieldElement fe)
+    {
+        return (fe.getFieldSize() + 7) / 8;
+    }
+
+    /**
+     * Convert an integer to a byte array, ensuring it is exactly qLength long.
+     *
+     * @param s the integer to be converted.
+     * @param qLength the length
+     * @return the resulting byte array.
+     */
+    public byte[] integerToBytes(
+        BigInteger s,
+        int        qLength)
+    {
+        byte[] bytes = s.toByteArray();
+        
+        if (qLength < bytes.length)
+        {
+            byte[] tmp = new byte[qLength];
+        
+            System.arraycopy(bytes, bytes.length - tmp.length, tmp, 0, tmp.length);
+            
+            return tmp;
+        }
+        else if (qLength > bytes.length)
+        {
+            byte[] tmp = new byte[qLength];
+        
+            System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length);
+            
+            return tmp; 
+        }
+    
+        return bytes;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
new file mode 100644
index 0000000..903465b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
@@ -0,0 +1,226 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.asn1.x9;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ *
+ * Object identifiers for the various X9 standards.
+ * <pre>
+ * ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ *                                    us(840) ansi-x962(10045) }
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface X9ObjectIdentifiers
+{
+    /** Base OID: 1.2.840.10045 */
+    ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045");
+
+    /** OID: 1.2.840.10045.1 */
+    ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1");
+
+    /** OID: 1.2.840.10045.1.1 */
+    ASN1ObjectIdentifier prime_field = id_fieldType.branch("1");
+
+    /** OID: 1.2.840.10045.1.2 */
+    ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2");
+
+    /** OID: 1.2.840.10045.1.2.3.1 */
+    ASN1ObjectIdentifier gnBasis = characteristic_two_field.branch("3.1");
+
+    /** OID: 1.2.840.10045.1.2.3.2 */
+    ASN1ObjectIdentifier tpBasis = characteristic_two_field.branch("3.2");
+
+    /** OID: 1.2.840.10045.1.2.3.3 */
+    ASN1ObjectIdentifier ppBasis = characteristic_two_field.branch("3.3");
+
+    /** OID: 1.2.840.10045.4 */
+    ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4");
+
+    /** OID: 1.2.840.10045.4.1 */
+    ASN1ObjectIdentifier ecdsa_with_SHA1 = id_ecSigType.branch("1");
+
+    /** OID: 1.2.840.10045.2 */
+    ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2");
+
+    /** OID: 1.2.840.10045.2.1 */
+    ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1");
+
+    /** OID: 1.2.840.10045.4.3 */
+    ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3");
+
+    /** OID: 1.2.840.10045.4.3.1 */
+    ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1");
+
+    /** OID: 1.2.840.10045.4.3.2 */
+    ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2");
+
+    /** OID: 1.2.840.10045.4.3.3 */
+    ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3");
+
+    /** OID: 1.2.840.10045.4.3.4 */
+    ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4");
+
+    /**
+     * Named curves base
+     * <p>
+     * OID: 1.2.840.10045.3
+     */
+    ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3");
+
+    /**
+     * Two Curves
+     * <p>
+     * OID: 1.2.840.10045.3.0
+     */
+    ASN1ObjectIdentifier  cTwoCurve = ellipticCurve.branch("0");
+
+    /** Two Curve c2pnb163v1, OID: 1.2.840.10045.3.0.1 */
+    ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1");
+    /** Two Curve c2pnb163v2, OID: 1.2.840.10045.3.0.2 */
+    ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2");
+    /** Two Curve c2pnb163v3, OID: 1.2.840.10045.3.0.3 */
+    ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3");
+    /** Two Curve c2pnb176w1, OID: 1.2.840.10045.3.0.4 */
+    ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4");
+    /** Two Curve c2tnb191v1, OID: 1.2.840.10045.3.0.5 */
+    ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5");
+    /** Two Curve c2tnb191v2, OID: 1.2.840.10045.3.0.6 */
+    ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6");
+    /** Two Curve c2tnb191v3, OID: 1.2.840.10045.3.0.7 */
+    ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7");
+    /** Two Curve c2onb191v4, OID: 1.2.840.10045.3.0.8 */
+    ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8");
+    /** Two Curve c2onb191v5, OID: 1.2.840.10045.3.0.9 */
+    ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9");
+    /** Two Curve c2pnb208w1, OID: 1.2.840.10045.3.0.10 */
+    ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10");
+    /** Two Curve c2tnb239v1, OID: 1.2.840.10045.3.0.11 */
+    ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11");
+    /** Two Curve c2tnb239v2, OID: 1.2.840.10045.3.0.12 */
+    ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12");
+    /** Two Curve c2tnb239v3, OID: 1.2.840.10045.3.0.13 */
+    ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13");
+    /** Two Curve c2onb239v4, OID: 1.2.840.10045.3.0.14 */
+    ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14");
+    /** Two Curve c2onb239v5, OID: 1.2.840.10045.3.0.15 */
+    ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15");
+    /** Two Curve c2pnb272w1, OID: 1.2.840.10045.3.0.16 */
+    ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16");
+    /** Two Curve c2pnb304w1, OID: 1.2.840.10045.3.0.17 */
+    ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17");
+    /** Two Curve c2tnb359v1, OID: 1.2.840.10045.3.0.18 */
+    ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18");
+    /** Two Curve c2pnb368w1, OID: 1.2.840.10045.3.0.19 */
+    ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19");
+    /** Two Curve c2tnb431r1, OID: 1.2.840.10045.3.0.20 */
+    ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20");
+
+    /**
+     * Prime Curves
+     * <p>
+     * OID: 1.2.840.10045.3.1
+     */
+    ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1");
+
+    /** Prime Curve prime192v1, OID: 1.2.840.10045.3.1.1 */
+    ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1");
+    /** Prime Curve prime192v2, OID: 1.2.840.10045.3.1.2 */
+    ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2");
+    /** Prime Curve prime192v3, OID: 1.2.840.10045.3.1.3 */
+    ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3");
+    /** Prime Curve prime239v1, OID: 1.2.840.10045.3.1.4 */
+    ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4");
+    /** Prime Curve prime239v2, OID: 1.2.840.10045.3.1.5 */
+    ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5");
+    /** Prime Curve prime239v3, OID: 1.2.840.10045.3.1.6 */
+    ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6");
+    /** Prime Curve prime256v1, OID: 1.2.840.10045.3.1.7 */
+    ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7");
+
+    /**
+     * DSA
+     * <pre>
+     * dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+     *                                         us(840) ansi-x957(10040) number-type(4) 1 }
+     * </pre>
+     * Base OID: 1.2.840.10040.4.1
+     */
+    ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1");
+
+    /**
+     * <pre>
+     * id-dsa-with-sha1 OBJECT IDENTIFIER ::= {
+     *     iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 }
+     * </pre>
+     * OID: 1.2.840.10040.4.3
+     */
+    ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3");
+
+    /**
+     * X9.63 - Signature Specification
+     * <p>
+     * Base OID: 1.3.133.16.840.63.0
+     */
+    ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0");
+    /** OID: 1.3.133.16.840.63.0.2 */
+    ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme      = x9_63_scheme.branch("2");
+    /** OID: 1.3.133.16.840.63.0.3 */
+    ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3");
+    /** OID: 1.3.133.16.840.63.0.16 */
+    ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme           = x9_63_scheme.branch("16");
+
+    /**
+     * X9.42
+     */
+
+    ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046");
+
+    /**
+     * Diffie-Hellman
+     * <pre>
+     * dhpublicnumber OBJECT IDENTIFIER ::= {
+     *    iso(1) member-body(2)  us(840) ansi-x942(10046) number-type(2) 1
+     * }
+     * </pre>
+     * OID: 1.2.840.10046.2.1
+     */
+    ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1");
+
+    /** X9.42 schemas base OID: 1.2.840.10046.3 */
+    ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3");
+    /** X9.42 dhStatic OID: 1.2.840.10046.3.1 */
+    ASN1ObjectIdentifier dhStatic        = x9_42_schemes.branch("1");
+    /** X9.42 dhEphem OID: 1.2.840.10046.3.2 */
+    ASN1ObjectIdentifier dhEphem         = x9_42_schemes.branch("2");
+    /** X9.42 dhOneFlow OID: 1.2.840.10046.3.3 */
+    ASN1ObjectIdentifier dhOneFlow       = x9_42_schemes.branch("3");
+    /** X9.42 dhHybrid1 OID: 1.2.840.10046.3.4 */
+    ASN1ObjectIdentifier dhHybrid1       = x9_42_schemes.branch("4");
+    /** X9.42 dhHybrid2 OID: 1.2.840.10046.3.5 */
+    ASN1ObjectIdentifier dhHybrid2       = x9_42_schemes.branch("5");
+    /** X9.42 dhHybridOneFlow OID: 1.2.840.10046.3.6 */
+    ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6");
+    /** X9.42 MQV2 OID: 1.2.840.10046.3.7 */
+    ASN1ObjectIdentifier mqv2            = x9_42_schemes.branch("7");
+    /** X9.42 MQV1 OID: 1.2.840.10046.3.8 */
+    ASN1ObjectIdentifier mqv1            = x9_42_schemes.branch("8");
+
+    /**
+     * X9.44
+     * <pre>
+     *    x9-44 OID ::= {
+     *      iso(1) identified-organization(3) tc68(133) country(16) x9(840)
+     *      x9Standards(9) x9-44(44)
+     *   }
+     * </pre>
+     */
+
+    ASN1ObjectIdentifier x9_44 = new ASN1ObjectIdentifier("1.3.133.16.840.9.44");
+
+    ASN1ObjectIdentifier x9_44_components = x9_44.branch("1");
+
+    ASN1ObjectIdentifier id_kdf_kdf2 = x9_44_components.branch("1");
+    ASN1ObjectIdentifier id_kdf_kdf3 = x9_44_components.branch("2");
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/AsymmetricBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/AsymmetricBlockCipher.java
new file mode 100644
index 0000000..511e48c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/AsymmetricBlockCipher.java
@@ -0,0 +1,47 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+
+/**
+ * base interface that a public/private key block cipher needs
+ * to conform to.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface AsymmetricBlockCipher
+{
+    /**
+     * initialise the cipher.
+     *
+     * @param forEncryption if true the cipher is initialised for 
+     *  encryption, if false for decryption.
+     * @param param the key and other data required by the cipher.
+     */
+    public void init(boolean forEncryption, CipherParameters param);
+
+    /**
+     * returns the largest size an input block can be.
+     *
+     * @return maximum size for an input block.
+     */
+    public int getInputBlockSize();
+
+    /**
+     * returns the maximum size of the block produced by this cipher.
+     *
+     * @return maximum size of the output block produced by the cipher.
+     */
+    public int getOutputBlockSize();
+
+    /**
+     * process the block of len bytes stored in in from offset inOff.
+     *
+     * @param in the input data
+     * @param inOff offset into the in array where the data starts
+     * @param len the length of the block to be processed.
+     * @return the resulting byte array of the encryption/decryption process.
+     * @exception InvalidCipherTextException data decrypts improperly.
+     * @exception DataLengthException the input data is too large for the cipher.
+     */
+    public byte[] processBlock(byte[] in, int inOff, int len)
+        throws InvalidCipherTextException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java
new file mode 100644
index 0000000..7bd42ea
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java
@@ -0,0 +1,63 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+import com.android.internal.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+
+/**
+ * a holding class for public/private parameter pairs.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AsymmetricCipherKeyPair
+{
+    private AsymmetricKeyParameter    publicParam;
+    private AsymmetricKeyParameter    privateParam;
+
+    /**
+     * basic constructor.
+     *
+     * @param publicParam a public key parameters object.
+     * @param privateParam the corresponding private key parameters.
+     */
+    public AsymmetricCipherKeyPair(
+        AsymmetricKeyParameter    publicParam,
+        AsymmetricKeyParameter    privateParam)
+    {
+        this.publicParam = publicParam;
+        this.privateParam = privateParam;
+    }
+
+    /**
+     * basic constructor.
+     *
+     * @param publicParam a public key parameters object.
+     * @param privateParam the corresponding private key parameters.
+     * @deprecated use AsymmetricKeyParameter
+     */
+    public AsymmetricCipherKeyPair(
+        CipherParameters    publicParam,
+        CipherParameters    privateParam)
+    {
+        this.publicParam = (AsymmetricKeyParameter)publicParam;
+        this.privateParam = (AsymmetricKeyParameter)privateParam;
+    }
+
+    /**
+     * return the public key parameters.
+     *
+     * @return the public key parameters.
+     */
+    public AsymmetricKeyParameter getPublic()
+    {
+        return publicParam;
+    }
+
+    /**
+     * return the private key parameters.
+     *
+     * @return the private key parameters.
+     */
+    public AsymmetricKeyParameter getPrivate()
+    {
+        return privateParam;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/AsymmetricCipherKeyPairGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/AsymmetricCipherKeyPairGenerator.java
new file mode 100644
index 0000000..c7d272b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/AsymmetricCipherKeyPairGenerator.java
@@ -0,0 +1,24 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * interface that a public/private key pair generator should conform to.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface AsymmetricCipherKeyPairGenerator
+{
+    /**
+     * intialise the key pair generator.
+     *
+     * @param param the parameters the key pair is to be initialised with.
+     */
+    public void init(KeyGenerationParameters param);
+
+    /**
+     * return an AsymmetricCipherKeyPair containing the generated keys.
+     *
+     * @return an AsymmetricCipherKeyPair containing the generated keys.
+     */
+    public AsymmetricCipherKeyPair generateKeyPair();
+}
+
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/BasicAgreement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/BasicAgreement.java
new file mode 100644
index 0000000..fcf2382
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/BasicAgreement.java
@@ -0,0 +1,28 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+import java.math.BigInteger;
+
+/**
+ * The basic interface that basic Diffie-Hellman implementations
+ * conforms to.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface BasicAgreement
+{
+    /**
+     * initialise the agreement engine.
+     */
+    void init(CipherParameters param);
+
+    /**
+     * return the field size for the agreement algorithm in bytes.
+     */
+    int getFieldSize();
+
+    /**
+     * given a public key from a given party calculate the next
+     * message in the agreement sequence. 
+     */
+    BigInteger calculateAgreement(CipherParameters pubKey);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/BlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/BlockCipher.java
new file mode 100644
index 0000000..9fbfe10
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/BlockCipher.java
@@ -0,0 +1,58 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+
+/**
+ * Block cipher engines are expected to conform to this interface.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface BlockCipher
+{
+    /**
+     * Initialise the cipher.
+     *
+     * @param forEncryption if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(boolean forEncryption, CipherParameters params)
+        throws IllegalArgumentException;
+
+    /**
+     * Return the name of the algorithm the cipher implements.
+     *
+     * @return the name of the algorithm the cipher implements.
+     */
+    public String getAlgorithmName();
+
+    /**
+     * Return the block size for this cipher (in bytes).
+     *
+     * @return the block size for this cipher in bytes.
+     */
+    public int getBlockSize();
+
+    /**
+     * Process one block of input from the array in and write it to
+     * the out array.
+     *
+     * @param in the array containing the input data.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the output data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+        throws DataLengthException, IllegalStateException;
+
+    /**
+     * Reset the cipher. After resetting the cipher is in the same state
+     * as it was after the last init (if there was one).
+     */
+    public void reset();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/BufferedBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/BufferedBlockCipher.java
new file mode 100644
index 0000000..f9e8c6c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/BufferedBlockCipher.java
@@ -0,0 +1,322 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+
+/**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the
+ * buffer is full and more data is being added, or on a doFinal.
+ * <p>
+ * Note: in the case where the underlying cipher is either a CFB cipher or an
+ * OFB one the last block may not be a multiple of the block size.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BufferedBlockCipher
+{
+    protected byte[]        buf;
+    protected int           bufOff;
+
+    protected boolean       forEncryption;
+    protected BlockCipher   cipher;
+
+    protected boolean       partialBlockOkay;
+    protected boolean       pgpCFB;
+
+    /**
+     * constructor for subclasses
+     */
+    protected BufferedBlockCipher()
+    {
+    }
+
+    /**
+     * Create a buffered block cipher without padding.
+     *
+     * @param cipher the underlying block cipher this buffering object wraps.
+     */
+    public BufferedBlockCipher(
+        BlockCipher     cipher)
+    {
+        this.cipher = cipher;
+
+        buf = new byte[cipher.getBlockSize()];
+        bufOff = 0;
+
+        //
+        // check if we can handle partial blocks on doFinal.
+        //
+        String  name = cipher.getAlgorithmName();
+        int     idx = name.indexOf('/') + 1;
+
+        pgpCFB = (idx > 0 && name.startsWith("PGP", idx));
+
+        if (pgpCFB || cipher instanceof StreamCipher)
+        {
+            partialBlockOkay = true;
+        }
+        else
+        {
+            partialBlockOkay = (idx > 0 && (name.startsWith("OpenPGP", idx)));
+        }
+    }
+
+    /**
+     * return the cipher this object wraps.
+     *
+     * @return the cipher this object wraps.
+     */
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+    /**
+     * initialise the cipher.
+     *
+     * @param forEncryption if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             forEncryption,
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        this.forEncryption = forEncryption;
+
+        reset();
+
+        cipher.init(forEncryption, params);
+    }
+
+    /**
+     * return the blocksize for the underlying cipher.
+     *
+     * @return the blocksize for the underlying cipher.
+     */
+    public int getBlockSize()
+    {
+        return cipher.getBlockSize();
+    }
+
+    /**
+     * return the size of the output buffer required for an update 
+     * an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update
+     * with len bytes of input.
+     */
+    public int getUpdateOutputSize(
+        int len)
+    {
+        int total       = len + bufOff;
+        int leftOver;
+
+        if (pgpCFB)
+        {
+            if (forEncryption)
+            {
+                leftOver = total % buf.length - (cipher.getBlockSize() + 2);
+            }
+            else
+            {
+                leftOver = total % buf.length;
+            }
+        }
+        else
+        {
+            leftOver    = total % buf.length;
+        }
+
+        return total - leftOver;
+    }
+
+    /**
+     * return the size of the output buffer required for an update plus a
+     * doFinal with an input of 'length' bytes.
+     *
+     * @param length the length of the input.
+     * @return the space required to accommodate a call to update and doFinal
+     * with 'length' bytes of input.
+     */
+    public int getOutputSize(
+        int length)
+    {
+        // Note: Can assume partialBlockOkay is true for purposes of this calculation
+        return length + bufOff;
+    }
+
+    /**
+     * process a single byte, producing an output block if necessary.
+     *
+     * @param in the input byte.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processByte(
+        byte        in,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        int         resultLen = 0;
+
+        buf[bufOff++] = in;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = cipher.processBlock(buf, 0, out, outOff);
+            bufOff = 0;
+        }
+
+        return resultLen;
+    }
+
+    /**
+     * process an array of bytes, producing output if necessary.
+     *
+     * @param in the input byte array.
+     * @param inOff the offset at which the input data starts.
+     * @param len the number of bytes to be copied out of the input array.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processBytes(
+        byte[]      in,
+        int         inOff,
+        int         len,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int blockSize   = getBlockSize();
+        int length      = getUpdateOutputSize(len);
+        
+        if (length > 0)
+        {
+            if ((outOff + length) > out.length)
+            {
+                throw new OutputLengthException("output buffer too short");
+            }
+        }
+
+        int resultLen = 0;
+        int gapLen = buf.length - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += cipher.processBlock(buf, 0, out, outOff);
+
+            bufOff = 0;
+            len -= gapLen;
+            inOff += gapLen;
+
+            while (len > buf.length)
+            {
+                resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
+
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+
+        bufOff += len;
+
+        if (bufOff == buf.length)
+        {
+            resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+            bufOff = 0;
+        }
+
+        return resultLen;
+    }
+
+    /**
+     * Process the last block in the buffer.
+     *
+     * @param out the array the block currently being held is copied into.
+     * @param outOff the offset at which the copying starts.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there is insufficient space in out for
+     * the output, or the input is not block size aligned and should be.
+     * @exception IllegalStateException if the underlying cipher is not
+     * initialised.
+     * @exception InvalidCipherTextException if padding is expected and not found.
+     * @exception DataLengthException if the input is not block size
+     * aligned.
+     */
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+        throws DataLengthException, IllegalStateException, InvalidCipherTextException
+    {
+        try
+        {
+            int resultLen = 0;
+
+            if (outOff + bufOff > out.length)
+            {
+                throw new OutputLengthException("output buffer too short for doFinal()");
+            }
+
+            if (bufOff != 0)
+            {
+                if (!partialBlockOkay)
+                {
+                    throw new DataLengthException("data not block size aligned");
+                }
+
+                cipher.processBlock(buf, 0, buf, 0);
+                resultLen = bufOff;
+                bufOff = 0;
+                System.arraycopy(buf, 0, out, outOff, resultLen);
+            }
+
+            return resultLen;
+        }
+        finally
+        {
+            reset();
+        }
+    }
+
+    /**
+     * Reset the buffer and cipher. After resetting the object is in the same
+     * state as it was after the last init (if there was one).
+     */
+    public void reset()
+    {
+        //
+        // clean the buffer.
+        //
+        for (int i = 0; i < buf.length; i++)
+        {
+            buf[i] = 0;
+        }
+
+        bufOff = 0;
+
+        //
+        // reset the underlying cipher.
+        //
+        cipher.reset();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CipherKeyGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CipherKeyGenerator.java
new file mode 100644
index 0000000..2b26db6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CipherKeyGenerator.java
@@ -0,0 +1,40 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+import java.security.SecureRandom;
+
+/**
+ * The base class for symmetric, or secret, cipher key generators.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CipherKeyGenerator
+{
+    protected SecureRandom  random;
+    protected int           strength;
+
+    /**
+     * initialise the key generator.
+     *
+     * @param param the parameters to be used for key generation
+     */
+    public void init(
+        KeyGenerationParameters param)
+    {
+        this.random = param.getRandom();
+        this.strength = (param.getStrength() + 7) / 8;
+    }
+
+    /**
+     * generate a secret key.
+     *
+     * @return a byte array containing the key value.
+     */
+    public byte[] generateKey()
+    {
+        byte[]  key = new byte[strength];
+
+        random.nextBytes(key);
+
+        return key;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CipherParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CipherParameters.java
new file mode 100644
index 0000000..20658e2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CipherParameters.java
@@ -0,0 +1,10 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * all parameter classes implement this.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface CipherParameters
+{
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CryptoException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CryptoException.java
new file mode 100644
index 0000000..af6bf04
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CryptoException.java
@@ -0,0 +1,50 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * the foundation class for the hard exceptions thrown by the crypto packages.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CryptoException 
+    extends Exception
+{
+    private Throwable cause;
+
+    /**
+     * base constructor.
+     */
+    public CryptoException()
+    {
+    }
+
+    /**
+     * create a CryptoException with the given message.
+     *
+     * @param message the message to be carried with the exception.
+     */
+    public CryptoException(
+        String  message)
+    {
+        super(message);
+    }
+
+    /**
+     * Create a CryptoException with the given message and underlying cause.
+     *
+     * @param message message describing exception.
+     * @param cause the throwable that was the underlying cause.
+     */
+    public CryptoException(
+        String  message,
+        Throwable cause)
+    {
+        super(message);
+
+        this.cause = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CryptoServicesPermission.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CryptoServicesPermission.java
new file mode 100644
index 0000000..6c1f44a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CryptoServicesPermission.java
@@ -0,0 +1,83 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+import java.security.Permission;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Permissions that need to be configured if a SecurityManager is used.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CryptoServicesPermission
+    extends Permission
+{
+    /**
+     * Enable the setting of global configuration properties. This permission implies THREAD_LOCAL_CONFIG
+     */
+    public static final String GLOBAL_CONFIG = "globalConfig";
+
+    /**
+     * Enable the setting of thread local configuration properties.
+     */
+    public static final String THREAD_LOCAL_CONFIG = "threadLocalConfig";
+
+    /**
+     * Enable the setting of the default SecureRandom.
+     */
+    public static final String DEFAULT_RANDOM = "defaultRandomConfig";
+
+    private final Set<String> actions = new HashSet<String>();
+
+    public CryptoServicesPermission(String name)
+    {
+        super(name);
+
+        this.actions.add(name);
+    }
+
+    public boolean implies(Permission permission)
+    {
+        if (permission instanceof CryptoServicesPermission)
+        {
+            CryptoServicesPermission other = (CryptoServicesPermission)permission;
+
+            if (this.getName().equals(other.getName()))
+            {
+                return true;
+            }
+
+            if (this.actions.containsAll(other.actions))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public boolean equals(Object obj)
+    {
+        if (obj instanceof CryptoServicesPermission)
+        {
+            CryptoServicesPermission other = (CryptoServicesPermission)obj;
+
+            if (this.actions.equals(other.actions))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public int hashCode()
+    {
+        return actions.hashCode();
+    }
+
+    public String getActions()
+    {
+        return actions.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CryptoServicesRegistrar.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CryptoServicesRegistrar.java
new file mode 100644
index 0000000..005a422
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/CryptoServicesRegistrar.java
@@ -0,0 +1,420 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+import java.security.SecureRandom;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHValidationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAValidationParameters;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * Basic registrar class for providing defaults for cryptography services in this module.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class CryptoServicesRegistrar
+{
+    private static final Permission CanSetDefaultProperty = new CryptoServicesPermission(CryptoServicesPermission.GLOBAL_CONFIG);
+    private static final Permission CanSetThreadProperty = new CryptoServicesPermission(CryptoServicesPermission.THREAD_LOCAL_CONFIG);
+    private static final Permission CanSetDefaultRandom = new CryptoServicesPermission(CryptoServicesPermission.DEFAULT_RANDOM);
+
+    private static final ThreadLocal<Map<String, Object[]>> threadProperties = new ThreadLocal<Map<String, Object[]>>();
+    private static final Map<String, Object[]> globalProperties = Collections.synchronizedMap(new HashMap<String, Object[]>());
+
+    private static volatile SecureRandom defaultSecureRandom;
+
+    static
+    {
+        // default domain parameters for DSA and Diffie-Hellman
+
+        DSAParameters def512Params = new DSAParameters(
+            new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16),
+            new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16),
+            new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16),
+            new DSAValidationParameters(Hex.decode("b869c82b35d70e1b1ff91b28e37a62ecdc34409b"), 123));
+
+        DSAParameters def768Params = new DSAParameters(
+            new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5" +
+                           "d890141922d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a" +
+                           "22219d470bce7d777d4a21fbe9c270b57f607002f3cef8393694cf45" +
+                           "ee3688c11a8c56ab127a3daf", 16),
+            new BigInteger("9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511", 16),
+            new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7" +
+                           "a31d23c4dbbcbe06174544401a5b2c020965d8c2bd2171d366844577" +
+                           "1f74ba084d2029d83c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a" +
+                           "7064f316933a346d3f529252", 16),
+            new DSAValidationParameters(Hex.decode("77d0f8c4dad15eb8c4f2f8d6726cefd96d5bb399"), 263));
+
+        DSAParameters def1024Params = new DSAParameters(
+            new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80" +
+                            "b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b" +
+                            "801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c6" +
+                            "1bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675" +
+                            "f3ae2b61d72aeff22203199dd14801c7", 16),
+            new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16),
+            new BigInteger("f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b" +
+                            "3d0782675159578ebad4594fe67107108180b449167123e84c281613" +
+                            "b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f" +
+                            "0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06" +
+                            "928b665e807b552564014c3bfecf492a", 16),
+            new DSAValidationParameters(Hex.decode("8d5155894229d5e689ee01e6018a237e2cae64cd"), 92));
+
+        DSAParameters def2048Params = new DSAParameters(
+            new BigInteger("95475cf5d93e596c3fcd1d902add02f427f5f3c7210313bb45fb4d5b" +
+                            "b2e5fe1cbd678cd4bbdd84c9836be1f31c0777725aeb6c2fc38b85f4" +
+                            "8076fa76bcd8146cc89a6fb2f706dd719898c2083dc8d896f84062e2" +
+                            "c9c94d137b054a8d8096adb8d51952398eeca852a0af12df83e475aa" +
+                            "65d4ec0c38a9560d5661186ff98b9fc9eb60eee8b030376b236bc73b" +
+                            "e3acdbd74fd61c1d2475fa3077b8f080467881ff7e1ca56fee066d79" +
+                            "506ade51edbb5443a563927dbc4ba520086746175c8885925ebc64c6" +
+                            "147906773496990cb714ec667304e261faee33b3cbdf008e0c3fa906" +
+                            "50d97d3909c9275bf4ac86ffcb3d03e6dfc8ada5934242dd6d3bcca2" +
+                            "a406cb0b", 16),
+            new BigInteger("f8183668ba5fc5bb06b5981e6d8b795d30b8978d43ca0ec572e37e09939a9773", 16),
+            new BigInteger("42debb9da5b3d88cc956e08787ec3f3a09bba5f48b889a74aaf53174" +
+                            "aa0fbe7e3c5b8fcd7a53bef563b0e98560328960a9517f4014d3325f" +
+                            "c7962bf1e049370d76d1314a76137e792f3f0db859d095e4a5b93202" +
+                            "4f079ecf2ef09c797452b0770e1350782ed57ddf794979dcef23cb96" +
+                            "f183061965c4ebc93c9c71c56b925955a75f94cccf1449ac43d586d0" +
+                            "beee43251b0b2287349d68de0d144403f13e802f4146d882e057af19" +
+                            "b6f6275c6676c8fa0e3ca2713a3257fd1b27d0639f695e347d8d1cf9" +
+                            "ac819a26ca9b04cb0eb9b7b035988d15bbac65212a55239cfc7e58fa" +
+                            "e38d7250ab9991ffbc97134025fe8ce04c4399ad96569be91a546f49" +
+                            "78693c7a", 16),
+            new DSAValidationParameters(Hex.decode("b0b4417601b59cbc9d8ac8f935cadaec4f5fbb2f23785609ae466748d9b5a536"), 497));
+
+        localSetGlobalProperty(Property.DSA_DEFAULT_PARAMS, def512Params, def768Params, def1024Params, def2048Params);
+        localSetGlobalProperty(Property.DH_DEFAULT_PARAMS, toDH(def512Params), toDH(def768Params), toDH(def1024Params), toDH(def2048Params));
+    }
+
+    private CryptoServicesRegistrar()
+    {
+
+    }
+
+    /**
+     * Return the default source of randomness.
+     *
+     * @return the default SecureRandom
+     * @throws IllegalStateException if no source of randomness has been provided.
+     */
+    public static SecureRandom getSecureRandom()
+    {
+        if (defaultSecureRandom == null)
+        {
+            return new SecureRandom();
+        }
+        
+        return defaultSecureRandom;
+    }
+
+    /**
+     * Set a default secure random to be used where none is otherwise provided.
+     *
+     * @param secureRandom the SecureRandom to use as the default.
+     */
+    public static void setSecureRandom(SecureRandom secureRandom)
+    {
+        checkPermission(CanSetDefaultRandom);
+
+        defaultSecureRandom = secureRandom;
+    }
+
+    /**
+     * Return the default value for a particular property if one exists. The look up is done on the thread's local
+     * configuration first and then on the global configuration in no local configuration exists.
+     *
+     * @param property the property to look up.
+     * @param <T> the type to be returned
+     * @return null if the property is not set, the default value otherwise,
+     */
+    public static <T> T getProperty(Property property)
+    {
+        Object[] values = lookupProperty(property);
+
+        if (values != null)
+        {
+            return (T)values[0];
+        }
+
+        return null;
+    }
+
+    private static Object[] lookupProperty(Property property)
+    {
+        Map<String, Object[]> properties = threadProperties.get();
+        Object[] values;
+
+        if (properties == null || !properties.containsKey(property.name))
+        {
+            values = globalProperties.get(property.name);
+        }
+        else
+        {
+            values = properties.get(property.name);
+        }
+        return values;
+    }
+
+    /**
+     * Return an array representing the current values for a sized property such as DH_DEFAULT_PARAMS or
+     * DSA_DEFAULT_PARAMS.
+     *
+     * @param property the name of the property to look up.
+     * @param <T> the base type of the array to be returned.
+     * @return null if the property is not set, an array of the current values otherwise.
+     */
+    public static <T> T[] getSizedProperty(Property property)
+    {
+        Object[] values = lookupProperty(property);
+
+        if (values == null)
+        {
+            return null;
+        }
+
+        return (T[])values.clone();
+    }
+
+    /**
+     * Return the value for a specific size for a sized property such as DH_DEFAULT_PARAMS or
+     * DSA_DEFAULT_PARAMS.
+     *
+     * @param property the name of the property to look up.
+     * @param size the size (in bits) of the defining value in the property type.
+     * @param <T> the type of the value to be returned.
+     * @return the current value for the size, null if there is no value set,
+     */
+    public static <T> T getSizedProperty(Property property, int size)
+    {
+        Object[] values = lookupProperty(property);
+
+        if (values == null)
+        {
+            return null;
+        }
+
+        if (property.type.isAssignableFrom(DHParameters.class))
+        {
+            for (int i = 0; i != values.length; i++)
+            {
+                DHParameters params = (DHParameters)values[i];
+
+                if (params.getP().bitLength() == size)
+                {
+                    return (T)params;
+                }
+            }
+        }
+        else if (property.type.isAssignableFrom(DSAParameters.class))
+        {
+            for (int i = 0; i != values.length; i++)
+            {
+                DSAParameters params = (DSAParameters)values[i];
+
+                if (params.getP().bitLength() == size)
+                {
+                    return (T)params;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Set the value of the the passed in property on the current thread only. More than
+     * one value can be passed in for a sized property. If more than one value is provided the
+     * first value in the argument list becomes the default value.
+     *
+     * @param property the name of the property to set.
+     * @param propertyValue the values to assign to the property.
+     * @param <T> the base type of the property value.
+     */
+    public static <T> void setThreadProperty(Property property, T... propertyValue)
+    {
+        checkPermission(CanSetThreadProperty);
+
+        if (!property.type.isAssignableFrom(propertyValue[0].getClass()))
+        {
+            throw new IllegalArgumentException("Bad property value passed");
+        }
+
+        localSetThread(property, propertyValue.clone());
+    }
+
+    /**
+     * Set the value of the the passed in property globally in the JVM. More than
+     * one value can be passed in for a sized property. If more than one value is provided the
+     * first value in the argument list becomes the default value.
+     *
+     * @param property the name of the property to set.
+     * @param propertyValue the values to assign to the property.
+     * @param <T> the base type of the property value.
+     */
+    public static <T> void setGlobalProperty(Property property, T... propertyValue)
+    {
+        checkPermission(CanSetDefaultProperty);
+
+        localSetGlobalProperty(property, propertyValue.clone());
+    }
+
+    private static <T> void localSetThread(Property property, T[] propertyValue)
+    {
+        Map<String, Object[]> properties = threadProperties.get();
+
+        if (properties == null)
+        {
+            properties = new HashMap<String, Object[]>();
+            threadProperties.set(properties);
+        }
+
+        properties.put(property.name, propertyValue);
+    }
+
+    private static <T> void localSetGlobalProperty(Property property, T... propertyValue)
+    {
+        if (!property.type.isAssignableFrom(propertyValue[0].getClass()))
+        {
+            throw new IllegalArgumentException("Bad property value passed");
+        }
+
+        // set the property for the current thread as well to avoid mass confusion
+        localSetThread(property, propertyValue);
+
+        globalProperties.put(property.name, propertyValue);
+    }
+
+    /**
+     * Clear the global value for the passed in property.
+     *
+     * @param property the property to be cleared.
+     * @param <T> the base type of the property value
+     * @return an array of T if a value was previously set, null otherwise.
+     */
+    public static <T> T[] clearGlobalProperty(Property property)
+    {
+        checkPermission(CanSetDefaultProperty);
+
+        // clear the property for the current thread as well to avoid confusion
+        localClearThreadProperty(property);
+
+        return (T[])globalProperties.remove(property.name);
+    }
+
+    /**
+     * Clear the thread local value for the passed in property.
+     *
+     * @param property the property to be cleared.
+     * @param <T> the base type of the property value
+     * @return an array of T if a value was previously set, null otherwise.
+     */
+    public static <T> T[] clearThreadProperty(Property property)
+    {
+        checkPermission(CanSetThreadProperty);
+
+        return (T[])localClearThreadProperty(property);
+    }
+
+    private static Object[] localClearThreadProperty(Property property)
+    {
+        Map<String, Object[]> properties = threadProperties.get();
+
+        if (properties == null)
+        {
+            properties = new HashMap<String, Object[]>();
+            threadProperties.set(properties);
+        }
+
+        return properties.remove(property.name);
+    }
+
+    private static void checkPermission(final Permission permission)
+    {
+        final SecurityManager securityManager = System.getSecurityManager();
+
+        if (securityManager != null)
+        {
+            AccessController.doPrivileged(new PrivilegedAction<Object>()
+            {
+                public Object run()
+                {
+                    securityManager.checkPermission(permission);
+
+                    return null;
+                }
+            });
+        }
+    }
+
+    private static DHParameters toDH(DSAParameters dsaParams)
+    {
+        int pSize = dsaParams.getP().bitLength();
+        int m = chooseLowerBound(pSize);
+        return new DHParameters(dsaParams.getP(), dsaParams.getG(), dsaParams.getQ(), m, 0, null,
+            new DHValidationParameters(dsaParams.getValidationParameters().getSeed(), dsaParams.getValidationParameters().getCounter()));
+    }
+
+    // based on lower limit of at least 2^{2 * bits_of_security}
+    private static int chooseLowerBound(int pSize)
+    {
+        int m = 160;
+        if (pSize > 1024)
+        {
+            if (pSize <= 2048)
+            {
+                m = 224;
+            }
+            else if (pSize <= 3072)
+            {
+                m = 256;
+            }
+            else if (pSize <= 7680)
+            {
+                m = 384;
+            }
+            else
+            {
+                m = 512;
+            }
+        }
+        return m;
+    }
+
+    /**
+     * Available properties that can be set.
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static final class Property
+    {
+        /**
+         * The parameters to be used for processing implicitlyCA X9.62 parameters
+         */
+        public static final Property EC_IMPLICITLY_CA = new Property("ecImplicitlyCA", X9ECParameters.class);
+        /**
+         * The default parameters for a particular size of Diffie-Hellman key.This is a sized property.
+         */
+        public static final Property DH_DEFAULT_PARAMS= new Property("dhDefaultParams", DHParameters.class);
+        /**
+         * The default parameters for a particular size of DSA key. This is a sized property.
+         */
+        public static final Property DSA_DEFAULT_PARAMS= new Property("dsaDefaultParams", DSAParameters.class);
+        private final String name;
+        private final Class type;
+
+        private Property(String name, Class type)
+        {
+            this.name = name;
+            this.type = type;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DSA.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DSA.java
new file mode 100644
index 0000000..2d836c7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DSA.java
@@ -0,0 +1,38 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+import java.math.BigInteger;
+
+/**
+ * interface for classes implementing algorithms modeled similar to the Digital Signature Alorithm.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface DSA
+{
+    /**
+     * initialise the signer for signature generation or signature
+     * verification.
+     *
+     * @param forSigning true if we are generating a signature, false
+     * otherwise.
+     * @param param key parameters for signature generation.
+     */
+    public void init(boolean forSigning, CipherParameters param);
+
+    /**
+     * sign the passed in message (usually the output of a hash function).
+     *
+     * @param message the message to be signed.
+     * @return two big integers representing the r and s values respectively.
+     */
+    public BigInteger[] generateSignature(byte[] message);
+
+    /**
+     * verify the message message against the signature values r and s.
+     *
+     * @param message the message that was supposed to have been signed.
+     * @param r the r signature value.
+     * @param s the s signature value.
+     */
+    public boolean verifySignature(byte[] message, BigInteger  r, BigInteger s);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DSAExt.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DSAExt.java
new file mode 100644
index 0000000..c69a3f8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DSAExt.java
@@ -0,0 +1,18 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+import java.math.BigInteger;
+
+/**
+ * An "extended" interface for classes implementing DSA-style algorithms, that provides access to
+ * the group order.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface DSAExt
+    extends DSA
+{
+    /**
+     * Get the order of the group that the r, s values in signatures belong to.
+     */
+    public BigInteger getOrder();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DataLengthException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DataLengthException.java
new file mode 100644
index 0000000..a23947d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DataLengthException.java
@@ -0,0 +1,31 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * this exception is thrown if a buffer that is meant to have output
+ * copied into it turns out to be too short, or if we've been given 
+ * insufficient input. In general this exception will get thrown rather
+ * than an ArrayOutOfBounds exception.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DataLengthException 
+    extends RuntimeCryptoException
+{
+    /**
+     * base constructor.
+     */
+    public DataLengthException()
+    {
+    }
+
+    /**
+     * create a DataLengthException with the given message.
+     *
+     * @param message the message to be carried with the exception.
+     */
+    public DataLengthException(
+        String  message)
+    {
+        super(message);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DerivationFunction.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DerivationFunction.java
new file mode 100644
index 0000000..3e30b92
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DerivationFunction.java
@@ -0,0 +1,14 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * base interface for general purpose byte derivation functions.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface DerivationFunction
+{
+    public void init(DerivationParameters param);
+
+    public int generateBytes(byte[] out, int outOff, int len)
+        throws DataLengthException, IllegalArgumentException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DerivationParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DerivationParameters.java
new file mode 100644
index 0000000..4110159
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/DerivationParameters.java
@@ -0,0 +1,10 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * Parameters for key/byte stream derivation classes
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface DerivationParameters
+{
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Digest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Digest.java
new file mode 100644
index 0000000..a73ca81
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Digest.java
@@ -0,0 +1,53 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * interface that a message digest conforms to.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Digest
+{
+    /**
+     * return the algorithm name
+     *
+     * @return the algorithm name
+     */
+    public String getAlgorithmName();
+
+    /**
+     * return the size, in bytes, of the digest produced by this message digest.
+     *
+     * @return the size, in bytes, of the digest produced by this message digest.
+     */
+    public int getDigestSize();
+
+    /**
+     * update the message digest with a single byte.
+     *
+     * @param in the input byte to be entered.
+     */
+    public void update(byte in);
+
+    /**
+     * update the message digest with a block of bytes.
+     *
+     * @param in the byte array containing the data.
+     * @param inOff the offset into the byte array where the data starts.
+     * @param len the length of the data.
+     */
+    public void update(byte[] in, int inOff, int len);
+
+    /**
+     * close the digest, producing the final digest value. The doFinal
+     * call leaves the digest reset.
+     *
+     * @param out the array the digest is to be copied into.
+     * @param outOff the offset into the out array the digest is to start at.
+     */
+    public int doFinal(byte[] out, int outOff);
+
+    /**
+     * reset the digest back to it's initial state.
+     */
+    public void reset();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/ExtendedDigest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/ExtendedDigest.java
new file mode 100644
index 0000000..75db865
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/ExtendedDigest.java
@@ -0,0 +1,17 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ExtendedDigest 
+    extends Digest
+{
+    /**
+     * Return the size in bytes of the internal buffer the digest applies it's compression
+     * function to.
+     * 
+     * @return byte length of the digests internal buffer.
+     */
+    public int getByteLength();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/InvalidCipherTextException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/InvalidCipherTextException.java
new file mode 100644
index 0000000..05ebfe5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/InvalidCipherTextException.java
@@ -0,0 +1,42 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * this exception is thrown whenever we find something we don't expect in a
+ * message.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class InvalidCipherTextException 
+    extends CryptoException
+{
+    /**
+     * base constructor.
+     */
+    public InvalidCipherTextException()
+    {
+    }
+
+    /**
+     * create a InvalidCipherTextException with the given message.
+     *
+     * @param message the message to be carried with the exception.
+     */
+    public InvalidCipherTextException(
+        String  message)
+    {
+        super(message);
+    }
+
+    /**
+     * create a InvalidCipherTextException with the given message.
+     *
+     * @param message the message to be carried with the exception.
+     * @param cause the root cause of the exception.
+     */
+    public InvalidCipherTextException(
+        String  message,
+        Throwable cause)
+    {
+        super(message, cause);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/KeyGenerationParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/KeyGenerationParameters.java
new file mode 100644
index 0000000..a563655
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/KeyGenerationParameters.java
@@ -0,0 +1,50 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+import java.security.SecureRandom;
+
+/**
+ * The base class for parameters to key generators.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyGenerationParameters
+{
+    private SecureRandom    random;
+    private int             strength;
+
+    /**
+     * initialise the generator with a source of randomness
+     * and a strength (in bits).
+     *
+     * @param random the random byte source.
+     * @param strength the size, in bits, of the keys we want to produce.
+     */
+    public KeyGenerationParameters(
+        SecureRandom    random,
+        int             strength)
+    {
+        this.random = random;
+        this.strength = strength;
+    }
+
+    /**
+     * return the random source associated with this
+     * generator.
+     *
+     * @return the generators random source.
+     */
+    public SecureRandom getRandom()
+    {
+        return random;
+    }
+
+    /**
+     * return the bit strength for keys produced by this generator,
+     *
+     * @return the strength of the keys this generator produces (in bits).
+     */
+    public int getStrength()
+    {
+        return strength;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Mac.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Mac.java
new file mode 100644
index 0000000..e7ec29d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Mac.java
@@ -0,0 +1,73 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+
+/**
+ * The base interface for implementations of message authentication codes (MACs).
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Mac
+{
+    /**
+     * Initialise the MAC.
+     *
+     * @param params the key and other data required by the MAC.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(CipherParameters params)
+        throws IllegalArgumentException;
+
+    /**
+     * Return the name of the algorithm the MAC implements.
+     *
+     * @return the name of the algorithm the MAC implements.
+     */
+    public String getAlgorithmName();
+
+    /**
+     * Return the block size for this MAC (in bytes).
+     *
+     * @return the block size for this MAC in bytes.
+     */
+    public int getMacSize();
+
+    /**
+     * add a single byte to the mac for processing.
+     *
+     * @param in the byte to be processed.
+     * @exception IllegalStateException if the MAC is not initialised.
+     */
+    public void update(byte in)
+        throws IllegalStateException;
+
+    /**
+     * @param in the array containing the input.
+     * @param inOff the index in the array the data begins at.
+     * @param len the length of the input starting at inOff.
+     * @exception IllegalStateException if the MAC is not initialised.
+     * @exception DataLengthException if there isn't enough data in in.
+     */
+    public void update(byte[] in, int inOff, int len)
+        throws DataLengthException, IllegalStateException;
+
+    /**
+     * Compute the final stage of the MAC writing the output to the out
+     * parameter.
+     * <p>
+     * doFinal leaves the MAC in the same state it was after the last init.
+     *
+     * @param out the array the MAC is to be output to.
+     * @param outOff the offset into the out buffer the output is to start at.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the MAC is not initialised.
+     */
+    public int doFinal(byte[] out, int outOff)
+        throws DataLengthException, IllegalStateException;
+
+    /**
+     * Reset the MAC. At the end of resetting the MAC should be in the
+     * in the same state it was after the last init (if there was one).
+     */
+    public void reset();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/OutputLengthException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/OutputLengthException.java
new file mode 100644
index 0000000..c87bd1e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/OutputLengthException.java
@@ -0,0 +1,14 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OutputLengthException
+    extends DataLengthException
+{
+    public OutputLengthException(String msg)
+    {
+        super(msg);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/PBEParametersGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/PBEParametersGenerator.java
new file mode 100644
index 0000000..8ac380f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/PBEParametersGenerator.java
@@ -0,0 +1,173 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * super class for all Password Based Encryption (PBE) parameter generator classes.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class PBEParametersGenerator
+{
+    protected byte[]  password;
+    protected byte[]  salt;
+    protected int     iterationCount;
+
+    /**
+     * base constructor.
+     */
+    protected PBEParametersGenerator()
+    {
+    }
+
+    /**
+     * initialise the PBE generator.
+     *
+     * @param password the password converted into bytes (see below).
+     * @param salt the salt to be mixed with the password.
+     * @param iterationCount the number of iterations the "mixing" function
+     * is to be applied for.
+     */
+    public void init(
+        byte[]  password,
+        byte[]  salt,
+        int     iterationCount)
+    {
+        this.password = password;
+        this.salt = salt;
+        this.iterationCount = iterationCount;
+    }
+
+    /**
+     * return the password byte array.
+     *
+     * @return the password byte array.
+     */
+    public byte[] getPassword()
+    {
+        return password;
+    }
+
+    /**
+     * return the salt byte array.
+     *
+     * @return the salt byte array.
+     */
+    public byte[] getSalt()
+    {
+        return salt;
+    }
+
+    /**
+     * return the iteration count.
+     *
+     * @return the iteration count.
+     */
+    public int getIterationCount()
+    {
+        return iterationCount;
+    }
+
+    /**
+     * generate derived parameters for a key of length keySize.
+     *
+     * @param keySize the length, in bits, of the key required.
+     * @return a parameters object representing a key.
+     */
+    public abstract CipherParameters generateDerivedParameters(int keySize);
+
+    /**
+     * generate derived parameters for a key of length keySize, and
+     * an initialisation vector (IV) of length ivSize.
+     *
+     * @param keySize the length, in bits, of the key required.
+     * @param ivSize the length, in bits, of the iv required.
+     * @return a parameters object representing a key and an IV.
+     */
+    public abstract CipherParameters generateDerivedParameters(int keySize, int ivSize);
+
+    /**
+     * generate derived parameters for a key of length keySize, specifically
+     * for use with a MAC.
+     *
+     * @param keySize the length, in bits, of the key required.
+     * @return a parameters object representing a key.
+     */
+    public abstract CipherParameters generateDerivedMacParameters(int keySize);
+
+    /**
+     * converts a password to a byte array according to the scheme in
+     * PKCS5 (ascii, no padding)
+     *
+     * @param password a character array representing the password.
+     * @return a byte array representing the password.
+     */
+    public static byte[] PKCS5PasswordToBytes(
+        char[]  password)
+    {
+        if (password != null)
+        {
+            byte[]  bytes = new byte[password.length];
+
+            for (int i = 0; i != bytes.length; i++)
+            {
+                bytes[i] = (byte)password[i];
+            }
+
+            return bytes;
+        }
+        else
+        {
+            return new byte[0];
+        }
+    }
+
+    /**
+     * converts a password to a byte array according to the scheme in
+     * PKCS5 (UTF-8, no padding)
+     *
+     * @param password a character array representing the password.
+     * @return a byte array representing the password.
+     */
+    public static byte[] PKCS5PasswordToUTF8Bytes(
+        char[]  password)
+    {
+        if (password != null)
+        {
+            return Strings.toUTF8ByteArray(password);
+        }
+        else
+        {
+            return new byte[0];
+        }
+    }
+
+    /**
+     * converts a password to a byte array according to the scheme in
+     * PKCS12 (unicode, big endian, 2 zero pad bytes at the end).
+     *
+     * @param password a character array representing the password.
+     * @return a byte array representing the password.
+     */
+    public static byte[] PKCS12PasswordToBytes(
+        char[]  password)
+    {
+        if (password != null && password.length > 0)
+        {
+                                       // +1 for extra 2 pad bytes.
+            byte[]  bytes = new byte[(password.length + 1) * 2];
+
+            for (int i = 0; i != password.length; i ++)
+            {
+                bytes[i * 2] = (byte)(password[i] >>> 8);
+                bytes[i * 2 + 1] = (byte)password[i];
+            }
+
+            return bytes;
+        }
+        else
+        {
+            return new byte[0];
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/RawAgreement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/RawAgreement.java
new file mode 100644
index 0000000..19ee267
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/RawAgreement.java
@@ -0,0 +1,14 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface RawAgreement
+{
+    void init(CipherParameters parameters);
+
+    int getAgreementSize();
+
+    void calculateAgreement(CipherParameters publicKey, byte[] buf, int off);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/RuntimeCryptoException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/RuntimeCryptoException.java
new file mode 100644
index 0000000..44122cb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/RuntimeCryptoException.java
@@ -0,0 +1,28 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * the foundation class for the exceptions thrown by the crypto packages.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RuntimeCryptoException 
+    extends RuntimeException
+{
+    /**
+     * base constructor.
+     */
+    public RuntimeCryptoException()
+    {
+    }
+
+    /**
+     * create a RuntimeCryptoException with the given message.
+     *
+     * @param message the message to be carried with the exception.
+     */
+    public RuntimeCryptoException(
+        String  message)
+    {
+        super(message);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Signer.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Signer.java
new file mode 100644
index 0000000..3cecaa4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Signer.java
@@ -0,0 +1,45 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * Generic signer interface for hash based and message recovery signers.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Signer 
+{
+    /**
+     * Initialise the signer for signing or verification.
+     * 
+     * @param forSigning true if for signing, false otherwise
+     * @param param necessary parameters.
+     */
+    public void init(boolean forSigning, CipherParameters param);
+
+    /**
+     * update the internal digest with the byte b
+     */
+    public void update(byte b);
+
+    /**
+     * update the internal digest with the byte array in
+     */
+    public void update(byte[] in, int off, int len);
+
+    /**
+     * generate a signature for the message we've been loaded with using
+     * the key we were initialised with.
+     */
+    public byte[] generateSignature()
+        throws CryptoException, DataLengthException;
+
+    /**
+     * return true if the internal state represents the signature described
+     * in the passed in array.
+     */
+    public boolean verifySignature(byte[] signature);
+    
+    /**
+     * reset the internal state
+     */
+    public void reset();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/SignerWithRecovery.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/SignerWithRecovery.java
new file mode 100644
index 0000000..d211afe
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/SignerWithRecovery.java
@@ -0,0 +1,36 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * Signer with message recovery.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface SignerWithRecovery 
+    extends Signer
+{
+    /**
+     * Returns true if the signer has recovered the full message as
+     * part of signature verification.
+     * 
+     * @return true if full message recovered.
+     */
+    public boolean hasFullMessage();
+    
+    /**
+     * Returns a reference to what message was recovered (if any).
+     * 
+     * @return full/partial message, null if nothing.
+     */
+    public byte[] getRecoveredMessage();
+
+    /**
+     * Perform an update with the recovered message before adding any other data. This must
+     * be the first update method called, and calling it will result in the signer assuming
+     * that further calls to update will include message content past what is recoverable.
+     *
+     * @param signature the signature that we are in the process of verifying.
+     * @throws IllegalStateException
+     */
+    public void updateWithRecoveredMessage(byte[] signature)
+        throws InvalidCipherTextException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/SkippingCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/SkippingCipher.java
new file mode 100644
index 0000000..709041e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/SkippingCipher.java
@@ -0,0 +1,33 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * Ciphers producing a key stream which can be reset to particular points in the stream implement this.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface SkippingCipher
+{
+    /**
+     * Skip numberOfBytes forwards, or backwards.
+     *
+     * @param numberOfBytes the number of bytes to skip (positive forward, negative backwards).
+     * @return the number of bytes actually skipped.
+     * @throws java.lang.IllegalArgumentException if numberOfBytes is an invalid value.
+     */
+    long skip(long numberOfBytes);
+
+    /**
+     * Reset the cipher and then skip forward to a given position.
+     *
+     * @param position the number of bytes in to set the cipher state to.
+     * @return the byte position moved to.
+     */
+    long seekTo(long position);
+
+    /**
+     * Return the current "position" of the cipher
+     *
+     * @return the current byte position.
+     */
+    long getPosition();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/SkippingStreamCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/SkippingStreamCipher.java
new file mode 100644
index 0000000..ee3e335
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/SkippingStreamCipher.java
@@ -0,0 +1,11 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * General interface for a stream cipher that supports skipping.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface SkippingStreamCipher
+    extends StreamCipher, SkippingCipher
+{
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/StreamBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/StreamBlockCipher.java
new file mode 100644
index 0000000..b52b224
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/StreamBlockCipher.java
@@ -0,0 +1,59 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * A parent class for block cipher modes that do not require block aligned data to be processed, but can function in
+ * a streaming mode.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class StreamBlockCipher
+    implements BlockCipher, StreamCipher
+{
+    private final BlockCipher cipher;
+
+    protected StreamBlockCipher(BlockCipher cipher)
+    {
+        this.cipher = cipher;
+    }
+
+    /**
+     * return the underlying block cipher that we are wrapping.
+     *
+     * @return the underlying block cipher that we are wrapping.
+     */
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+    public final byte returnByte(byte in)
+    {
+        return calculateByte(in);
+    }
+
+    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+        throws DataLengthException
+    {
+        if (inOff + len > in.length)
+        {
+            throw new DataLengthException("input buffer too small");
+        }
+        if (outOff + len > out.length)
+        {
+            throw new OutputLengthException("output buffer too short");
+        }
+
+        int inStart = inOff;
+        int inEnd = inOff + len;
+        int outStart = outOff;
+
+        while (inStart < inEnd)
+        {
+             out[outStart++] = calculateByte(in[inStart++]);
+        }
+
+        return len;
+    }
+
+    protected abstract byte calculateByte(byte b);
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/StreamCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/StreamCipher.java
new file mode 100644
index 0000000..0564bbb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/StreamCipher.java
@@ -0,0 +1,56 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * the interface stream ciphers conform to.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface StreamCipher
+{
+    /**
+     * Initialise the cipher.
+     *
+     * @param forEncryption if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(boolean forEncryption, CipherParameters params)
+        throws IllegalArgumentException;
+
+    /**
+     * Return the name of the algorithm the cipher implements.
+     *
+     * @return the name of the algorithm the cipher implements.
+     */
+    public String getAlgorithmName();
+
+    /**
+     * encrypt/decrypt a single byte returning the result.
+     *
+     * @param in the byte to be processed.
+     * @return the result of processing the input byte.
+     */
+    public byte returnByte(byte in);
+
+    /**
+     * process a block of bytes from in putting the result into out.
+     *
+     * @param in the input byte array.
+     * @param inOff the offset into the in array where the data to be processed starts.
+     * @param len the number of bytes to be processed.
+     * @param out the output buffer the processed bytes go into.
+     * @param outOff the offset into the output byte array the processed data starts at.
+     * @return the number of bytes produced - should always be len.
+     * @exception DataLengthException if the output buffer is too small.
+     */
+    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+        throws DataLengthException;
+
+    /**
+     * reset the cipher. This leaves it in the same state
+     * it was at after the last init (if there was one).
+     */
+    public void reset();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Wrapper.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Wrapper.java
new file mode 100644
index 0000000..1d24270
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/Wrapper.java
@@ -0,0 +1,22 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Wrapper
+{
+    public void init(boolean forWrapping, CipherParameters param);
+
+    /**
+     * Return the name of the algorithm the wrapper implements.
+     *
+     * @return the name of the algorithm the wrapper implements.
+     */
+    public String getAlgorithmName();
+
+    public byte[] wrap(byte[] in, int inOff, int inLen);
+
+    public byte[] unwrap(byte[] in, int inOff, int inLen)
+        throws InvalidCipherTextException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/agreement/DHBasicAgreement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/agreement/DHBasicAgreement.java
new file mode 100644
index 0000000..718e105
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/agreement/DHBasicAgreement.java
@@ -0,0 +1,89 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.agreement;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.crypto.BasicAgreement;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+
+/**
+ * a Diffie-Hellman key agreement class.
+ * <p>
+ * note: This is only the basic algorithm, it doesn't take advantage of
+ * long term public keys if they are available. See the DHAgreement class
+ * for a "better" implementation.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHBasicAgreement
+    implements BasicAgreement
+{
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+
+    private DHPrivateKeyParameters  key;
+    private DHParameters            dhParams;
+
+    public void init(
+        CipherParameters    param)
+    {
+        AsymmetricKeyParameter  kParam;
+
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom rParam = (ParametersWithRandom)param;
+            kParam = (AsymmetricKeyParameter)rParam.getParameters();
+        }
+        else
+        {
+            kParam = (AsymmetricKeyParameter)param;
+        }
+
+        if (!(kParam instanceof DHPrivateKeyParameters))
+        {
+            throw new IllegalArgumentException("DHEngine expects DHPrivateKeyParameters");
+        }
+
+        this.key = (DHPrivateKeyParameters)kParam;
+        this.dhParams = key.getParameters();
+    }
+
+    public int getFieldSize()
+    {
+        return (key.getParameters().getP().bitLength() + 7) / 8;
+    }
+
+    /**
+     * given a short term public key from a given party calculate the next
+     * message in the agreement sequence. 
+     */
+    public BigInteger calculateAgreement(
+        CipherParameters   pubKey)
+    {
+        DHPublicKeyParameters   pub = (DHPublicKeyParameters)pubKey;
+
+        if (!pub.getParameters().equals(dhParams))
+        {
+            throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters.");
+        }
+
+        BigInteger p = dhParams.getP();
+
+        BigInteger peerY = pub.getY();
+        if (peerY == null || peerY.compareTo(ONE) <= 0 || peerY.compareTo(p.subtract(ONE)) >= 0)
+        {
+            throw new IllegalArgumentException("Diffie-Hellman public key is weak");
+        }
+
+        BigInteger result = peerY.modPow(key.getX(), p);
+        if (result.equals(ONE))
+        {
+            throw new IllegalStateException("Shared key can't be 1");
+        }
+
+        return result;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
new file mode 100644
index 0000000..944a986
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
@@ -0,0 +1,80 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.agreement;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.crypto.BasicAgreement;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import com.android.internal.org.bouncycastle.math.ec.ECAlgorithms;
+import com.android.internal.org.bouncycastle.math.ec.ECConstants;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * P1363 7.2.1 ECSVDP-DH
+ *
+ * ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive,
+ * Diffie-Hellman version. It is based on the work of [DH76], [Mil86],
+ * and [Kob87]. This primitive derives a shared secret value from one
+ * party's private key and another party's public key, where both have
+ * the same set of EC domain parameters. If two parties correctly
+ * execute this primitive, they will produce the same output. This
+ * primitive can be invoked by a scheme to derive a shared secret key;
+ * specifically, it may be used with the schemes ECKAS-DH1 and
+ * DL/ECKAS-DH2. It assumes that the input keys are valid (see also
+ * Section 7.2.2).
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECDHBasicAgreement
+    implements BasicAgreement
+{
+    private ECPrivateKeyParameters key;
+
+    public void init(
+        CipherParameters key)
+    {
+        this.key = (ECPrivateKeyParameters)key;
+    }
+
+    public int getFieldSize()
+    {
+        return (key.getParameters().getCurve().getFieldSize() + 7) / 8;
+    }
+
+    public BigInteger calculateAgreement(
+        CipherParameters pubKey)
+    {
+        ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey;
+        ECDomainParameters params = key.getParameters();
+        if (!params.equals(pub.getParameters()))
+        {
+            throw new IllegalStateException("ECDH public key has wrong domain parameters");
+        }
+
+        BigInteger d = key.getD();
+
+        // Always perform calculations on the exact curve specified by our private key's parameters
+        ECPoint Q = ECAlgorithms.cleanPoint(params.getCurve(), pub.getQ());
+        if (Q.isInfinity())
+        {
+            throw new IllegalStateException("Infinity is not a valid public key for ECDH");
+        }
+
+        BigInteger h = params.getH();
+        if (!h.equals(ECConstants.ONE))
+        {
+            d = params.getHInv().multiply(d).mod(params.getN());
+            Q = ECAlgorithms.referenceMultiply(Q, h);
+        }
+
+        ECPoint P = Q.multiply(d).normalize();
+        if (P.isInfinity())
+        {
+            throw new IllegalStateException("Infinity is not a valid agreement value for ECDH");
+        }
+
+        return P.getAffineXCoord().toBigInteger();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactory.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactory.java
new file mode 100644
index 0000000..638b962
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactory.java
@@ -0,0 +1,111 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+import java.security.Security;
+import java.util.Locale;
+
+import com.android.internal.org.bouncycastle.crypto.Digest;
+
+/**
+ * Level of indirection to let us select OpenSSLDigest implementations
+ * for libcore but fallback to BouncyCastle ones on the RI.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class AndroidDigestFactory {
+    private static final AndroidDigestFactoryInterface CONSCRYPT;
+    private static final AndroidDigestFactoryInterface BC;
+
+    static {
+        BC = new AndroidDigestFactoryBouncyCastle();
+        if (Security.getProvider("AndroidOpenSSL") != null) {
+            CONSCRYPT = new AndroidDigestFactoryOpenSSL();
+        } else {
+            if (System.getProperty("java.vendor", "").toLowerCase(Locale.US).contains("android")) {
+                throw new AssertionError("Provider AndroidOpenSSL must exist");
+            }
+            CONSCRYPT = null;
+        }
+    }
+
+    public static Digest getMD5() {
+        if (CONSCRYPT != null) {
+            try {
+                return CONSCRYPT.getMD5();
+            } catch (Exception ignored) {
+            }
+        }
+
+        return BC.getMD5();
+    }
+
+    public static Digest getSHA1() {
+        if (CONSCRYPT != null) {
+            try {
+                return CONSCRYPT.getSHA1();
+            } catch (Exception ignored) {
+            }
+        }
+
+        return BC.getSHA1();
+    }
+
+    public static Digest getSHA224() {
+        if (CONSCRYPT != null) {
+            try {
+                return CONSCRYPT.getSHA224();
+            } catch (Exception ignored) {
+            }
+        }
+
+        return BC.getSHA224();
+    }
+
+    public static Digest getSHA256() {
+        if (CONSCRYPT != null) {
+            try {
+                return CONSCRYPT.getSHA256();
+            } catch (Exception ignored) {
+            }
+        }
+
+        return BC.getSHA256();
+    }
+
+    public static Digest getSHA384() {
+        if (CONSCRYPT != null) {
+            try {
+                return CONSCRYPT.getSHA384();
+            } catch (Exception ignored) {
+            }
+        }
+
+        return BC.getSHA384();
+    }
+
+    public static Digest getSHA512() {
+        if (CONSCRYPT != null) {
+            try {
+                return CONSCRYPT.getSHA512();
+            } catch (Exception ignored) {
+            }
+        }
+
+        return BC.getSHA512();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java
new file mode 100644
index 0000000..bfbe92c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java
@@ -0,0 +1,44 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+import com.android.internal.org.bouncycastle.crypto.Digest;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AndroidDigestFactoryBouncyCastle implements AndroidDigestFactoryInterface {
+    public Digest getMD5() {
+        return new MD5Digest();
+    }
+    public Digest getSHA1() {
+        return new SHA1Digest();
+    }
+    public Digest getSHA224() {
+        return new SHA224Digest();
+    }
+    public Digest getSHA256() {
+        return new SHA256Digest();
+    }
+    public Digest getSHA384() {
+        return new SHA384Digest();
+    }
+    public Digest getSHA512() {
+        return new SHA512Digest();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java
new file mode 100644
index 0000000..cee9ca8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+import com.android.internal.org.bouncycastle.crypto.Digest;
+
+interface AndroidDigestFactoryInterface {
+    public Digest getMD5();
+    public Digest getSHA1();
+    public Digest getSHA224();
+    public Digest getSHA256();
+    public Digest getSHA384();
+    public Digest getSHA512();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java
new file mode 100644
index 0000000..1cc3451
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java
@@ -0,0 +1,44 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+import com.android.internal.org.bouncycastle.crypto.Digest;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AndroidDigestFactoryOpenSSL implements AndroidDigestFactoryInterface {
+    public Digest getMD5() {
+        return new OpenSSLDigest.MD5();
+    }
+    public Digest getSHA1() {
+        return new OpenSSLDigest.SHA1();
+    }
+    public Digest getSHA224() {
+        return new OpenSSLDigest.SHA224();
+    }
+    public Digest getSHA256() {
+        return new OpenSSLDigest.SHA256();
+    }
+    public Digest getSHA384() {
+        return new OpenSSLDigest.SHA384();
+    }
+    public Digest getSHA512() {
+        return new OpenSSLDigest.SHA512();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/EncodableDigest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/EncodableDigest.java
new file mode 100644
index 0000000..9197ba6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/EncodableDigest.java
@@ -0,0 +1,19 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+/**
+ *  Encodable digests allow you to download an encoded copy of their internal state. This is useful for the situation where
+ *  you need to generate a signature on an external device and it allows for "sign with last round", so a copy of the
+ *  internal state of the digest, plus the last few blocks of the message are all that needs to be sent, rather than the
+ *  entire message.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface EncodableDigest
+{
+    /**
+     * Return an encoded byte array for the digest's internal state
+     *
+     * @return an encoding of the digests internal state.
+     */
+    byte[] getEncodedState();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/GeneralDigest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/GeneralDigest.java
new file mode 100644
index 0000000..75038bd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/GeneralDigest.java
@@ -0,0 +1,162 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+import com.android.internal.org.bouncycastle.crypto.ExtendedDigest;
+import com.android.internal.org.bouncycastle.util.Memoable;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * base implementation of MD4 family style digest as outlined in
+ * "Handbook of Applied Cryptography", pages 344 - 347.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class GeneralDigest
+    implements ExtendedDigest, Memoable
+{
+    private static final int BYTE_LENGTH = 64;
+
+    private final byte[]  xBuf = new byte[4];
+    private int           xBufOff;
+
+    private long    byteCount;
+
+    /**
+     * Standard constructor
+     */
+    protected GeneralDigest()
+    {
+        xBufOff = 0;
+    }
+
+    /**
+     * Copy constructor.  We are using copy constructors in place
+     * of the Object.clone() interface as this interface is not
+     * supported by J2ME.
+     */
+    protected GeneralDigest(GeneralDigest t)
+    {
+        copyIn(t);
+    }
+
+    protected GeneralDigest(byte[] encodedState)
+    {
+        System.arraycopy(encodedState, 0, xBuf, 0, xBuf.length);
+        xBufOff = Pack.bigEndianToInt(encodedState, 4);
+        byteCount = Pack.bigEndianToLong(encodedState, 8);
+    }
+
+    protected void copyIn(GeneralDigest t)
+    {
+        System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
+
+        xBufOff = t.xBufOff;
+        byteCount = t.byteCount;
+    }
+
+    public void update(
+        byte in)
+    {
+        xBuf[xBufOff++] = in;
+
+        if (xBufOff == xBuf.length)
+        {
+            processWord(xBuf, 0);
+            xBufOff = 0;
+        }
+
+        byteCount++;
+    }
+
+    public void update(
+        byte[]  in,
+        int     inOff,
+        int     len)
+    {
+        len = Math.max(0,  len);
+
+        //
+        // fill the current word
+        //
+        int i = 0;
+        if (xBufOff != 0)
+        {
+            while (i < len)
+            {
+                xBuf[xBufOff++] = in[inOff + i++];
+                if (xBufOff == 4)
+                {
+                    processWord(xBuf, 0);
+                    xBufOff = 0;
+                    break;
+                }
+            }
+        }
+
+        //
+        // process whole words.
+        //
+        int limit = ((len - i) & ~3) + i;
+        for (; i < limit; i += 4)
+        {
+            processWord(in, inOff + i);
+        }
+
+        //
+        // load in the remainder.
+        //
+        while (i < len)
+        {
+            xBuf[xBufOff++] = in[inOff + i++];
+        }
+
+        byteCount += len;
+    }
+
+    public void finish()
+    {
+        long    bitLength = (byteCount << 3);
+
+        //
+        // add the pad bytes.
+        //
+        update((byte)128);
+
+        while (xBufOff != 0)
+        {
+            update((byte)0);
+        }
+
+        processLength(bitLength);
+
+        processBlock();
+    }
+
+    public void reset()
+    {
+        byteCount = 0;
+
+        xBufOff = 0;
+        for (int i = 0; i < xBuf.length; i++)
+        {
+            xBuf[i] = 0;
+        }
+    }
+
+    protected void populateState(byte[] state)
+    {
+        System.arraycopy(xBuf, 0, state, 0, xBufOff);
+        Pack.intToBigEndian(xBufOff, state, 4);
+        Pack.longToBigEndian(byteCount, state, 8);
+    }
+
+    public int getByteLength()
+    {
+        return BYTE_LENGTH;
+    }
+    
+    protected abstract void processWord(byte[] in, int inOff);
+
+    protected abstract void processLength(long bitLength);
+
+    protected abstract void processBlock();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/LongDigest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/LongDigest.java
new file mode 100644
index 0000000..cc7411e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/LongDigest.java
@@ -0,0 +1,411 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+import com.android.internal.org.bouncycastle.crypto.ExtendedDigest;
+import com.android.internal.org.bouncycastle.util.Memoable;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * Base class for SHA-384 and SHA-512.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class LongDigest
+    implements ExtendedDigest, Memoable, EncodableDigest
+{
+    private static final int BYTE_LENGTH = 128;
+
+    private byte[] xBuf = new byte[8];
+    private int     xBufOff;
+
+    private long    byteCount1;
+    private long    byteCount2;
+
+    protected long    H1, H2, H3, H4, H5, H6, H7, H8;
+
+    private long[]  W = new long[80];
+    private int     wOff;
+
+    /**
+     * Constructor for variable length word
+     */
+    protected LongDigest()
+    {
+        xBufOff = 0;
+
+        reset();
+    }
+
+    /**
+     * Copy constructor.  We are using copy constructors in place
+     * of the Object.clone() interface as this interface is not
+     * supported by J2ME.
+     */
+    protected LongDigest(LongDigest t)
+    {
+        copyIn(t);
+    }
+
+    protected void copyIn(LongDigest t)
+    {
+        System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
+
+        xBufOff = t.xBufOff;
+        byteCount1 = t.byteCount1;
+        byteCount2 = t.byteCount2;
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+        H5 = t.H5;
+        H6 = t.H6;
+        H7 = t.H7;
+        H8 = t.H8;
+
+        System.arraycopy(t.W, 0, W, 0, t.W.length);
+        wOff = t.wOff;
+    }
+
+    protected void populateState(byte[] state)
+    {
+        System.arraycopy(xBuf, 0, state, 0, xBufOff);
+        Pack.intToBigEndian(xBufOff, state, 8);
+        Pack.longToBigEndian(byteCount1, state, 12);
+        Pack.longToBigEndian(byteCount2, state, 20);
+        Pack.longToBigEndian(H1, state, 28);
+        Pack.longToBigEndian(H2, state, 36);
+        Pack.longToBigEndian(H3, state, 44);
+        Pack.longToBigEndian(H4, state, 52);
+        Pack.longToBigEndian(H5, state, 60);
+        Pack.longToBigEndian(H6, state, 68);
+        Pack.longToBigEndian(H7, state, 76);
+        Pack.longToBigEndian(H8, state, 84);
+
+        Pack.intToBigEndian(wOff, state, 92);
+        for (int i = 0; i < wOff; i++)
+        {
+            Pack.longToBigEndian(W[i], state, 96 + (i * 8));
+        }
+    }
+
+    protected void restoreState(byte[] encodedState)
+    {
+        xBufOff = Pack.bigEndianToInt(encodedState, 8);
+        System.arraycopy(encodedState, 0, xBuf, 0, xBufOff);
+        byteCount1 = Pack.bigEndianToLong(encodedState, 12);
+        byteCount2 = Pack.bigEndianToLong(encodedState, 20);
+
+        H1 = Pack.bigEndianToLong(encodedState, 28);
+        H2 = Pack.bigEndianToLong(encodedState, 36);
+        H3 = Pack.bigEndianToLong(encodedState, 44);
+        H4 = Pack.bigEndianToLong(encodedState, 52);
+        H5 = Pack.bigEndianToLong(encodedState, 60);
+        H6 = Pack.bigEndianToLong(encodedState, 68);
+        H7 = Pack.bigEndianToLong(encodedState, 76);
+        H8 = Pack.bigEndianToLong(encodedState, 84);
+
+        wOff = Pack.bigEndianToInt(encodedState, 92);
+        for (int i = 0; i < wOff; i++)
+        {
+            W[i] = Pack.bigEndianToLong(encodedState, 96 + (i * 8));
+        }
+    }
+
+    protected int getEncodedStateSize()
+    {
+        return 96 + (wOff * 8);
+    }
+
+    public void update(
+        byte in)
+    {
+        xBuf[xBufOff++] = in;
+
+        if (xBufOff == xBuf.length)
+        {
+            processWord(xBuf, 0);
+            xBufOff = 0;
+        }
+
+        byteCount1++;
+    }
+
+    public void update(
+        byte[]  in,
+        int     inOff,
+        int     len)
+    {
+        //
+        // fill the current word
+        //
+        while ((xBufOff != 0) && (len > 0))
+        {
+            update(in[inOff]);
+
+            inOff++;
+            len--;
+        }
+
+        //
+        // process whole words.
+        //
+        while (len > xBuf.length)
+        {
+            processWord(in, inOff);
+
+            inOff += xBuf.length;
+            len -= xBuf.length;
+            byteCount1 += xBuf.length;
+        }
+
+        //
+        // load in the remainder.
+        //
+        while (len > 0)
+        {
+            update(in[inOff]);
+
+            inOff++;
+            len--;
+        }
+    }
+
+    public void finish()
+    {
+        adjustByteCounts();
+
+        long    lowBitLength = byteCount1 << 3;
+        long    hiBitLength = byteCount2;
+
+        //
+        // add the pad bytes.
+        //
+        update((byte)128);
+
+        while (xBufOff != 0)
+        {
+            update((byte)0);
+        }
+
+        processLength(lowBitLength, hiBitLength);
+
+        processBlock();
+    }
+
+    public void reset()
+    {
+        byteCount1 = 0;
+        byteCount2 = 0;
+
+        xBufOff = 0;
+        for (int i = 0; i < xBuf.length; i++)
+        {
+            xBuf[i] = 0;
+        }
+
+        wOff = 0;
+        for (int i = 0; i != W.length; i++)
+        {
+            W[i] = 0;
+        }
+    }
+
+    public int getByteLength()
+    {
+        return BYTE_LENGTH;
+    }
+
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        W[wOff] = Pack.bigEndianToLong(in, inOff);
+
+        if (++wOff == 16)
+        {
+            processBlock();
+        }
+    }
+
+    /**
+     * adjust the byte counts so that byteCount2 represents the
+     * upper long (less 3 bits) word of the byte count.
+     */
+    private void adjustByteCounts()
+    {
+        if (byteCount1 > 0x1fffffffffffffffL)
+        {
+            byteCount2 += (byteCount1 >>> 61);
+            byteCount1 &= 0x1fffffffffffffffL;
+        }
+    }
+
+    protected void processLength(
+        long    lowW,
+        long    hiW)
+    {
+        if (wOff > 14)
+        {
+            processBlock();
+        }
+
+        W[14] = hiW;
+        W[15] = lowW;
+    }
+
+    protected void processBlock()
+    {
+        adjustByteCounts();
+
+        //
+        // expand 16 word block into 80 word blocks.
+        //
+        for (int t = 16; t <= 79; t++)
+        {
+            W[t] = Sigma1(W[t - 2]) + W[t - 7] + Sigma0(W[t - 15]) + W[t - 16];
+        }
+
+        //
+        // set up working variables.
+        //
+        long     a = H1;
+        long     b = H2;
+        long     c = H3;
+        long     d = H4;
+        long     e = H5;
+        long     f = H6;
+        long     g = H7;
+        long     h = H8;
+
+        int t = 0;
+        for(int i = 0; i < 10; i ++)
+        {
+          // t = 8 * i
+          h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++];
+          d += h;
+          h += Sum0(a) + Maj(a, b, c);
+
+          // t = 8 * i + 1
+          g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++];
+          c += g;
+          g += Sum0(h) + Maj(h, a, b);
+
+          // t = 8 * i + 2
+          f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++];
+          b += f;
+          f += Sum0(g) + Maj(g, h, a);
+
+          // t = 8 * i + 3
+          e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++];
+          a += e;
+          e += Sum0(f) + Maj(f, g, h);
+
+          // t = 8 * i + 4
+          d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++];
+          h += d;
+          d += Sum0(e) + Maj(e, f, g);
+
+          // t = 8 * i + 5
+          c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++];
+          g += c;
+          c += Sum0(d) + Maj(d, e, f);
+
+          // t = 8 * i + 6
+          b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++];
+          f += b;
+          b += Sum0(c) + Maj(c, d, e);
+
+          // t = 8 * i + 7
+          a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++];
+          e += a;
+          a += Sum0(b) + Maj(b, c, d);
+        }
+
+        H1 += a;
+        H2 += b;
+        H3 += c;
+        H4 += d;
+        H5 += e;
+        H6 += f;
+        H7 += g;
+        H8 += h;
+
+        //
+        // reset the offset and clean out the word buffer.
+        //
+        wOff = 0;
+        for (int i = 0; i < 16; i++)
+        {
+            W[i] = 0;
+        }
+    }
+
+    /* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */
+    private long Ch(
+        long    x,
+        long    y,
+        long    z)
+    {
+        return ((x & y) ^ ((~x) & z));
+    }
+
+    private long Maj(
+        long    x,
+        long    y,
+        long    z)
+    {
+        return ((x & y) ^ (x & z) ^ (y & z));
+    }
+
+    private long Sum0(
+        long    x)
+    {
+        return ((x << 36)|(x >>> 28)) ^ ((x << 30)|(x >>> 34)) ^ ((x << 25)|(x >>> 39));
+    }
+
+    private long Sum1(
+        long    x)
+    {
+        return ((x << 50)|(x >>> 14)) ^ ((x << 46)|(x >>> 18)) ^ ((x << 23)|(x >>> 41));
+    }
+
+    private long Sigma0(
+        long    x)
+    {
+        return ((x << 63)|(x >>> 1)) ^ ((x << 56)|(x >>> 8)) ^ (x >>> 7);
+    }
+
+    private long Sigma1(
+        long    x)
+    {
+        return ((x << 45)|(x >>> 19)) ^ ((x << 3)|(x >>> 61)) ^ (x >>> 6);
+    }
+
+    /* SHA-384 and SHA-512 Constants
+     * (represent the first 64 bits of the fractional parts of the
+     * cube roots of the first sixty-four prime numbers)
+     */
+    static final long K[] = {
+0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL,
+0x3956c25bf348b538L, 0x59f111f1b605d019L, 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L,
+0xd807aa98a3030242L, 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
+0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, 0xc19bf174cf692694L,
+0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L,
+0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
+0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L,
+0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, 0x06ca6351e003826fL, 0x142929670a0e6e70L,
+0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
+0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, 0x92722c851482353bL,
+0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, 0xc24b8b70d0f89791L, 0xc76c51a30654be30L,
+0xd192e819d6ef5218L, 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L,
+0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L,
+0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L,
+0x748f82ee5defb2fcL, 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL,
+0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL,
+0xca273eceea26619cL, 0xd186b8c721c0c207L, 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L,
+0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
+0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL,
+0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L
+    };
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/MD4Digest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/MD4Digest.java
new file mode 100644
index 0000000..9b8176d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/MD4Digest.java
@@ -0,0 +1,293 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+
+import com.android.internal.org.bouncycastle.util.Memoable;
+
+/**
+ * implementation of MD4 as RFC 1320 by R. Rivest, MIT Laboratory for
+ * Computer Science and RSA Data Security, Inc.
+ * <p>
+ * <b>NOTE</b>: This algorithm is only included for backwards compatability
+ * with legacy applications, it's not secure, don't use it for anything new!
+ * @hide This class is not part of the Android public SDK API
+ */
+public class MD4Digest
+        extends GeneralDigest
+{
+    private static final int    DIGEST_LENGTH = 16;
+
+    private int     H1, H2, H3, H4;         // IV's
+
+    private int[]   X = new int[16];
+    private int     xOff;
+
+    /**
+     * Standard constructor
+     */
+    public MD4Digest()
+    {
+        reset();
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public MD4Digest(MD4Digest t)
+    {
+        super(t);
+
+        copyIn(t);
+    }
+
+    private void copyIn(MD4Digest t)
+    {
+        super.copyIn(t);
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+    }
+
+    public String getAlgorithmName()
+    {
+        return "MD4";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    protected void processWord(
+            byte[]  in,
+            int     inOff)
+    {
+        X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8)
+                | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24);
+
+        if (xOff == 16)
+        {
+            processBlock();
+        }
+    }
+
+    protected void processLength(
+            long    bitLength)
+    {
+        if (xOff > 14)
+        {
+            processBlock();
+        }
+
+        X[14] = (int)(bitLength & 0xffffffff);
+        X[15] = (int)(bitLength >>> 32);
+    }
+
+    private void unpackWord(
+            int     word,
+            byte[]  out,
+            int     outOff)
+    {
+        out[outOff]     = (byte)word;
+        out[outOff + 1] = (byte)(word >>> 8);
+        out[outOff + 2] = (byte)(word >>> 16);
+        out[outOff + 3] = (byte)(word >>> 24);
+    }
+
+    public int doFinal(
+            byte[]  out,
+            int     outOff)
+    {
+        finish();
+
+        unpackWord(H1, out, outOff);
+        unpackWord(H2, out, outOff + 4);
+        unpackWord(H3, out, outOff + 8);
+        unpackWord(H4, out, outOff + 12);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables to the IV values.
+     */
+    public void reset()
+    {
+        super.reset();
+
+        H1 = 0x67452301;
+        H2 = 0xefcdab89;
+        H3 = 0x98badcfe;
+        H4 = 0x10325476;
+
+        xOff = 0;
+
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    //
+    // round 1 left rotates
+    //
+    private static final int S11 = 3;
+    private static final int S12 = 7;
+    private static final int S13 = 11;
+    private static final int S14 = 19;
+
+    //
+    // round 2 left rotates
+    //
+    private static final int S21 = 3;
+    private static final int S22 = 5;
+    private static final int S23 = 9;
+    private static final int S24 = 13;
+
+    //
+    // round 3 left rotates
+    //
+    private static final int S31 = 3;
+    private static final int S32 = 9;
+    private static final int S33 = 11;
+    private static final int S34 = 15;
+
+    /*
+     * rotate int x left n bits.
+     */
+    private int rotateLeft(
+            int x,
+            int n)
+    {
+        return (x << n) | (x >>> (32 - n));
+    }
+
+    /*
+     * F, G, H and I are the basic MD4 functions.
+     */
+    private int F(
+            int u,
+            int v,
+            int w)
+    {
+        return (u & v) | (~u & w);
+    }
+
+    private int G(
+            int u,
+            int v,
+            int w)
+    {
+        return (u & v) | (u & w) | (v & w);
+    }
+
+    private int H(
+            int u,
+            int v,
+            int w)
+    {
+        return u ^ v ^ w;
+    }
+
+    protected void processBlock()
+    {
+        int a = H1;
+        int b = H2;
+        int c = H3;
+        int d = H4;
+
+        //
+        // Round 1 - F cycle, 16 times.
+        //
+        a = rotateLeft(a + F(b, c, d) + X[ 0], S11);
+        d = rotateLeft(d + F(a, b, c) + X[ 1], S12);
+        c = rotateLeft(c + F(d, a, b) + X[ 2], S13);
+        b = rotateLeft(b + F(c, d, a) + X[ 3], S14);
+        a = rotateLeft(a + F(b, c, d) + X[ 4], S11);
+        d = rotateLeft(d + F(a, b, c) + X[ 5], S12);
+        c = rotateLeft(c + F(d, a, b) + X[ 6], S13);
+        b = rotateLeft(b + F(c, d, a) + X[ 7], S14);
+        a = rotateLeft(a + F(b, c, d) + X[ 8], S11);
+        d = rotateLeft(d + F(a, b, c) + X[ 9], S12);
+        c = rotateLeft(c + F(d, a, b) + X[10], S13);
+        b = rotateLeft(b + F(c, d, a) + X[11], S14);
+        a = rotateLeft(a + F(b, c, d) + X[12], S11);
+        d = rotateLeft(d + F(a, b, c) + X[13], S12);
+        c = rotateLeft(c + F(d, a, b) + X[14], S13);
+        b = rotateLeft(b + F(c, d, a) + X[15], S14);
+
+        //
+        // Round 2 - G cycle, 16 times.
+        //
+        a = rotateLeft(a + G(b, c, d) + X[ 0] + 0x5a827999, S21);
+        d = rotateLeft(d + G(a, b, c) + X[ 4] + 0x5a827999, S22);
+        c = rotateLeft(c + G(d, a, b) + X[ 8] + 0x5a827999, S23);
+        b = rotateLeft(b + G(c, d, a) + X[12] + 0x5a827999, S24);
+        a = rotateLeft(a + G(b, c, d) + X[ 1] + 0x5a827999, S21);
+        d = rotateLeft(d + G(a, b, c) + X[ 5] + 0x5a827999, S22);
+        c = rotateLeft(c + G(d, a, b) + X[ 9] + 0x5a827999, S23);
+        b = rotateLeft(b + G(c, d, a) + X[13] + 0x5a827999, S24);
+        a = rotateLeft(a + G(b, c, d) + X[ 2] + 0x5a827999, S21);
+        d = rotateLeft(d + G(a, b, c) + X[ 6] + 0x5a827999, S22);
+        c = rotateLeft(c + G(d, a, b) + X[10] + 0x5a827999, S23);
+        b = rotateLeft(b + G(c, d, a) + X[14] + 0x5a827999, S24);
+        a = rotateLeft(a + G(b, c, d) + X[ 3] + 0x5a827999, S21);
+        d = rotateLeft(d + G(a, b, c) + X[ 7] + 0x5a827999, S22);
+        c = rotateLeft(c + G(d, a, b) + X[11] + 0x5a827999, S23);
+        b = rotateLeft(b + G(c, d, a) + X[15] + 0x5a827999, S24);
+
+        //
+        // Round 3 - H cycle, 16 times.
+        //
+        a = rotateLeft(a + H(b, c, d) + X[ 0] + 0x6ed9eba1, S31);
+        d = rotateLeft(d + H(a, b, c) + X[ 8] + 0x6ed9eba1, S32);
+        c = rotateLeft(c + H(d, a, b) + X[ 4] + 0x6ed9eba1, S33);
+        b = rotateLeft(b + H(c, d, a) + X[12] + 0x6ed9eba1, S34);
+        a = rotateLeft(a + H(b, c, d) + X[ 2] + 0x6ed9eba1, S31);
+        d = rotateLeft(d + H(a, b, c) + X[10] + 0x6ed9eba1, S32);
+        c = rotateLeft(c + H(d, a, b) + X[ 6] + 0x6ed9eba1, S33);
+        b = rotateLeft(b + H(c, d, a) + X[14] + 0x6ed9eba1, S34);
+        a = rotateLeft(a + H(b, c, d) + X[ 1] + 0x6ed9eba1, S31);
+        d = rotateLeft(d + H(a, b, c) + X[ 9] + 0x6ed9eba1, S32);
+        c = rotateLeft(c + H(d, a, b) + X[ 5] + 0x6ed9eba1, S33);
+        b = rotateLeft(b + H(c, d, a) + X[13] + 0x6ed9eba1, S34);
+        a = rotateLeft(a + H(b, c, d) + X[ 3] + 0x6ed9eba1, S31);
+        d = rotateLeft(d + H(a, b, c) + X[11] + 0x6ed9eba1, S32);
+        c = rotateLeft(c + H(d, a, b) + X[ 7] + 0x6ed9eba1, S33);
+        b = rotateLeft(b + H(c, d, a) + X[15] + 0x6ed9eba1, S34);
+
+        H1 += a;
+        H2 += b;
+        H3 += c;
+        H4 += d;
+
+        //
+        // reset the offset and clean out the word buffer.
+        //
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    public Memoable copy()
+    {
+        return new MD4Digest(this);
+    }
+
+    public void reset(Memoable other)
+    {
+        MD4Digest d = (MD4Digest)other;
+
+        copyIn(d);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/MD5Digest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/MD5Digest.java
new file mode 100644
index 0000000..ba66202
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/MD5Digest.java
@@ -0,0 +1,363 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+
+import com.android.internal.org.bouncycastle.util.Memoable;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class MD5Digest
+    extends GeneralDigest
+    implements EncodableDigest
+{
+    private static final int    DIGEST_LENGTH = 16;
+
+    private int     H1, H2, H3, H4;         // IV's
+
+    private int[]   X = new int[16];
+    private int     xOff;
+
+    /**
+     * Standard constructor
+     */
+    public MD5Digest()
+    {
+        reset();
+    }
+
+    public MD5Digest(byte[] encodedState)
+    {
+        super(encodedState);
+
+        H1 = Pack.bigEndianToInt(encodedState, 16);
+        H2 = Pack.bigEndianToInt(encodedState, 20);
+        H3 = Pack.bigEndianToInt(encodedState, 24);
+        H4 = Pack.bigEndianToInt(encodedState, 28);
+
+        xOff = Pack.bigEndianToInt(encodedState, 32);
+        for (int i = 0; i != xOff; i++)
+        {
+            X[i] = Pack.bigEndianToInt(encodedState, 36 + (i * 4));
+        }
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public MD5Digest(MD5Digest t)
+    {
+        super(t);
+
+        copyIn(t);
+    }
+
+    private void copyIn(MD5Digest t)
+    {
+        super.copyIn(t);
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+    }
+
+    public String getAlgorithmName()
+    {
+        return "MD5";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8)
+            | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); 
+
+        if (xOff == 16)
+        {
+            processBlock();
+        }
+    }
+
+    protected void processLength(
+        long    bitLength)
+    {
+        if (xOff > 14)
+        {
+            processBlock();
+        }
+
+        X[14] = (int)(bitLength & 0xffffffff);
+        X[15] = (int)(bitLength >>> 32);
+    }
+
+    private void unpackWord(
+        int     word,
+        byte[]  out,
+        int     outOff)
+    {
+        out[outOff]     = (byte)word;
+        out[outOff + 1] = (byte)(word >>> 8);
+        out[outOff + 2] = (byte)(word >>> 16);
+        out[outOff + 3] = (byte)(word >>> 24);
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        unpackWord(H1, out, outOff);
+        unpackWord(H2, out, outOff + 4);
+        unpackWord(H3, out, outOff + 8);
+        unpackWord(H4, out, outOff + 12);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables to the IV values.
+     */
+    public void reset()
+    {
+        super.reset();
+
+        H1 = 0x67452301;
+        H2 = 0xefcdab89;
+        H3 = 0x98badcfe;
+        H4 = 0x10325476;
+
+        xOff = 0;
+
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    //
+    // round 1 left rotates
+    //
+    private static final int S11 = 7;
+    private static final int S12 = 12;
+    private static final int S13 = 17;
+    private static final int S14 = 22;
+
+    //
+    // round 2 left rotates
+    //
+    private static final int S21 = 5;
+    private static final int S22 = 9;
+    private static final int S23 = 14;
+    private static final int S24 = 20;
+
+    //
+    // round 3 left rotates
+    //
+    private static final int S31 = 4;
+    private static final int S32 = 11;
+    private static final int S33 = 16;
+    private static final int S34 = 23;
+
+    //
+    // round 4 left rotates
+    //
+    private static final int S41 = 6;
+    private static final int S42 = 10;
+    private static final int S43 = 15;
+    private static final int S44 = 21;
+
+    /*
+     * rotate int x left n bits.
+     */
+    private int rotateLeft(
+        int x,
+        int n)
+    {
+        return (x << n) | (x >>> (32 - n));
+    }
+
+    /*
+     * F, G, H and I are the basic MD5 functions.
+     */
+    private int F(
+        int u,
+        int v,
+        int w)
+    {
+        return (u & v) | (~u & w);
+    }
+
+    private int G(
+        int u,
+        int v,
+        int w)
+    {
+        return (u & w) | (v & ~w);
+    }
+
+    private int H(
+        int u,
+        int v,
+        int w)
+    {
+        return u ^ v ^ w;
+    }
+
+    private int K(
+        int u,
+        int v,
+        int w)
+    {
+        return v ^ (u | ~w);
+    }
+
+    protected void processBlock()
+    {
+        int a = H1;
+        int b = H2;
+        int c = H3;
+        int d = H4;
+
+        //
+        // Round 1 - F cycle, 16 times.
+        //
+        a = rotateLeft(a + F(b, c, d) + X[ 0] + 0xd76aa478, S11) + b;
+        d = rotateLeft(d + F(a, b, c) + X[ 1] + 0xe8c7b756, S12) + a;
+        c = rotateLeft(c + F(d, a, b) + X[ 2] + 0x242070db, S13) + d;
+        b = rotateLeft(b + F(c, d, a) + X[ 3] + 0xc1bdceee, S14) + c;
+        a = rotateLeft(a + F(b, c, d) + X[ 4] + 0xf57c0faf, S11) + b;
+        d = rotateLeft(d + F(a, b, c) + X[ 5] + 0x4787c62a, S12) + a;
+        c = rotateLeft(c + F(d, a, b) + X[ 6] + 0xa8304613, S13) + d;
+        b = rotateLeft(b + F(c, d, a) + X[ 7] + 0xfd469501, S14) + c;
+        a = rotateLeft(a + F(b, c, d) + X[ 8] + 0x698098d8, S11) + b;
+        d = rotateLeft(d + F(a, b, c) + X[ 9] + 0x8b44f7af, S12) + a;
+        c = rotateLeft(c + F(d, a, b) + X[10] + 0xffff5bb1, S13) + d;
+        b = rotateLeft(b + F(c, d, a) + X[11] + 0x895cd7be, S14) + c;
+        a = rotateLeft(a + F(b, c, d) + X[12] + 0x6b901122, S11) + b;
+        d = rotateLeft(d + F(a, b, c) + X[13] + 0xfd987193, S12) + a;
+        c = rotateLeft(c + F(d, a, b) + X[14] + 0xa679438e, S13) + d;
+        b = rotateLeft(b + F(c, d, a) + X[15] + 0x49b40821, S14) + c;
+
+        //
+        // Round 2 - G cycle, 16 times.
+        //
+        a = rotateLeft(a + G(b, c, d) + X[ 1] + 0xf61e2562, S21) + b;
+        d = rotateLeft(d + G(a, b, c) + X[ 6] + 0xc040b340, S22) + a;
+        c = rotateLeft(c + G(d, a, b) + X[11] + 0x265e5a51, S23) + d;
+        b = rotateLeft(b + G(c, d, a) + X[ 0] + 0xe9b6c7aa, S24) + c;
+        a = rotateLeft(a + G(b, c, d) + X[ 5] + 0xd62f105d, S21) + b;
+        d = rotateLeft(d + G(a, b, c) + X[10] + 0x02441453, S22) + a;
+        c = rotateLeft(c + G(d, a, b) + X[15] + 0xd8a1e681, S23) + d;
+        b = rotateLeft(b + G(c, d, a) + X[ 4] + 0xe7d3fbc8, S24) + c;
+        a = rotateLeft(a + G(b, c, d) + X[ 9] + 0x21e1cde6, S21) + b;
+        d = rotateLeft(d + G(a, b, c) + X[14] + 0xc33707d6, S22) + a;
+        c = rotateLeft(c + G(d, a, b) + X[ 3] + 0xf4d50d87, S23) + d;
+        b = rotateLeft(b + G(c, d, a) + X[ 8] + 0x455a14ed, S24) + c;
+        a = rotateLeft(a + G(b, c, d) + X[13] + 0xa9e3e905, S21) + b;
+        d = rotateLeft(d + G(a, b, c) + X[ 2] + 0xfcefa3f8, S22) + a;
+        c = rotateLeft(c + G(d, a, b) + X[ 7] + 0x676f02d9, S23) + d;
+        b = rotateLeft(b + G(c, d, a) + X[12] + 0x8d2a4c8a, S24) + c;
+
+        //
+        // Round 3 - H cycle, 16 times.
+        //
+        a = rotateLeft(a + H(b, c, d) + X[ 5] + 0xfffa3942, S31) + b;
+        d = rotateLeft(d + H(a, b, c) + X[ 8] + 0x8771f681, S32) + a;
+        c = rotateLeft(c + H(d, a, b) + X[11] + 0x6d9d6122, S33) + d;
+        b = rotateLeft(b + H(c, d, a) + X[14] + 0xfde5380c, S34) + c;
+        a = rotateLeft(a + H(b, c, d) + X[ 1] + 0xa4beea44, S31) + b;
+        d = rotateLeft(d + H(a, b, c) + X[ 4] + 0x4bdecfa9, S32) + a;
+        c = rotateLeft(c + H(d, a, b) + X[ 7] + 0xf6bb4b60, S33) + d;
+        b = rotateLeft(b + H(c, d, a) + X[10] + 0xbebfbc70, S34) + c;
+        a = rotateLeft(a + H(b, c, d) + X[13] + 0x289b7ec6, S31) + b;
+        d = rotateLeft(d + H(a, b, c) + X[ 0] + 0xeaa127fa, S32) + a;
+        c = rotateLeft(c + H(d, a, b) + X[ 3] + 0xd4ef3085, S33) + d;
+        b = rotateLeft(b + H(c, d, a) + X[ 6] + 0x04881d05, S34) + c;
+        a = rotateLeft(a + H(b, c, d) + X[ 9] + 0xd9d4d039, S31) + b;
+        d = rotateLeft(d + H(a, b, c) + X[12] + 0xe6db99e5, S32) + a;
+        c = rotateLeft(c + H(d, a, b) + X[15] + 0x1fa27cf8, S33) + d;
+        b = rotateLeft(b + H(c, d, a) + X[ 2] + 0xc4ac5665, S34) + c;
+
+        //
+        // Round 4 - K cycle, 16 times.
+        //
+        a = rotateLeft(a + K(b, c, d) + X[ 0] + 0xf4292244, S41) + b;
+        d = rotateLeft(d + K(a, b, c) + X[ 7] + 0x432aff97, S42) + a;
+        c = rotateLeft(c + K(d, a, b) + X[14] + 0xab9423a7, S43) + d;
+        b = rotateLeft(b + K(c, d, a) + X[ 5] + 0xfc93a039, S44) + c;
+        a = rotateLeft(a + K(b, c, d) + X[12] + 0x655b59c3, S41) + b;
+        d = rotateLeft(d + K(a, b, c) + X[ 3] + 0x8f0ccc92, S42) + a;
+        c = rotateLeft(c + K(d, a, b) + X[10] + 0xffeff47d, S43) + d;
+        b = rotateLeft(b + K(c, d, a) + X[ 1] + 0x85845dd1, S44) + c;
+        a = rotateLeft(a + K(b, c, d) + X[ 8] + 0x6fa87e4f, S41) + b;
+        d = rotateLeft(d + K(a, b, c) + X[15] + 0xfe2ce6e0, S42) + a;
+        c = rotateLeft(c + K(d, a, b) + X[ 6] + 0xa3014314, S43) + d;
+        b = rotateLeft(b + K(c, d, a) + X[13] + 0x4e0811a1, S44) + c;
+        a = rotateLeft(a + K(b, c, d) + X[ 4] + 0xf7537e82, S41) + b;
+        d = rotateLeft(d + K(a, b, c) + X[11] + 0xbd3af235, S42) + a;
+        c = rotateLeft(c + K(d, a, b) + X[ 2] + 0x2ad7d2bb, S43) + d;
+        b = rotateLeft(b + K(c, d, a) + X[ 9] + 0xeb86d391, S44) + c;
+
+        H1 += a;
+        H2 += b;
+        H3 += c;
+        H4 += d;
+
+        //
+        // reset the offset and clean out the word buffer.
+        //
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    public Memoable copy()
+    {
+        return new MD5Digest(this);
+    }
+
+    public void reset(Memoable other)
+    {
+        MD5Digest d = (MD5Digest)other;
+
+        copyIn(d);
+    }
+
+    public byte[] getEncodedState()
+    {
+        byte[] state = new byte[36 + xOff * 4];
+
+        super.populateState(state);
+
+        Pack.intToBigEndian(H1, state, 16);
+        Pack.intToBigEndian(H2, state, 20);
+        Pack.intToBigEndian(H3, state, 24);
+        Pack.intToBigEndian(H4, state, 28);
+        Pack.intToBigEndian(xOff, state, 32);
+
+        for (int i = 0; i != xOff; i++)
+        {
+            Pack.intToBigEndian(X[i], state, 36 + (i * 4));
+        }
+
+        return state;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/NullDigest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/NullDigest.java
new file mode 100644
index 0000000..5447a04
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/NullDigest.java
@@ -0,0 +1,69 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+import java.io.ByteArrayOutputStream;
+
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class NullDigest
+    implements Digest
+{
+    private OpenByteArrayOutputStream bOut = new OpenByteArrayOutputStream();
+
+    public String getAlgorithmName()
+    {
+        return "NULL";
+    }
+
+    public int getDigestSize()
+    {
+        return bOut.size();
+    }
+
+    public void update(byte in)
+    {
+        bOut.write(in);
+    }
+
+    public void update(byte[] in, int inOff, int len)
+    {
+        bOut.write(in, inOff, len);
+    }
+
+    public int doFinal(byte[] out, int outOff)
+    {
+        int size = bOut.size();
+
+        bOut.copy(out, outOff);
+
+        reset();
+        
+        return size;
+    }
+
+    public void reset()
+    {
+        bOut.reset();
+    }
+
+    private static class OpenByteArrayOutputStream
+        extends ByteArrayOutputStream
+    {
+        public void reset()
+        {
+            super.reset();
+
+            Arrays.clear(buf);
+        }
+
+        void copy(byte[] out, int outOff)
+        {
+            System.arraycopy(buf, 0, out, outOff, this.size());
+        }
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/OpenSSLDigest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/OpenSSLDigest.java
new file mode 100644
index 0000000..fe2ff80
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/OpenSSLDigest.java
@@ -0,0 +1,117 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+import com.android.internal.org.bouncycastle.crypto.ExtendedDigest;
+import com.android.internal.org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi;
+import java.security.DigestException;
+import java.security.MessageDigest;
+
+/**
+ * Implements the BouncyCastle Digest interface using OpenSSL's EVP API. This
+ * must be an ExtendedDigest for {@link BcKeyStoreSpi} to be able to use it.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OpenSSLDigest implements ExtendedDigest {
+    private final MessageDigest delegate;
+
+    private final int byteSize;
+
+    public OpenSSLDigest(String algorithm, int byteSize) {
+        try {
+            delegate = MessageDigest.getInstance(algorithm, "AndroidOpenSSL");
+            this.byteSize = byteSize;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public String getAlgorithmName() {
+        return delegate.getAlgorithm();
+    }
+
+    public int getDigestSize() {
+        return delegate.getDigestLength();
+    }
+
+    public int getByteLength() {
+        return byteSize;
+    }
+
+    public void reset() {
+        delegate.reset();
+    }
+
+    public void update(byte in) {
+        delegate.update(in);
+    }
+
+    public void update(byte[] in, int inOff, int len) {
+        delegate.update(in, inOff, len);
+    }
+
+    public int doFinal(byte[] out, int outOff) {
+        try {
+            return delegate.digest(out, outOff, out.length - outOff);
+        } catch (DigestException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class MD5 extends OpenSSLDigest {
+        public MD5() { super("MD5", 64); }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class SHA1 extends OpenSSLDigest {
+        public SHA1() { super("SHA-1", 64); }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class SHA224 extends OpenSSLDigest {
+        public SHA224() { super("SHA-224", 64); }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class SHA256 extends OpenSSLDigest {
+        public SHA256() { super("SHA-256", 64); }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class SHA384 extends OpenSSLDigest {
+        public SHA384() { super("SHA-384", 128); }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class SHA512 extends OpenSSLDigest {
+        public SHA512() { super("SHA-512", 128); }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA1Digest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA1Digest.java
new file mode 100644
index 0000000..12f82e5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA1Digest.java
@@ -0,0 +1,355 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+import com.android.internal.org.bouncycastle.util.Memoable;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
+ *
+ * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
+ * is the "endianness" of the word processing!
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SHA1Digest
+    extends GeneralDigest
+    implements EncodableDigest
+{
+    private static final int    DIGEST_LENGTH = 20;
+
+    private int     H1, H2, H3, H4, H5;
+
+    private int[]   X = new int[80];
+    private int     xOff;
+
+    /**
+     * Standard constructor
+     */
+    public SHA1Digest()
+    {
+        reset();
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public SHA1Digest(SHA1Digest t)
+    {
+        super(t);
+
+        copyIn(t);
+    }
+
+    /**
+     * State constructor - create a digest initialised with the state of a previous one.
+     *
+     * @param encodedState the encoded state from the originating digest.
+     */
+    public SHA1Digest(byte[] encodedState)
+    {
+        super(encodedState);
+
+        H1 = Pack.bigEndianToInt(encodedState, 16);
+        H2 = Pack.bigEndianToInt(encodedState, 20);
+        H3 = Pack.bigEndianToInt(encodedState, 24);
+        H4 = Pack.bigEndianToInt(encodedState, 28);
+        H5 = Pack.bigEndianToInt(encodedState, 32);
+
+        xOff = Pack.bigEndianToInt(encodedState, 36);
+        for (int i = 0; i != xOff; i++)
+        {
+            X[i] = Pack.bigEndianToInt(encodedState, 40 + (i * 4));
+        }
+    }
+
+    private void copyIn(SHA1Digest t)
+    {
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+        H5 = t.H5;
+
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+    }
+
+    public String getAlgorithmName()
+    {
+        return "SHA-1";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        // Note: Inlined for performance
+//        X[xOff] = Pack.bigEndianToInt(in, inOff);
+        int n = in[  inOff] << 24;
+        n |= (in[++inOff] & 0xff) << 16;
+        n |= (in[++inOff] & 0xff) << 8;
+        n |= (in[++inOff] & 0xff);
+        X[xOff] = n;
+
+        if (++xOff == 16)
+        {
+            processBlock();
+        }        
+    }
+
+    protected void processLength(
+        long    bitLength)
+    {
+        if (xOff > 14)
+        {
+            processBlock();
+        }
+
+        X[14] = (int)(bitLength >>> 32);
+        X[15] = (int)bitLength;
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        Pack.intToBigEndian(H1, out, outOff);
+        Pack.intToBigEndian(H2, out, outOff + 4);
+        Pack.intToBigEndian(H3, out, outOff + 8);
+        Pack.intToBigEndian(H4, out, outOff + 12);
+        Pack.intToBigEndian(H5, out, outOff + 16);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables
+     */
+    public void reset()
+    {
+        super.reset();
+
+        H1 = 0x67452301;
+        H2 = 0xefcdab89;
+        H3 = 0x98badcfe;
+        H4 = 0x10325476;
+        H5 = 0xc3d2e1f0;
+
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    //
+    // Additive constants
+    //
+    private static final int    Y1 = 0x5a827999;
+    private static final int    Y2 = 0x6ed9eba1;
+    private static final int    Y3 = 0x8f1bbcdc;
+    private static final int    Y4 = 0xca62c1d6;
+   
+    private int f(
+        int    u,
+        int    v,
+        int    w)
+    {
+        return ((u & v) | ((~u) & w));
+    }
+
+    private int h(
+        int    u,
+        int    v,
+        int    w)
+    {
+        return (u ^ v ^ w);
+    }
+
+    private int g(
+        int    u,
+        int    v,
+        int    w)
+    {
+        return ((u & v) | (u & w) | (v & w));
+    }
+
+    protected void processBlock()
+    {
+        //
+        // expand 16 word block into 80 word block.
+        //
+        for (int i = 16; i < 80; i++)
+        {
+            int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
+            X[i] = t << 1 | t >>> 31;
+        }
+
+        //
+        // set up working variables.
+        //
+        int     A = H1;
+        int     B = H2;
+        int     C = H3;
+        int     D = H4;
+        int     E = H5;
+
+        //
+        // round 1
+        //
+        int idx = 0;
+        
+        for (int j = 0; j < 4; j++)
+        {
+            // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1
+            // B = rotateLeft(B, 30)
+            E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1;
+            B = B << 30 | B >>> 2;
+        
+            D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1;
+            A = A << 30 | A >>> 2;
+       
+            C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1;
+            E = E << 30 | E >>> 2;
+       
+            B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1;
+            D = D << 30 | D >>> 2;
+
+            A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1;
+            C = C << 30 | C >>> 2;
+        }
+        
+        //
+        // round 2
+        //
+        for (int j = 0; j < 4; j++)
+        {
+            // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2
+            // B = rotateLeft(B, 30)
+            E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2;
+            B = B << 30 | B >>> 2;   
+            
+            D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2;
+            A = A << 30 | A >>> 2;
+            
+            C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2;
+            E = E << 30 | E >>> 2;
+            
+            B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2;
+            D = D << 30 | D >>> 2;
+
+            A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2;
+            C = C << 30 | C >>> 2;
+        }
+        
+        //
+        // round 3
+        //
+        for (int j = 0; j < 4; j++)
+        {
+            // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3
+            // B = rotateLeft(B, 30)
+            E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3;
+            B = B << 30 | B >>> 2;
+            
+            D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3;
+            A = A << 30 | A >>> 2;
+            
+            C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3;
+            E = E << 30 | E >>> 2;
+            
+            B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3;
+            D = D << 30 | D >>> 2;
+
+            A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3;
+            C = C << 30 | C >>> 2;
+        }
+
+        //
+        // round 4
+        //
+        for (int j = 0; j <= 3; j++)
+        {
+            // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4
+            // B = rotateLeft(B, 30)
+            E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4;
+            B = B << 30 | B >>> 2;
+            
+            D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4;
+            A = A << 30 | A >>> 2;
+            
+            C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4;
+            E = E << 30 | E >>> 2;
+            
+            B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4;
+            D = D << 30 | D >>> 2;
+
+            A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4;
+            C = C << 30 | C >>> 2;
+        }
+
+
+        H1 += A;
+        H2 += B;
+        H3 += C;
+        H4 += D;
+        H5 += E;
+
+        //
+        // reset start of the buffer.
+        //
+        xOff = 0;
+        for (int i = 0; i < 16; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    public Memoable copy()
+    {
+        return new SHA1Digest(this);
+    }
+
+    public void reset(Memoable other)
+    {
+        SHA1Digest d = (SHA1Digest)other;
+
+        super.copyIn(d);
+        copyIn(d);
+    }
+
+    public byte[] getEncodedState()
+    {
+        byte[] state = new byte[40 + xOff * 4];
+
+        super.populateState(state);
+
+        Pack.intToBigEndian(H1, state, 16);
+        Pack.intToBigEndian(H2, state, 20);
+        Pack.intToBigEndian(H3, state, 24);
+        Pack.intToBigEndian(H4, state, 28);
+        Pack.intToBigEndian(H5, state, 32);
+        Pack.intToBigEndian(xOff, state, 36);
+
+        for (int i = 0; i != xOff; i++)
+        {
+            Pack.intToBigEndian(X[i], state, 40 + (i * 4));
+        }
+
+        return state;
+    }
+}
+
+
+
+
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA224Digest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA224Digest.java
new file mode 100644
index 0000000..8c3f9a4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA224Digest.java
@@ -0,0 +1,363 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+
+import com.android.internal.org.bouncycastle.util.Memoable;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+
+/**
+ * SHA-224 as described in RFC 3874
+ * <pre>
+ *         block  word  digest
+ * SHA-1   512    32    160
+ * SHA-224 512    32    224
+ * SHA-256 512    32    256
+ * SHA-384 1024   64    384
+ * SHA-512 1024   64    512
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SHA224Digest
+    extends GeneralDigest
+    implements EncodableDigest
+{
+    private static final int    DIGEST_LENGTH = 28;
+
+    private int     H1, H2, H3, H4, H5, H6, H7, H8;
+
+    private int[]   X = new int[64];
+    private int     xOff;
+
+    /**
+     * Standard constructor
+     */
+    public SHA224Digest()
+    {
+        reset();
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public SHA224Digest(SHA224Digest t)
+    {
+        super(t);
+
+        doCopy(t);
+    }
+
+    private void doCopy(SHA224Digest t)
+    {
+        super.copyIn(t);
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+        H5 = t.H5;
+        H6 = t.H6;
+        H7 = t.H7;
+        H8 = t.H8;
+
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+    }
+
+    /**
+     * State constructor - create a digest initialised with the state of a previous one.
+     *
+     * @param encodedState the encoded state from the originating digest.
+     */
+    public SHA224Digest(byte[] encodedState)
+    {
+        super(encodedState);
+
+        H1 = Pack.bigEndianToInt(encodedState, 16);
+        H2 = Pack.bigEndianToInt(encodedState, 20);
+        H3 = Pack.bigEndianToInt(encodedState, 24);
+        H4 = Pack.bigEndianToInt(encodedState, 28);
+        H5 = Pack.bigEndianToInt(encodedState, 32);
+        H6 = Pack.bigEndianToInt(encodedState, 36);
+        H7 = Pack.bigEndianToInt(encodedState, 40);
+        H8 = Pack.bigEndianToInt(encodedState, 44);
+
+        xOff = Pack.bigEndianToInt(encodedState, 48);
+        for (int i = 0; i != xOff; i++)
+        {
+            X[i] = Pack.bigEndianToInt(encodedState, 52 + (i * 4));
+        }
+    }
+
+    public String getAlgorithmName()
+    {
+        return "SHA-224";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        // Note: Inlined for performance
+//        X[xOff] = Pack.bigEndianToInt(in, inOff);
+        int n = in[  inOff] << 24;
+        n |= (in[++inOff] & 0xff) << 16;
+        n |= (in[++inOff] & 0xff) << 8;
+        n |= (in[++inOff] & 0xff);
+        X[xOff] = n;
+
+        if (++xOff == 16)
+        {
+            processBlock();
+        }
+    }
+
+    protected void processLength(
+        long    bitLength)
+    {
+        if (xOff > 14)
+        {
+            processBlock();
+        }
+
+        X[14] = (int)(bitLength >>> 32);
+        X[15] = (int)(bitLength & 0xffffffff);
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        Pack.intToBigEndian(H1, out, outOff);
+        Pack.intToBigEndian(H2, out, outOff + 4);
+        Pack.intToBigEndian(H3, out, outOff + 8);
+        Pack.intToBigEndian(H4, out, outOff + 12);
+        Pack.intToBigEndian(H5, out, outOff + 16);
+        Pack.intToBigEndian(H6, out, outOff + 20);
+        Pack.intToBigEndian(H7, out, outOff + 24);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables
+     */
+    public void reset()
+    {
+        super.reset();
+
+        /* SHA-224 initial hash value
+         */
+
+        H1 = 0xc1059ed8;
+        H2 = 0x367cd507;
+        H3 = 0x3070dd17;
+        H4 = 0xf70e5939;
+        H5 = 0xffc00b31;
+        H6 = 0x68581511;
+        H7 = 0x64f98fa7;
+        H8 = 0xbefa4fa4;
+
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    protected void processBlock()
+    {
+        //
+        // expand 16 word block into 64 word blocks.
+        //
+        for (int t = 16; t <= 63; t++)
+        {
+            X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16];
+        }
+
+        //
+        // set up working variables.
+        //
+        int     a = H1;
+        int     b = H2;
+        int     c = H3;
+        int     d = H4;
+        int     e = H5;
+        int     f = H6;
+        int     g = H7;
+        int     h = H8;
+
+
+        int t = 0;     
+        for(int i = 0; i < 8; i ++)
+        {
+            // t = 8 * i
+            h += Sum1(e) + Ch(e, f, g) + K[t] + X[t];
+            d += h;
+            h += Sum0(a) + Maj(a, b, c);
+            ++t;
+
+            // t = 8 * i + 1
+            g += Sum1(d) + Ch(d, e, f) + K[t] + X[t];
+            c += g;
+            g += Sum0(h) + Maj(h, a, b);
+            ++t;
+
+            // t = 8 * i + 2
+            f += Sum1(c) + Ch(c, d, e) + K[t] + X[t];
+            b += f;
+            f += Sum0(g) + Maj(g, h, a);
+            ++t;
+
+            // t = 8 * i + 3
+            e += Sum1(b) + Ch(b, c, d) + K[t] + X[t];
+            a += e;
+            e += Sum0(f) + Maj(f, g, h);
+            ++t;
+
+            // t = 8 * i + 4
+            d += Sum1(a) + Ch(a, b, c) + K[t] + X[t];
+            h += d;
+            d += Sum0(e) + Maj(e, f, g);
+            ++t;
+
+            // t = 8 * i + 5
+            c += Sum1(h) + Ch(h, a, b) + K[t] + X[t];
+            g += c;
+            c += Sum0(d) + Maj(d, e, f);
+            ++t;
+
+            // t = 8 * i + 6
+            b += Sum1(g) + Ch(g, h, a) + K[t] + X[t];
+            f += b;
+            b += Sum0(c) + Maj(c, d, e);
+            ++t;
+
+            // t = 8 * i + 7
+            a += Sum1(f) + Ch(f, g, h) + K[t] + X[t];
+            e += a;
+            a += Sum0(b) + Maj(b, c, d);
+            ++t;
+        }
+
+        H1 += a;
+        H2 += b;
+        H3 += c;
+        H4 += d;
+        H5 += e;
+        H6 += f;
+        H7 += g;
+        H8 += h;
+
+        //
+        // reset the offset and clean out the word buffer.
+        //
+        xOff = 0;
+        for (int i = 0; i < 16; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    /* SHA-224 functions */
+    private int Ch(
+        int    x,
+        int    y,
+        int    z)
+    {
+        return ((x & y) ^ ((~x) & z));
+    }
+
+    private int Maj(
+        int    x,
+        int    y,
+        int    z)
+    {
+        return ((x & y) ^ (x & z) ^ (y & z));
+    }
+
+    private int Sum0(
+        int    x)
+    {
+        return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10));
+    }
+
+    private int Sum1(
+        int    x)
+    {
+        return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7));
+    }
+
+    private int Theta0(
+        int    x)
+    {
+        return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
+    }
+
+    private int Theta1(
+        int    x)
+    {
+        return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10);
+    }
+
+    /* SHA-224 Constants
+     * (represent the first 32 bits of the fractional parts of the
+     * cube roots of the first sixty-four prime numbers)
+     */
+    static final int K[] = {
+        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+    };
+
+    public Memoable copy()
+    {
+        return new SHA224Digest(this);
+    }
+
+    public void reset(Memoable other)
+    {
+        SHA224Digest d = (SHA224Digest)other;
+
+        doCopy(d);
+    }
+
+    public byte[] getEncodedState()
+    {
+        byte[] state = new byte[52 + xOff * 4];
+
+        super.populateState(state);
+
+        Pack.intToBigEndian(H1, state, 16);
+        Pack.intToBigEndian(H2, state, 20);
+        Pack.intToBigEndian(H3, state, 24);
+        Pack.intToBigEndian(H4, state, 28);
+        Pack.intToBigEndian(H5, state, 32);
+        Pack.intToBigEndian(H6, state, 36);
+        Pack.intToBigEndian(H7, state, 40);
+        Pack.intToBigEndian(H8, state, 44);
+        Pack.intToBigEndian(xOff, state, 48);
+
+        for (int i = 0; i != xOff; i++)
+        {
+            Pack.intToBigEndian(X[i], state, 52 + (i * 4));
+        }
+
+        return state;
+    }
+}
+
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA256Digest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA256Digest.java
new file mode 100644
index 0000000..a1e395e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA256Digest.java
@@ -0,0 +1,367 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+
+import com.android.internal.org.bouncycastle.util.Memoable;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+
+/**
+ * FIPS 180-2 implementation of SHA-256.
+ *
+ * <pre>
+ *         block  word  digest
+ * SHA-1   512    32    160
+ * SHA-256 512    32    256
+ * SHA-384 1024   64    384
+ * SHA-512 1024   64    512
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SHA256Digest
+    extends GeneralDigest
+    implements EncodableDigest
+{
+    private static final int    DIGEST_LENGTH = 32;
+
+    private int     H1, H2, H3, H4, H5, H6, H7, H8;
+
+    private int[]   X = new int[64];
+    private int     xOff;
+
+    /**
+     * Standard constructor
+     */
+    public SHA256Digest()
+    {
+        reset();
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public SHA256Digest(SHA256Digest t)
+    {
+        super(t);
+
+        copyIn(t);
+    }
+
+    private void copyIn(SHA256Digest t)
+    {
+        super.copyIn(t);
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+        H5 = t.H5;
+        H6 = t.H6;
+        H7 = t.H7;
+        H8 = t.H8;
+
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+    }
+
+    /**
+     * State constructor - create a digest initialised with the state of a previous one.
+     *
+     * @param encodedState the encoded state from the originating digest.
+     */
+    public SHA256Digest(byte[] encodedState)
+    {
+        super(encodedState);
+
+        H1 = Pack.bigEndianToInt(encodedState, 16);
+        H2 = Pack.bigEndianToInt(encodedState, 20);
+        H3 = Pack.bigEndianToInt(encodedState, 24);
+        H4 = Pack.bigEndianToInt(encodedState, 28);
+        H5 = Pack.bigEndianToInt(encodedState, 32);
+        H6 = Pack.bigEndianToInt(encodedState, 36);
+        H7 = Pack.bigEndianToInt(encodedState, 40);
+        H8 = Pack.bigEndianToInt(encodedState, 44);
+
+        xOff = Pack.bigEndianToInt(encodedState, 48);
+        for (int i = 0; i != xOff; i++)
+        {
+            X[i] = Pack.bigEndianToInt(encodedState, 52 + (i * 4));
+        }
+    }
+
+
+    public String getAlgorithmName()
+    {
+        return "SHA-256";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        // Note: Inlined for performance
+//        X[xOff] = Pack.bigEndianToInt(in, inOff);
+        int n = in[inOff] << 24;
+        n |= (in[++inOff] & 0xff) << 16;
+        n |= (in[++inOff] & 0xff) << 8;
+        n |= (in[++inOff] & 0xff);
+        X[xOff] = n;
+
+        if (++xOff == 16)
+        {
+            processBlock();
+        }
+    }
+
+    protected void processLength(
+        long    bitLength)
+    {
+        if (xOff > 14)
+        {
+            processBlock();
+        }
+
+        X[14] = (int)(bitLength >>> 32);
+        X[15] = (int)(bitLength & 0xffffffff);
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        Pack.intToBigEndian(H1, out, outOff);
+        Pack.intToBigEndian(H2, out, outOff + 4);
+        Pack.intToBigEndian(H3, out, outOff + 8);
+        Pack.intToBigEndian(H4, out, outOff + 12);
+        Pack.intToBigEndian(H5, out, outOff + 16);
+        Pack.intToBigEndian(H6, out, outOff + 20);
+        Pack.intToBigEndian(H7, out, outOff + 24);
+        Pack.intToBigEndian(H8, out, outOff + 28);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables
+     */
+    public void reset()
+    {
+        super.reset();
+
+        /* SHA-256 initial hash value
+         * The first 32 bits of the fractional parts of the square roots
+         * of the first eight prime numbers
+         */
+
+        H1 = 0x6a09e667;
+        H2 = 0xbb67ae85;
+        H3 = 0x3c6ef372;
+        H4 = 0xa54ff53a;
+        H5 = 0x510e527f;
+        H6 = 0x9b05688c;
+        H7 = 0x1f83d9ab;
+        H8 = 0x5be0cd19;
+
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    protected void processBlock()
+    {
+        //
+        // expand 16 word block into 64 word blocks.
+        //
+        for (int t = 16; t <= 63; t++)
+        {
+            X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16];
+        }
+
+        //
+        // set up working variables.
+        //
+        int     a = H1;
+        int     b = H2;
+        int     c = H3;
+        int     d = H4;
+        int     e = H5;
+        int     f = H6;
+        int     g = H7;
+        int     h = H8;
+
+        int t = 0;     
+        for(int i = 0; i < 8; i ++)
+        {
+            // t = 8 * i
+            h += Sum1(e) + Ch(e, f, g) + K[t] + X[t];
+            d += h;
+            h += Sum0(a) + Maj(a, b, c);
+            ++t;
+
+            // t = 8 * i + 1
+            g += Sum1(d) + Ch(d, e, f) + K[t] + X[t];
+            c += g;
+            g += Sum0(h) + Maj(h, a, b);
+            ++t;
+
+            // t = 8 * i + 2
+            f += Sum1(c) + Ch(c, d, e) + K[t] + X[t];
+            b += f;
+            f += Sum0(g) + Maj(g, h, a);
+            ++t;
+
+            // t = 8 * i + 3
+            e += Sum1(b) + Ch(b, c, d) + K[t] + X[t];
+            a += e;
+            e += Sum0(f) + Maj(f, g, h);
+            ++t;
+
+            // t = 8 * i + 4
+            d += Sum1(a) + Ch(a, b, c) + K[t] + X[t];
+            h += d;
+            d += Sum0(e) + Maj(e, f, g);
+            ++t;
+
+            // t = 8 * i + 5
+            c += Sum1(h) + Ch(h, a, b) + K[t] + X[t];
+            g += c;
+            c += Sum0(d) + Maj(d, e, f);
+            ++t;
+
+            // t = 8 * i + 6
+            b += Sum1(g) + Ch(g, h, a) + K[t] + X[t];
+            f += b;
+            b += Sum0(c) + Maj(c, d, e);
+            ++t;
+
+            // t = 8 * i + 7
+            a += Sum1(f) + Ch(f, g, h) + K[t] + X[t];
+            e += a;
+            a += Sum0(b) + Maj(b, c, d);
+            ++t;
+        }
+
+        H1 += a;
+        H2 += b;
+        H3 += c;
+        H4 += d;
+        H5 += e;
+        H6 += f;
+        H7 += g;
+        H8 += h;
+
+        //
+        // reset the offset and clean out the word buffer.
+        //
+        xOff = 0;
+        for (int i = 0; i < 16; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    /* SHA-256 functions */
+    private int Ch(
+        int    x,
+        int    y,
+        int    z)
+    {
+        return (x & y) ^ ((~x) & z);
+    }
+
+    private int Maj(
+        int    x,
+        int    y,
+        int    z)
+    {
+        return (x & y) ^ (x & z) ^ (y & z);
+    }
+
+    private int Sum0(
+        int    x)
+    {
+        return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10));
+    }
+
+    private int Sum1(
+        int    x)
+    {
+        return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7));
+    }
+
+    private int Theta0(
+        int    x)
+    {
+        return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
+    }
+
+    private int Theta1(
+        int    x)
+    {
+        return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10);
+    }
+
+    /* SHA-256 Constants
+     * (represent the first 32 bits of the fractional parts of the
+     * cube roots of the first sixty-four prime numbers)
+     */
+    static final int K[] = {
+        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+    };
+
+    public Memoable copy()
+    {
+        return new SHA256Digest(this);
+    }
+
+    public void reset(Memoable other)
+    {
+        SHA256Digest d = (SHA256Digest)other;
+
+        copyIn(d);
+    }
+
+    public byte[] getEncodedState()
+    {
+        byte[] state = new byte[52 + xOff * 4];
+
+        super.populateState(state);
+
+        Pack.intToBigEndian(H1, state, 16);
+        Pack.intToBigEndian(H2, state, 20);
+        Pack.intToBigEndian(H3, state, 24);
+        Pack.intToBigEndian(H4, state, 28);
+        Pack.intToBigEndian(H5, state, 32);
+        Pack.intToBigEndian(H6, state, 36);
+        Pack.intToBigEndian(H7, state, 40);
+        Pack.intToBigEndian(H8, state, 44);
+        Pack.intToBigEndian(xOff, state, 48);
+
+        for (int i = 0; i != xOff; i++)
+        {
+            Pack.intToBigEndian(X[i], state, 52 + (i * 4));
+        }
+
+        return state;
+    }
+}
+
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA384Digest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA384Digest.java
new file mode 100644
index 0000000..77a0db3
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA384Digest.java
@@ -0,0 +1,118 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+import com.android.internal.org.bouncycastle.util.Memoable;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+
+/**
+ * FIPS 180-2 implementation of SHA-384.
+ *
+ * <pre>
+ *         block  word  digest
+ * SHA-1   512    32    160
+ * SHA-256 512    32    256
+ * SHA-384 1024   64    384
+ * SHA-512 1024   64    512
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SHA384Digest
+    extends LongDigest
+{
+    private static final int    DIGEST_LENGTH = 48;
+
+    /**
+     * Standard constructor
+     */
+    public SHA384Digest()
+    {
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public SHA384Digest(SHA384Digest t)
+    {
+        super(t);
+    }
+
+    /**
+     * State constructor - create a digest initialised with the state of a previous one.
+     *
+     * @param encodedState the encoded state from the originating digest.
+     */
+    public SHA384Digest(byte[] encodedState)
+    {
+        restoreState(encodedState);
+    }
+
+    public String getAlgorithmName()
+    {
+        return "SHA-384";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        Pack.longToBigEndian(H1, out, outOff);
+        Pack.longToBigEndian(H2, out, outOff + 8);
+        Pack.longToBigEndian(H3, out, outOff + 16);
+        Pack.longToBigEndian(H4, out, outOff + 24);
+        Pack.longToBigEndian(H5, out, outOff + 32);
+        Pack.longToBigEndian(H6, out, outOff + 40);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables
+     */
+    public void reset()
+    {
+        super.reset();
+
+        /* SHA-384 initial hash value
+         * The first 64 bits of the fractional parts of the square roots
+         * of the 9th through 16th prime numbers
+         */
+        H1 = 0xcbbb9d5dc1059ed8l;
+        H2 = 0x629a292a367cd507l;
+        H3 = 0x9159015a3070dd17l;
+        H4 = 0x152fecd8f70e5939l;
+        H5 = 0x67332667ffc00b31l;
+        H6 = 0x8eb44a8768581511l;
+        H7 = 0xdb0c2e0d64f98fa7l;
+        H8 = 0x47b5481dbefa4fa4l;
+    }
+
+    public Memoable copy()
+    {
+        return new SHA384Digest(this);
+    }
+
+    public void reset(Memoable other)
+    {
+        SHA384Digest d = (SHA384Digest)other;
+
+        super.copyIn(d);
+    }
+
+    public byte[] getEncodedState()
+    {
+        byte[] encoded = new byte[getEncodedStateSize()];
+        super.populateState(encoded);
+        return encoded;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA512Digest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA512Digest.java
new file mode 100644
index 0000000..5a84732
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/digests/SHA512Digest.java
@@ -0,0 +1,121 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.digests;
+
+import com.android.internal.org.bouncycastle.util.Memoable;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+
+/**
+ * FIPS 180-2 implementation of SHA-512.
+ *
+ * <pre>
+ *         block  word  digest
+ * SHA-1   512    32    160
+ * SHA-256 512    32    256
+ * SHA-384 1024   64    384
+ * SHA-512 1024   64    512
+ * </pre>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SHA512Digest
+    extends LongDigest
+{
+    private static final int    DIGEST_LENGTH = 64;
+
+    /**
+     * Standard constructor
+     */
+    public SHA512Digest()
+    {
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public SHA512Digest(SHA512Digest t)
+    {
+        super(t);
+    }
+
+    /**
+     * State constructor - create a digest initialised with the state of a previous one.
+     *
+     * @param encodedState the encoded state from the originating digest.
+     */
+    public SHA512Digest(byte[] encodedState)
+    {
+        restoreState(encodedState);
+    }
+
+    public String getAlgorithmName()
+    {
+        return "SHA-512";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        Pack.longToBigEndian(H1, out, outOff);
+        Pack.longToBigEndian(H2, out, outOff + 8);
+        Pack.longToBigEndian(H3, out, outOff + 16);
+        Pack.longToBigEndian(H4, out, outOff + 24);
+        Pack.longToBigEndian(H5, out, outOff + 32);
+        Pack.longToBigEndian(H6, out, outOff + 40);
+        Pack.longToBigEndian(H7, out, outOff + 48);
+        Pack.longToBigEndian(H8, out, outOff + 56);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables
+     */
+    public void reset()
+    {
+        super.reset();
+
+        /* SHA-512 initial hash value
+         * The first 64 bits of the fractional parts of the square roots
+         * of the first eight prime numbers
+         */
+        H1 = 0x6a09e667f3bcc908L;
+        H2 = 0xbb67ae8584caa73bL;
+        H3 = 0x3c6ef372fe94f82bL;
+        H4 = 0xa54ff53a5f1d36f1L;
+        H5 = 0x510e527fade682d1L;
+        H6 = 0x9b05688c2b3e6c1fL;
+        H7 = 0x1f83d9abfb41bd6bL;
+        H8 = 0x5be0cd19137e2179L;
+    }
+
+    public Memoable copy()
+    {
+        return new SHA512Digest(this);
+    }
+
+    public void reset(Memoable other)
+    {
+        SHA512Digest d = (SHA512Digest)other;
+
+        copyIn(d);
+    }
+
+    public byte[] getEncodedState()
+    {
+        byte[] encoded = new byte[getEncodedStateSize()];
+        super.populateState(encoded);
+        return encoded;
+    }
+}
+
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/ec/CustomNamedCurves.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/ec/CustomNamedCurves.java
new file mode 100644
index 0000000..e6692a0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/ec/CustomNamedCurves.java
@@ -0,0 +1,802 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.ec;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.gm.GMObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParametersHolder;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECPoint;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+// BEGIN android-removed
+// import org.bouncycastle.math.ec.custom.djb.Curve25519;
+// import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecP128R1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecP160K1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecP160R1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecP160R2Curve;
+// END android-removed
+import com.android.internal.org.bouncycastle.math.ec.custom.sec.SecP192K1Curve;
+import com.android.internal.org.bouncycastle.math.ec.custom.sec.SecP192R1Curve;
+import com.android.internal.org.bouncycastle.math.ec.custom.sec.SecP224K1Curve;
+import com.android.internal.org.bouncycastle.math.ec.custom.sec.SecP224R1Curve;
+import com.android.internal.org.bouncycastle.math.ec.custom.sec.SecP256K1Curve;
+import com.android.internal.org.bouncycastle.math.ec.custom.sec.SecP256R1Curve;
+import com.android.internal.org.bouncycastle.math.ec.custom.sec.SecP384R1Curve;
+import com.android.internal.org.bouncycastle.math.ec.custom.sec.SecP521R1Curve;
+// BEGIN android-removed
+// import org.bouncycastle.math.ec.custom.sec.SecT113R1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT113R2Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT131R1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT131R2Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT163K1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT163R1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT163R2Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT193R1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT193R2Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT233K1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT233R1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT239K1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT283K1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT283R1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT409K1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT409R1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT571K1Curve;
+// import org.bouncycastle.math.ec.custom.sec.SecT571R1Curve;
+// END android-removed
+import com.android.internal.org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism;
+import com.android.internal.org.bouncycastle.math.ec.endo.GLVTypeBParameters;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CustomNamedCurves
+{
+    private static ECCurve configureCurve(ECCurve curve)
+    {
+        return curve;
+    }
+
+    private static ECCurve configureCurveGLV(ECCurve c, GLVTypeBParameters p)
+    {
+        return c.configure().setEndomorphism(new GLVTypeBEndomorphism(c, p)).create();
+    }
+
+    // BEGIN Android-removed: Unsupported curves
+    /*
+    /*
+     * curve25519
+     *
+    static X9ECParametersHolder curve25519 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            ECCurve curve = configureCurve(new Curve25519());
+
+            /*
+             * NOTE: Curve25519 was specified in Montgomery form. Rewriting in Weierstrass form
+             * involves substitution of variables, so the base-point x coordinate is 9 + (486662 / 3).
+             * 
+             * The Curve25519 paper doesn't say which of the two possible y values the base
+             * point has. The choice here is guided by language in the Ed25519 paper.
+             * 
+             * (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14) 
+             *
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A"
+                + "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"));
+
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * secp128r1
+     *
+    static X9ECParametersHolder secp128r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("000E0D4D696E6768756151750CC03A4473D03679");
+            ECCurve curve = configureCurve(new SecP128R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "161FF7528B899B2D0C28607CA52C5B86"
+                + "CF5AC8395BAFEB13C02DA292DDED7A83"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * secp160k1
+     *
+    static X9ECParametersHolder secp160k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            GLVTypeBParameters glv = new GLVTypeBParameters(
+                new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16),
+                new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16),
+                new BigInteger[]{
+                    new BigInteger("9162fbe73984472a0a9e", 16),
+                    new BigInteger("-96341f1138933bc2f505", 16) },
+                new BigInteger[]{
+                    new BigInteger("127971af8721782ecffa3", 16),
+                    new BigInteger("9162fbe73984472a0a9e", 16) },
+                new BigInteger("9162fbe73984472a0a9d0590", 16),
+                new BigInteger("96341f1138933bc2f503fd44", 16),
+                176);
+            ECCurve curve = configureCurveGLV(new SecP160K1Curve(), glv);
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
+                + "938CF935318FDCED6BC28286531733C3F03C4FEE"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * secp160r1
+     *
+    static X9ECParametersHolder secp160r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("1053CDE42C14D696E67687561517533BF3F83345");
+            ECCurve curve = configureCurve(new SecP160R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "4A96B5688EF573284664698968C38BB913CBFC82"
+                + "23A628553168947D59DCC912042351377AC5FB32"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * secp160r2
+     *
+    static X9ECParametersHolder secp160r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("B99B99B099B323E02709A4D696E6768756151751");
+            ECCurve curve = configureCurve(new SecP160R2Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
+                + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+    */
+    // END Android-removed: Unsupported curves
+
+    /*
+     * secp192k1
+     */
+    static X9ECParametersHolder secp192k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            GLVTypeBParameters glv = new GLVTypeBParameters(
+                new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16),
+                new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16),
+                new BigInteger[]{
+                    new BigInteger("71169be7330b3038edb025f1", 16),
+                    new BigInteger("-b3fb3400dec5c4adceb8655c", 16) },
+                new BigInteger[]{
+                    new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
+                    new BigInteger("71169be7330b3038edb025f1", 16) },
+                new BigInteger("71169be7330b3038edb025f1d0f9", 16),
+                new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16),
+                208);
+            ECCurve curve = configureCurveGLV(new SecP192K1Curve(), glv);
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+                + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * secp192r1
+     */
+    static X9ECParametersHolder secp192r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
+            ECCurve curve = configureCurve(new SecP192R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+                + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * secp224k1
+     */
+    static X9ECParametersHolder secp224k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            GLVTypeBParameters glv = new GLVTypeBParameters(
+                new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16),
+                new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16),
+                new BigInteger[]{
+                    new BigInteger("6b8cf07d4ca75c88957d9d670591", 16),
+                    new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) },
+                new BigInteger[]{
+                    new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
+                    new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
+                new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16),
+                new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16),
+                240);
+            ECCurve curve = configureCurveGLV(new SecP224K1Curve(), glv);
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+                + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * secp224r1
+     */
+    static X9ECParametersHolder secp224r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
+            ECCurve curve = configureCurve(new SecP224R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+                + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * secp256k1
+     */
+    static X9ECParametersHolder secp256k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            GLVTypeBParameters glv = new GLVTypeBParameters(
+                new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16),
+                new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16),
+                new BigInteger[]{
+                    new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16),
+                    new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) },
+                new BigInteger[]{
+                    new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
+                    new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
+                new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16),
+                new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16),
+                272);
+            ECCurve curve = configureCurveGLV(new SecP256K1Curve(), glv);
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+                + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * secp256r1
+     */
+    static X9ECParametersHolder secp256r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90");
+            ECCurve curve = configureCurve(new SecP256R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+                + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * secp384r1
+     */
+    static X9ECParametersHolder secp384r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
+            ECCurve curve = configureCurve(new SecP384R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+                + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * secp521r1
+     */
+    static X9ECParametersHolder secp521r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("D09E8800291CB85396CC6717393284AAA0DA64BA");
+            ECCurve curve = configureCurve(new SecP521R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
+                + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    // BEGIN Android-removed: Unsupported curves
+    /*
+    /*
+     * sect113r1
+     *
+    static X9ECParametersHolder sect113r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("10E723AB14D696E6768756151756FEBF8FCB49A9");
+            ECCurve curve = configureCurve(new SecT113R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "009D73616F35F4AB1407D73562C10F"
+                + "00A52830277958EE84D1315ED31886"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect113r2
+     *
+    static X9ECParametersHolder sect113r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("10C0FB15760860DEF1EEF4D696E676875615175D");
+            ECCurve curve = configureCurve(new SecT113R2Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "01A57A6A7B26CA5EF52FCDB8164797"
+                + "00B3ADC94ED1FE674C06E695BABA1D"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect131r1
+     *
+    static X9ECParametersHolder sect131r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("4D696E676875615175985BD3ADBADA21B43A97E2");
+            ECCurve curve = configureCurve(new SecT131R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0081BAF91FDF9833C40F9C181343638399"
+                + "078C6E7EA38C001F73C8134B1B4EF9E150"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect131r2
+     *
+    static X9ECParametersHolder sect131r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("985BD3ADBAD4D696E676875615175A21B43A97E3");
+            ECCurve curve = configureCurve(new SecT131R2Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0356DCD8F2F95031AD652D23951BB366A8"
+                + "0648F06D867940A5366D9E265DE9EB240F"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect163k1
+     *
+    static X9ECParametersHolder sect163k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            ECCurve curve = configureCurve(new SecT163K1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
+                + "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect163r1
+     *
+    static X9ECParametersHolder sect163r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("24B7B137C8A14D696E6768756151756FD0DA2E5C");
+            ECCurve curve = configureCurve(new SecT163R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0369979697AB43897789566789567F787A7876A654"
+                + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect163r2
+     *
+    static X9ECParametersHolder sect163r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("85E25BFE5C86226CDB12016F7553F9D0E693A268");
+            ECCurve curve = configureCurve(new SecT163R2Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "03F0EBA16286A2D57EA0991168D4994637E8343E36"
+                + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect193r1
+     *
+    static X9ECParametersHolder sect193r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("103FAEC74D696E676875615175777FC5B191EF30");
+            ECCurve curve = configureCurve(new SecT193R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"
+                + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect193r2
+     *
+    static X9ECParametersHolder sect193r2 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("10B7B4D696E676875615175137C8A16FD0DA2211");
+            ECCurve curve = configureCurve(new SecT193R2Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"
+                + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect233k1
+     *
+    static X9ECParametersHolder sect233k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            ECCurve curve = configureCurve(new SecT233K1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
+                + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect233r1
+     *
+    static X9ECParametersHolder sect233r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3");
+            ECCurve curve = configureCurve(new SecT233R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
+                + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect239k1
+     *
+    static X9ECParametersHolder sect239k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            ECCurve curve = configureCurve(new SecT239K1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
+                + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect283k1
+     *
+    static X9ECParametersHolder sect283k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            ECCurve curve = configureCurve(new SecT283K1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
+                + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect283r1
+     *
+    static X9ECParametersHolder sect283r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE");
+            ECCurve curve = configureCurve(new SecT283R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
+                + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect409k1
+     *
+    static X9ECParametersHolder sect409k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            ECCurve curve = configureCurve(new SecT409K1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
+                + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect409r1
+     *
+    static X9ECParametersHolder sect409r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("4099B5A457F9D69F79213D094C4BCD4D4262210B");
+            ECCurve curve = configureCurve(new SecT409R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
+                + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect571k1
+     *
+    static X9ECParametersHolder sect571k1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            ECCurve curve = configureCurve(new SecT571K1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
+                + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sect571r1
+     *
+    static X9ECParametersHolder sect571r1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = Hex.decode("2AA058F73A0E33AB486B0F610410C53A7F132310");
+            ECCurve curve = configureCurve(new SecT571R1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
+                + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+
+    /*
+     * sm2p256v1
+     *
+    static X9ECParametersHolder sm2p256v1 = new X9ECParametersHolder()
+    {
+        protected X9ECParameters createParameters()
+        {
+            byte[] S = null;
+            ECCurve curve = configureCurve(new SM2P256V1Curve());
+            X9ECPoint G = new X9ECPoint(curve, Hex.decode("04"
+                + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"
+                + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"));
+            return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S);
+        }
+    };
+    */
+    // END Android-removed: Unsupported curves
+
+    static final Hashtable nameToCurve = new Hashtable();
+    static final Hashtable nameToOID = new Hashtable();
+    static final Hashtable oidToCurve = new Hashtable();
+    static final Hashtable oidToName = new Hashtable();
+    static final Vector names = new Vector();
+
+    static void defineCurve(String name, X9ECParametersHolder holder)
+    {
+        names.addElement(name);
+        name = Strings.toLowerCase(name);
+        nameToCurve.put(name, holder);
+    }
+
+    static void defineCurveWithOID(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
+    {
+        names.addElement(name);
+        oidToName.put(oid, name);
+        oidToCurve.put(oid, holder);
+        name = Strings.toLowerCase(name);
+        nameToOID.put(name, oid);
+        nameToCurve.put(name, holder);
+    }
+
+    static void defineCurveAlias(String name, ASN1ObjectIdentifier oid)
+    {
+        Object curve = oidToCurve.get(oid);
+        if (curve == null)
+        {
+            throw new IllegalStateException();
+        }
+
+        name = Strings.toLowerCase(name);
+        nameToOID.put(name, oid);
+        nameToCurve.put(name, curve);
+    }
+
+    static
+    {
+        // BEGIN Android-removed: Unsupported curves
+        /*
+        defineCurveWithOID("curve25519", CryptlibObjectIdentifiers.curvey25519, curve25519);
+
+//        defineCurveWithOID("secp112r1", SECObjectIdentifiers.secp112r1, secp112r1);
+//        defineCurveWithOID("secp112r2", SECObjectIdentifiers.secp112r2, secp112r2);
+        defineCurveWithOID("secp128r1", SECObjectIdentifiers.secp128r1, secp128r1);
+//        defineCurveWithOID("secp128r2", SECObjectIdentifiers.secp128r2, secp128r2);
+        defineCurveWithOID("secp160k1", SECObjectIdentifiers.secp160k1, secp160k1);
+        defineCurveWithOID("secp160r1", SECObjectIdentifiers.secp160r1, secp160r1);
+        defineCurveWithOID("secp160r2", SECObjectIdentifiers.secp160r2, secp160r2);
+        */
+        // END Android-removed: Unsupported curves
+        defineCurveWithOID("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1);
+        defineCurveWithOID("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1);
+        defineCurveWithOID("secp224k1", SECObjectIdentifiers.secp224k1, secp224k1);
+        defineCurveWithOID("secp224r1", SECObjectIdentifiers.secp224r1, secp224r1);
+        defineCurveWithOID("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1);
+        defineCurveWithOID("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1);
+        defineCurveWithOID("secp384r1", SECObjectIdentifiers.secp384r1, secp384r1);
+        defineCurveWithOID("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1);
+
+        // BEGIN Android-removed: Unsupported curves
+        /*
+        defineCurveWithOID("sect113r1", SECObjectIdentifiers.sect113r1, sect113r1);
+        defineCurveWithOID("sect113r2", SECObjectIdentifiers.sect113r2, sect113r2);
+        defineCurveWithOID("sect131r1", SECObjectIdentifiers.sect131r1, sect131r1);
+        defineCurveWithOID("sect131r2", SECObjectIdentifiers.sect131r2, sect131r2);
+        defineCurveWithOID("sect163k1", SECObjectIdentifiers.sect163k1, sect163k1);
+        defineCurveWithOID("sect163r1", SECObjectIdentifiers.sect163r1, sect163r1);
+        defineCurveWithOID("sect163r2", SECObjectIdentifiers.sect163r2, sect163r2);
+        defineCurveWithOID("sect193r1", SECObjectIdentifiers.sect193r1, sect193r1);
+        defineCurveWithOID("sect193r2", SECObjectIdentifiers.sect193r2, sect193r2);
+        defineCurveWithOID("sect233k1", SECObjectIdentifiers.sect233k1, sect233k1);
+        defineCurveWithOID("sect233r1", SECObjectIdentifiers.sect233r1, sect233r1);
+        defineCurveWithOID("sect239k1", SECObjectIdentifiers.sect239k1, sect239k1);
+        defineCurveWithOID("sect283k1", SECObjectIdentifiers.sect283k1, sect283k1);
+        defineCurveWithOID("sect283r1", SECObjectIdentifiers.sect283r1, sect283r1);
+        defineCurveWithOID("sect409k1", SECObjectIdentifiers.sect409k1, sect409k1);
+        defineCurveWithOID("sect409r1", SECObjectIdentifiers.sect409r1, sect409r1);
+        defineCurveWithOID("sect571k1", SECObjectIdentifiers.sect571k1, sect571k1);
+        defineCurveWithOID("sect571r1", SECObjectIdentifiers.sect571r1, sect571r1);
+
+        defineCurveWithOID("sm2p256v1", GMObjectIdentifiers.sm2p256v1, sm2p256v1);
+
+        defineCurveAlias("B-163", SECObjectIdentifiers.sect163r2);
+        defineCurveAlias("B-233", SECObjectIdentifiers.sect233r1);
+        defineCurveAlias("B-283", SECObjectIdentifiers.sect283r1);
+        defineCurveAlias("B-409", SECObjectIdentifiers.sect409r1);
+        defineCurveAlias("B-571", SECObjectIdentifiers.sect571r1);
+
+        defineCurveAlias("K-163", SECObjectIdentifiers.sect163k1);
+        defineCurveAlias("K-233", SECObjectIdentifiers.sect233k1);
+        defineCurveAlias("K-283", SECObjectIdentifiers.sect283k1);
+        defineCurveAlias("K-409", SECObjectIdentifiers.sect409k1);
+        defineCurveAlias("K-571", SECObjectIdentifiers.sect571k1);
+        */
+        // END Android-removed: Unsupported curves
+
+        defineCurveAlias("P-192", SECObjectIdentifiers.secp192r1);
+        defineCurveAlias("P-224", SECObjectIdentifiers.secp224r1);
+        defineCurveAlias("P-256", SECObjectIdentifiers.secp256r1);
+        defineCurveAlias("P-384", SECObjectIdentifiers.secp384r1);
+        defineCurveAlias("P-521", SECObjectIdentifiers.secp521r1);
+    }
+
+    public static X9ECParameters getByName(String name)
+    {
+        X9ECParametersHolder holder = (X9ECParametersHolder)nameToCurve.get(Strings.toLowerCase(name));
+        return holder == null ? null : holder.getParameters();
+    }
+
+    /**
+     * return the X9ECParameters object for the named curve represented by the passed in object
+     * identifier. Null if the curve isn't present.
+     * 
+     * @param oid
+     *            an object identifier representing a named curve, if present.
+     */
+    public static X9ECParameters getByOID(ASN1ObjectIdentifier oid)
+    {
+        X9ECParametersHolder holder = (X9ECParametersHolder)oidToCurve.get(oid);
+        return holder == null ? null : holder.getParameters();
+    }
+
+    /**
+     * return the object identifier signified by the passed in name. Null if there is no object
+     * identifier associated with name.
+     * 
+     * @return the object identifier associated with name, if present.
+     */
+    public static ASN1ObjectIdentifier getOID(String name)
+    {
+        return (ASN1ObjectIdentifier)nameToOID.get(Strings.toLowerCase(name));
+    }
+
+    /**
+     * return the named curve name represented by the given object identifier.
+     */
+    public static String getName(ASN1ObjectIdentifier oid)
+    {
+        return (String)oidToName.get(oid);
+    }
+
+    /**
+     * returns an enumeration containing the name strings for curves contained in this structure.
+     */
+    public static Enumeration getNames()
+    {
+        return names.elements();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/encodings/OAEPEncoding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/encodings/OAEPEncoding.java
new file mode 100644
index 0000000..5278e8d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/encodings/OAEPEncoding.java
@@ -0,0 +1,365 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.encodings;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.AsymmetricBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+// Android-changed: Use Android digests
+// import org.bouncycastle.crypto.util.DigestFactory;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OAEPEncoding
+    implements AsymmetricBlockCipher
+{
+    private byte[]                  defHash;
+    private Digest                  mgf1Hash;
+
+    private AsymmetricBlockCipher   engine;
+    private SecureRandom            random;
+    private boolean                 forEncryption;
+
+    public OAEPEncoding(
+        AsymmetricBlockCipher   cipher)
+    {
+        // Android-changed: Use Android digests
+        // this(cipher, DigestFactory.createSHA1(), null);
+        this(cipher, AndroidDigestFactory.getSHA1(), null);
+    }
+    
+    public OAEPEncoding(
+        AsymmetricBlockCipher       cipher,
+        Digest                      hash)
+    {
+        this(cipher, hash, null);
+    }
+    
+    public OAEPEncoding(
+        AsymmetricBlockCipher       cipher,
+        Digest                      hash,
+        byte[]                      encodingParams)
+    {
+        this(cipher, hash, hash, encodingParams);
+    }
+
+    public OAEPEncoding(
+        AsymmetricBlockCipher       cipher,
+        Digest                      hash,
+        Digest                      mgf1Hash,
+        byte[]                      encodingParams)
+    {
+        this.engine = cipher;
+        this.mgf1Hash = mgf1Hash;
+        this.defHash = new byte[hash.getDigestSize()];
+
+        hash.reset();
+
+        if (encodingParams != null)
+        {
+            hash.update(encodingParams, 0, encodingParams.length);
+        }
+
+        hash.doFinal(defHash, 0);
+    }
+
+    public AsymmetricBlockCipher getUnderlyingCipher()
+    {
+        return engine;
+    }
+
+    public void init(
+        boolean             forEncryption,
+        CipherParameters    param)
+    {
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom  rParam = (ParametersWithRandom)param;
+
+            this.random = rParam.getRandom();
+        }
+        else
+        {   
+            this.random = CryptoServicesRegistrar.getSecureRandom();
+        }
+
+        engine.init(forEncryption, param);
+
+        this.forEncryption = forEncryption;
+    }
+
+    public int getInputBlockSize()
+    {
+        int     baseBlockSize = engine.getInputBlockSize();
+
+        if (forEncryption)
+        {
+            return baseBlockSize - 1 - 2 * defHash.length;
+        }
+        else
+        {
+            return baseBlockSize;
+        }
+    }
+
+    public int getOutputBlockSize()
+    {
+        int     baseBlockSize = engine.getOutputBlockSize();
+
+        if (forEncryption)
+        {
+            return baseBlockSize;
+        }
+        else
+        {
+            return baseBlockSize - 1 - 2 * defHash.length;
+        }
+    }
+
+    public byte[] processBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        if (forEncryption)
+        {
+            return encodeBlock(in, inOff, inLen);
+        }
+        else
+        {
+            return decodeBlock(in, inOff, inLen);
+        }
+    }
+
+    public byte[] encodeBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        if (inLen > getInputBlockSize())
+        {
+            throw new DataLengthException("input data too long");
+        }
+
+        byte[]  block = new byte[getInputBlockSize() + 1 + 2 * defHash.length];
+
+        //
+        // copy in the message
+        //
+        System.arraycopy(in, inOff, block, block.length - inLen, inLen);
+
+        //
+        // add sentinel
+        //
+        block[block.length - inLen - 1] = 0x01;
+
+        //
+        // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0)
+        //
+
+        //
+        // add the hash of the encoding params.
+        //
+        System.arraycopy(defHash, 0, block, defHash.length, defHash.length);
+
+        //
+        // generate the seed.
+        //
+        byte[]  seed = new byte[defHash.length];
+
+        random.nextBytes(seed);
+
+        //
+        // mask the message block.
+        //
+        byte[]  mask = maskGeneratorFunction1(seed, 0, seed.length, block.length - defHash.length);
+
+        for (int i = defHash.length; i != block.length; i++)
+        {
+            block[i] ^= mask[i - defHash.length];
+        }
+
+        //
+        // add in the seed
+        //
+        System.arraycopy(seed, 0, block, 0, defHash.length);
+
+        //
+        // mask the seed.
+        //
+        mask = maskGeneratorFunction1(
+                        block, defHash.length, block.length - defHash.length, defHash.length);
+
+        for (int i = 0; i != defHash.length; i++)
+        {
+            block[i] ^= mask[i];
+        }
+
+        return engine.processBlock(block, 0, block.length);
+    }
+
+    /**
+     * @exception InvalidCipherTextException if the decrypted block turns out to
+     * be badly formatted.
+     */
+    public byte[] decodeBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        byte[]  data = engine.processBlock(in, inOff, inLen);
+        byte[]  block = new byte[engine.getOutputBlockSize()];
+
+        //
+        // as we may have zeros in our leading bytes for the block we produced
+        // on encryption, we need to make sure our decrypted block comes back
+        // the same size.
+        //
+        boolean wrongData = (block.length < (2 * defHash.length) + 1);
+
+        if (data.length <= block.length)
+        {
+            System.arraycopy(data, 0, block, block.length - data.length, data.length);
+        }
+        else
+        {
+            System.arraycopy(data, 0, block, 0, block.length);
+            wrongData = true;
+        }
+
+        //
+        // unmask the seed.
+        //
+        byte[] mask = maskGeneratorFunction1(
+                    block, defHash.length, block.length - defHash.length, defHash.length);
+
+        for (int i = 0; i != defHash.length; i++)
+        {
+            block[i] ^= mask[i];
+        }
+
+        //
+        // unmask the message block.
+        //
+        mask = maskGeneratorFunction1(block, 0, defHash.length, block.length - defHash.length);
+
+        for (int i = defHash.length; i != block.length; i++)
+        {
+            block[i] ^= mask[i - defHash.length];
+        }
+
+        //
+        // check the hash of the encoding params.
+        // long check to try to avoid this been a source of a timing attack.
+        //
+        boolean defHashWrong = false;
+
+        for (int i = 0; i != defHash.length; i++)
+        {
+            if (defHash[i] != block[defHash.length + i])
+            {
+                defHashWrong = true;
+            }
+        }
+
+        //
+        // find the data block
+        //
+        int start = block.length;
+
+        for (int index = 2 * defHash.length; index != block.length; index++)
+        {
+            if (block[index] != 0 & start == block.length)
+            {
+                start = index;
+            }
+        }
+
+        boolean dataStartWrong = (start > (block.length - 1) | block[start] != 1);
+
+        start++;
+
+        if (defHashWrong | wrongData | dataStartWrong)
+        {
+            Arrays.fill(block, (byte)0);
+            throw new InvalidCipherTextException("data wrong");
+        }
+
+        //
+        // extract the data block
+        //
+        byte[]  output = new byte[block.length - start];
+
+        System.arraycopy(block, start, output, 0, output.length);
+
+        return output;
+    }
+
+    /**
+     * int to octet string.
+     */
+    private void ItoOSP(
+        int     i,
+        byte[]  sp)
+    {
+        sp[0] = (byte)(i >>> 24);
+        sp[1] = (byte)(i >>> 16);
+        sp[2] = (byte)(i >>> 8);
+        sp[3] = (byte)(i >>> 0);
+    }
+
+    /**
+     * mask generator function, as described in PKCS1v2.
+     */
+    private byte[] maskGeneratorFunction1(
+        byte[]  Z,
+        int     zOff,
+        int     zLen,
+        int     length)
+    {
+        byte[]  mask = new byte[length];
+        byte[]  hashBuf = new byte[mgf1Hash.getDigestSize()];
+        byte[]  C = new byte[4];
+        int     counter = 0;
+
+        mgf1Hash.reset();
+
+        while (counter < (length / hashBuf.length))
+        {
+            ItoOSP(counter, C);
+
+            mgf1Hash.update(Z, zOff, zLen);
+            mgf1Hash.update(C, 0, C.length);
+            mgf1Hash.doFinal(hashBuf, 0);
+
+            System.arraycopy(hashBuf, 0, mask, counter * hashBuf.length, hashBuf.length);
+
+            counter++;
+        }
+
+        if ((counter * hashBuf.length) < length)
+        {
+            ItoOSP(counter, C);
+
+            mgf1Hash.update(Z, zOff, zLen);
+            mgf1Hash.update(C, 0, C.length);
+            mgf1Hash.doFinal(hashBuf, 0);
+
+            System.arraycopy(hashBuf, 0, mask, counter * hashBuf.length, mask.length - (counter * hashBuf.length));
+        }
+
+        return mask;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
new file mode 100644
index 0000000..394e457
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
@@ -0,0 +1,448 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.encodings;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.AsymmetricBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * this does your basic PKCS 1 v1.5 padding - whether or not you should be using this
+ * depends on your application - see PKCS1 Version 2 for details.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS1Encoding
+    implements AsymmetricBlockCipher
+{
+    /**
+     * @deprecated use NOT_STRICT_LENGTH_ENABLED_PROPERTY
+     */
+    public static final String STRICT_LENGTH_ENABLED_PROPERTY = "com.android.internal.org.bouncycastle.pkcs1.strict";
+
+    /**
+     * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to
+     * work with one of these set the system property org.bouncycastle.pkcs1.not_strict to true.
+     * <p>
+     * The system property is checked during construction of the encoding object, it is set to
+     * false by default.
+     * </p>
+     */
+    public static final String NOT_STRICT_LENGTH_ENABLED_PROPERTY = "com.android.internal.org.bouncycastle.pkcs1.not_strict";
+
+    private static final int HEADER_LENGTH = 10;
+
+    private SecureRandom random;
+    private AsymmetricBlockCipher engine;
+    private boolean forEncryption;
+    private boolean forPrivateKey;
+    private boolean useStrictLength;
+    private int pLen = -1;
+    private byte[] fallback = null;
+    private byte[] blockBuffer;
+
+    /**
+     * Basic constructor.
+     *
+     * @param cipher
+     */
+    public PKCS1Encoding(
+        AsymmetricBlockCipher cipher)
+    {
+        this.engine = cipher;
+        this.useStrictLength = useStrict();
+    }
+
+    /**
+     * Constructor for decryption with a fixed plaintext length.
+     *
+     * @param cipher The cipher to use for cryptographic operation.
+     * @param pLen   Length of the expected plaintext.
+     */
+    public PKCS1Encoding(
+        AsymmetricBlockCipher cipher,
+        int pLen)
+    {
+        this.engine = cipher;
+        this.useStrictLength = useStrict();
+        this.pLen = pLen;
+    }
+
+    /**
+     * Constructor for decryption with a fixed plaintext length and a fallback
+     * value that is returned, if the padding is incorrect.
+     *
+     * @param cipher   The cipher to use for cryptographic operation.
+     * @param fallback The fallback value, we don't do an arraycopy here.
+     */
+    public PKCS1Encoding(
+        AsymmetricBlockCipher cipher,
+        byte[] fallback)
+    {
+        this.engine = cipher;
+        this.useStrictLength = useStrict();
+        this.fallback = fallback;
+        this.pLen = fallback.length;
+    }
+
+
+    //
+    // for J2ME compatibility
+    //
+    private boolean useStrict()
+    {
+        // required if security manager has been installed.
+        String strict = (String)AccessController.doPrivileged(new PrivilegedAction()
+        {
+            public Object run()
+            {
+                return System.getProperty(STRICT_LENGTH_ENABLED_PROPERTY);
+            }
+        });
+        String notStrict = (String)AccessController.doPrivileged(new PrivilegedAction()
+        {
+            public Object run()
+            {
+                return System.getProperty(NOT_STRICT_LENGTH_ENABLED_PROPERTY);
+            }
+        });
+
+        if (notStrict != null)
+        {
+            return !notStrict.equals("true");
+        }
+
+        return strict == null || strict.equals("true");
+    }
+
+    public AsymmetricBlockCipher getUnderlyingCipher()
+    {
+        return engine;
+    }
+
+    public void init(
+        boolean forEncryption,
+        CipherParameters param)
+    {
+        AsymmetricKeyParameter kParam;
+
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+            this.random = rParam.getRandom();
+            kParam = (AsymmetricKeyParameter)rParam.getParameters();
+        }
+        else
+        {
+            kParam = (AsymmetricKeyParameter)param;
+            if (!kParam.isPrivate() && forEncryption)
+            {
+                this.random = CryptoServicesRegistrar.getSecureRandom();
+            }
+        }
+
+        engine.init(forEncryption, param);
+
+        this.forPrivateKey = kParam.isPrivate();
+        this.forEncryption = forEncryption;
+        this.blockBuffer = new byte[engine.getOutputBlockSize()];
+
+        if (pLen > 0 && fallback == null && random == null)
+        {
+           throw new IllegalArgumentException("encoder requires random");
+        }
+    }
+
+    public int getInputBlockSize()
+    {
+        int baseBlockSize = engine.getInputBlockSize();
+
+        if (forEncryption)
+        {
+            return baseBlockSize - HEADER_LENGTH;
+        }
+        else
+        {
+            return baseBlockSize;
+        }
+    }
+
+    public int getOutputBlockSize()
+    {
+        int baseBlockSize = engine.getOutputBlockSize();
+
+        if (forEncryption)
+        {
+            return baseBlockSize;
+        }
+        else
+        {
+            return baseBlockSize - HEADER_LENGTH;
+        }
+    }
+
+    public byte[] processBlock(
+        byte[] in,
+        int inOff,
+        int inLen)
+        throws InvalidCipherTextException
+    {
+        if (forEncryption)
+        {
+            return encodeBlock(in, inOff, inLen);
+        }
+        else
+        {
+            return decodeBlock(in, inOff, inLen);
+        }
+    }
+
+    private byte[] encodeBlock(
+        byte[] in,
+        int inOff,
+        int inLen)
+        throws InvalidCipherTextException
+    {
+        if (inLen > getInputBlockSize())
+        {
+            throw new IllegalArgumentException("input data too large");
+        }
+
+        byte[] block = new byte[engine.getInputBlockSize()];
+
+        if (forPrivateKey)
+        {
+            block[0] = 0x01;                        // type code 1
+
+            for (int i = 1; i != block.length - inLen - 1; i++)
+            {
+                block[i] = (byte)0xFF;
+            }
+        }
+        else
+        {
+            random.nextBytes(block);                // random fill
+
+            block[0] = 0x02;                        // type code 2
+
+            //
+            // a zero byte marks the end of the padding, so all
+            // the pad bytes must be non-zero.
+            //
+            for (int i = 1; i != block.length - inLen - 1; i++)
+            {
+                while (block[i] == 0)
+                {
+                    block[i] = (byte)random.nextInt();
+                }
+            }
+        }
+
+        block[block.length - inLen - 1] = 0x00;       // mark the end of the padding
+        System.arraycopy(in, inOff, block, block.length - inLen, inLen);
+
+        return engine.processBlock(block, 0, block.length);
+    }
+
+    /**
+     * Checks if the argument is a correctly PKCS#1.5 encoded Plaintext
+     * for encryption.
+     *
+     * @param encoded The Plaintext.
+     * @param pLen    Expected length of the plaintext.
+     * @return Either 0, if the encoding is correct, or -1, if it is incorrect.
+     */
+    private static int checkPkcs1Encoding(byte[] encoded, int pLen)
+    {
+        int correct = 0;
+        /*
+		 * Check if the first two bytes are 0 2
+		 */
+        correct |= (encoded[0] ^ 2);
+
+		/*
+		 * Now the padding check, check for no 0 byte in the padding
+		 */
+        int plen = encoded.length - (
+            pLen /* Lenght of the PMS */
+                + 1 /* Final 0-byte before PMS */
+        );
+
+        for (int i = 1; i < plen; i++)
+        {
+            int tmp = encoded[i];
+            tmp |= tmp >> 1;
+            tmp |= tmp >> 2;
+            tmp |= tmp >> 4;
+            correct |= (tmp & 1) - 1;
+        }
+
+		/*
+		 * Make sure the padding ends with a 0 byte.
+		 */
+        correct |= encoded[encoded.length - (pLen + 1)];
+
+		/*
+		 * Return 0 or 1, depending on the result.
+		 */
+        correct |= correct >> 1;
+        correct |= correct >> 2;
+        correct |= correct >> 4;
+        return ~((correct & 1) - 1);
+    }
+
+
+    /**
+     * Decode PKCS#1.5 encoding, and return a random value if the padding is not correct.
+     *
+     * @param in    The encrypted block.
+     * @param inOff Offset in the encrypted block.
+     * @param inLen Length of the encrypted block.
+     *              //@param pLen Length of the desired output.
+     * @return The plaintext without padding, or a random value if the padding was incorrect.
+     * @throws InvalidCipherTextException
+     */
+    private byte[] decodeBlockOrRandom(byte[] in, int inOff, int inLen)
+        throws InvalidCipherTextException
+    {
+        if (!forPrivateKey)
+        {
+            throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing");
+        }
+
+        byte[] block = engine.processBlock(in, inOff, inLen);
+        byte[] random;
+        if (this.fallback == null)
+        {
+            random = new byte[this.pLen];
+            this.random.nextBytes(random);
+        }
+        else
+        {
+            random = fallback;
+        }
+
+        byte[] data = (useStrictLength & (block.length != engine.getOutputBlockSize())) ? blockBuffer : block;
+
+		/*
+		 * Check the padding.
+		 */
+        int correct = PKCS1Encoding.checkPkcs1Encoding(data, this.pLen);
+		
+		/*
+		 * Now, to a constant time constant memory copy of the decrypted value
+		 * or the random value, depending on the validity of the padding.
+		 */
+        byte[] result = new byte[this.pLen];
+        for (int i = 0; i < this.pLen; i++)
+        {
+            result[i] = (byte)((data[i + (data.length - pLen)] & (~correct)) | (random[i] & correct));
+        }
+
+        Arrays.fill(data, (byte)0);
+
+        return result;
+    }
+
+    /**
+     * @throws InvalidCipherTextException if the decrypted block is not in PKCS1 format.
+     */
+    private byte[] decodeBlock(
+        byte[] in,
+        int inOff,
+        int inLen)
+        throws InvalidCipherTextException
+    {
+        /*
+         * If the length of the expected plaintext is known, we use a constant-time decryption.
+         * If the decryption fails, we return a random value.
+         */
+        if (this.pLen != -1)
+        {
+            return this.decodeBlockOrRandom(in, inOff, inLen);
+        }
+
+        byte[] block = engine.processBlock(in, inOff, inLen);
+        boolean incorrectLength = (useStrictLength & (block.length != engine.getOutputBlockSize()));
+
+        byte[] data;
+        if (block.length < getOutputBlockSize())
+        {
+            data = blockBuffer;
+        }
+        else
+        {
+            data = block;
+        }
+
+        byte type = data[0];
+
+        boolean badType;
+        if (forPrivateKey)
+        {
+            badType = (type != 2);
+        }
+        else
+        {
+            badType = (type != 1);
+        }
+
+        //
+        // find and extract the message block.
+        //
+        int start = findStart(type, data);
+
+        start++;           // data should start at the next byte
+
+        if (badType | start < HEADER_LENGTH)
+        {
+            Arrays.fill(data, (byte)0);
+            throw new InvalidCipherTextException("block incorrect");
+        }
+
+        // if we get this far, it's likely to be a genuine encoding error
+        if (incorrectLength)
+        {
+            Arrays.fill(data, (byte)0);
+            throw new InvalidCipherTextException("block incorrect size");
+        }
+
+        byte[] result = new byte[data.length - start];
+
+        System.arraycopy(data, start, result, 0, result.length);
+
+        return result;
+    }
+
+    private int findStart(byte type, byte[] block)
+        throws InvalidCipherTextException
+    {
+        int start = -1;
+        boolean padErr = false;
+
+        for (int i = 1; i != block.length; i++)
+        {
+            byte pad = block[i];
+
+            if (pad == 0 & start < 0)
+            {
+                start = i;
+            }
+            padErr |= (type == 1 & start < 0 & pad != (byte)0xff);
+        }
+
+        if (padErr)
+        {
+            return -1;
+        }
+
+        return start;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/AESEngine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/AESEngine.java
new file mode 100644
index 0000000..be2fbff
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/AESEngine.java
@@ -0,0 +1,631 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first.
+ *
+ * The slowest version uses no static tables at all and computes the values in each round.
+ * <p>
+ * This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
+ * @hide This class is not part of the Android public SDK API
+ *
+ */
+public class AESEngine
+    implements BlockCipher
+{
+    // The S box
+    private static final byte[] S = {
+        (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
+        (byte)48,   (byte)1, (byte)103,  (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
+        (byte)202, (byte)130, (byte)201, (byte)125, (byte)250,  (byte)89,  (byte)71, (byte)240,
+        (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
+        (byte)183, (byte)253, (byte)147,  (byte)38,  (byte)54,  (byte)63, (byte)247, (byte)204,
+        (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216,  (byte)49,  (byte)21,
+        (byte)4, (byte)199,  (byte)35, (byte)195,  (byte)24, (byte)150,   (byte)5, (byte)154,
+        (byte)7,  (byte)18, (byte)128, (byte)226, (byte)235,  (byte)39, (byte)178, (byte)117,
+        (byte)9, (byte)131,  (byte)44,  (byte)26,  (byte)27, (byte)110,  (byte)90, (byte)160,
+        (byte)82,  (byte)59, (byte)214, (byte)179,  (byte)41, (byte)227,  (byte)47, (byte)132,
+        (byte)83, (byte)209,   (byte)0, (byte)237,  (byte)32, (byte)252, (byte)177,  (byte)91,
+        (byte)106, (byte)203, (byte)190,  (byte)57,  (byte)74,  (byte)76,  (byte)88, (byte)207,
+        (byte)208, (byte)239, (byte)170, (byte)251,  (byte)67,  (byte)77,  (byte)51, (byte)133,
+        (byte)69, (byte)249,   (byte)2, (byte)127,  (byte)80,  (byte)60, (byte)159, (byte)168,
+        (byte)81, (byte)163,  (byte)64, (byte)143, (byte)146, (byte)157,  (byte)56, (byte)245,
+        (byte)188, (byte)182, (byte)218,  (byte)33,  (byte)16, (byte)255, (byte)243, (byte)210,
+        (byte)205,  (byte)12,  (byte)19, (byte)236,  (byte)95, (byte)151,  (byte)68,  (byte)23,
+        (byte)196, (byte)167, (byte)126,  (byte)61, (byte)100,  (byte)93,  (byte)25, (byte)115,
+        (byte)96, (byte)129,  (byte)79, (byte)220,  (byte)34,  (byte)42, (byte)144, (byte)136,
+        (byte)70, (byte)238, (byte)184,  (byte)20, (byte)222,  (byte)94,  (byte)11, (byte)219,
+        (byte)224,  (byte)50,  (byte)58,  (byte)10,  (byte)73,   (byte)6,  (byte)36,  (byte)92,
+        (byte)194, (byte)211, (byte)172,  (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
+        (byte)231, (byte)200,  (byte)55, (byte)109, (byte)141, (byte)213,  (byte)78, (byte)169,
+        (byte)108,  (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174,   (byte)8,
+        (byte)186, (byte)120,  (byte)37,  (byte)46,  (byte)28, (byte)166, (byte)180, (byte)198,
+        (byte)232, (byte)221, (byte)116,  (byte)31,  (byte)75, (byte)189, (byte)139, (byte)138,
+        (byte)112,  (byte)62, (byte)181, (byte)102,  (byte)72,   (byte)3, (byte)246,  (byte)14,
+        (byte)97,  (byte)53,  (byte)87, (byte)185, (byte)134, (byte)193,  (byte)29, (byte)158,
+        (byte)225, (byte)248, (byte)152,  (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
+        (byte)155,  (byte)30, (byte)135, (byte)233, (byte)206,  (byte)85,  (byte)40, (byte)223,
+        (byte)140, (byte)161, (byte)137,  (byte)13, (byte)191, (byte)230,  (byte)66, (byte)104,
+        (byte)65, (byte)153,  (byte)45,  (byte)15, (byte)176,  (byte)84, (byte)187,  (byte)22,
+    };
+
+    // The inverse S-box
+    private static final byte[] Si = {
+        (byte)82,   (byte)9, (byte)106, (byte)213,  (byte)48,  (byte)54, (byte)165,  (byte)56,
+        (byte)191,  (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
+        (byte)124, (byte)227,  (byte)57, (byte)130, (byte)155,  (byte)47, (byte)255, (byte)135,
+        (byte)52, (byte)142,  (byte)67,  (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
+        (byte)84, (byte)123, (byte)148,  (byte)50, (byte)166, (byte)194,  (byte)35,  (byte)61,
+        (byte)238,  (byte)76, (byte)149,  (byte)11,  (byte)66, (byte)250, (byte)195,  (byte)78,
+        (byte)8,  (byte)46, (byte)161, (byte)102,  (byte)40, (byte)217,  (byte)36, (byte)178,
+        (byte)118,  (byte)91, (byte)162,  (byte)73, (byte)109, (byte)139, (byte)209,  (byte)37,
+        (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152,  (byte)22,
+        (byte)212, (byte)164,  (byte)92, (byte)204,  (byte)93, (byte)101, (byte)182, (byte)146,
+        (byte)108, (byte)112,  (byte)72,  (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
+        (byte)94,  (byte)21,  (byte)70,  (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
+        (byte)144, (byte)216, (byte)171,   (byte)0, (byte)140, (byte)188, (byte)211,  (byte)10,
+        (byte)247, (byte)228,  (byte)88,   (byte)5, (byte)184, (byte)179,  (byte)69,   (byte)6,
+        (byte)208,  (byte)44,  (byte)30, (byte)143, (byte)202,  (byte)63,  (byte)15,   (byte)2,
+        (byte)193, (byte)175, (byte)189,   (byte)3,   (byte)1,  (byte)19, (byte)138, (byte)107,
+        (byte)58, (byte)145,  (byte)17,  (byte)65,  (byte)79, (byte)103, (byte)220, (byte)234,
+        (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
+        (byte)150, (byte)172, (byte)116,  (byte)34, (byte)231, (byte)173,  (byte)53, (byte)133,
+        (byte)226, (byte)249,  (byte)55, (byte)232,  (byte)28, (byte)117, (byte)223, (byte)110,
+        (byte)71, (byte)241,  (byte)26, (byte)113,  (byte)29,  (byte)41, (byte)197, (byte)137,
+        (byte)111, (byte)183,  (byte)98,  (byte)14, (byte)170,  (byte)24, (byte)190,  (byte)27,
+        (byte)252,  (byte)86,  (byte)62,  (byte)75, (byte)198, (byte)210, (byte)121,  (byte)32,
+        (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205,  (byte)90, (byte)244,
+        (byte)31, (byte)221, (byte)168,  (byte)51, (byte)136,   (byte)7, (byte)199,  (byte)49,
+        (byte)177,  (byte)18,  (byte)16,  (byte)89,  (byte)39, (byte)128, (byte)236,  (byte)95,
+        (byte)96,  (byte)81, (byte)127, (byte)169,  (byte)25, (byte)181,  (byte)74,  (byte)13,
+        (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
+        (byte)160, (byte)224,  (byte)59,  (byte)77, (byte)174,  (byte)42, (byte)245, (byte)176,
+        (byte)200, (byte)235, (byte)187,  (byte)60, (byte)131,  (byte)83, (byte)153,  (byte)97,
+        (byte)23,  (byte)43,   (byte)4, (byte)126, (byte)186, (byte)119, (byte)214,  (byte)38,
+        (byte)225, (byte)105,  (byte)20,  (byte)99,  (byte)85,  (byte)33,  (byte)12, (byte)125,
+        };
+
+    // vector used in calculating key schedule (powers of x in GF(256))
+    private static final int[] rcon = {
+         0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+         0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
+
+    // precomputation tables of calculations for rounds
+    private static final int[] T0 =
+    {
+     0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 
+     0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 
+     0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 
+     0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 
+     0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41, 
+     0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 
+     0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 
+     0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, 
+     0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 
+     0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, 
+     0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 
+     0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 
+     0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 
+     0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 
+     0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 
+     0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 
+     0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 
+     0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 
+     0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 
+     0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 
+     0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, 
+     0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 
+     0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, 
+     0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, 
+     0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 
+     0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 
+     0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 
+     0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 
+     0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 
+     0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 
+     0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 
+     0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 
+     0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 
+     0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, 
+     0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 
+     0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 
+     0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 
+     0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 
+     0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, 
+     0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 
+     0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 
+     0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 
+     0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 
+     0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 
+     0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 
+     0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 
+     0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 
+     0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 
+     0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 
+     0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 
+     0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 
+     0x3a16162c};
+
+private static final int[] Tinv0 =
+    {
+     0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 
+     0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 
+     0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 
+     0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 
+     0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, 
+     0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 
+     0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, 
+     0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 
+     0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 
+     0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, 
+     0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 
+     0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, 
+     0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 
+     0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 
+     0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, 
+     0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, 
+     0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 
+     0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, 
+     0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 
+     0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, 
+     0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, 
+     0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 
+     0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4, 
+     0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 
+     0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, 
+     0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 
+     0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 
+     0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 
+     0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, 
+     0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 
+     0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 
+     0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 
+     0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 
+     0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850, 
+     0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 
+     0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 
+     0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, 
+     0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 
+     0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, 
+     0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 
+     0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 
+     0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, 
+     0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 
+     0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 
+     0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, 
+     0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 
+     0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, 
+     0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, 
+     0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 
+     0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 
+     0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 
+     0x4257b8d0};
+
+    private static int shift(int r, int shift)
+    {
+        return (r >>> shift) | (r << -shift);
+    }
+
+    /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+    private static final int m1 = 0x80808080;
+    private static final int m2 = 0x7f7f7f7f;
+    private static final int m3 = 0x0000001b;
+    private static final int m4 = 0xC0C0C0C0;
+    private static final int m5 = 0x3f3f3f3f;
+
+    private static int FFmulX(int x)
+    {
+        return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
+    }
+
+    private static int FFmulX2(int x)
+    {
+        int t0  = (x & m5) << 2;
+        int t1  = (x & m4);
+            t1 ^= (t1 >>> 1);
+        return t0 ^ (t1 >>> 2) ^ (t1 >>> 5);
+    }
+
+    /* 
+       The following defines provide alternative definitions of FFmulX that might
+       give improved performance if a fast 32-bit multiply is not available.
+       
+       private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } 
+       private static final int  m4 = 0x1b1b1b1b;
+       private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } 
+
+    */
+
+    private static int inv_mcol(int x)
+    {
+        int t0, t1;
+        t0  = x;
+        t1  = t0 ^ shift(t0, 8);
+        t0 ^= FFmulX(t1);
+        t1 ^= FFmulX2(t0);
+        t0 ^= t1 ^ shift(t1, 16);
+        return t0;
+    }
+
+    private static int subWord(int x)
+    {
+        return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
+    }
+
+    /**
+     * Calculate the necessary round keys
+     * The number of calculations depends on key size and block size
+     * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+     * This code is written assuming those are the only possible values
+     */
+    private int[][] generateWorkingKey(byte[] key, boolean forEncryption)
+    {
+        int keyLen = key.length;
+        if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0)
+        {
+            throw new IllegalArgumentException("Key length not 128/192/256 bits.");
+        }
+
+        int KC = keyLen >>> 2;
+        ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
+        int[][] W = new int[ROUNDS+1][4];   // 4 words in a block
+
+        switch (KC)
+        {
+        case 4:
+        {
+            int t0 = Pack.littleEndianToInt(key,  0); W[0][0] = t0;
+            int t1 = Pack.littleEndianToInt(key,  4); W[0][1] = t1;
+            int t2 = Pack.littleEndianToInt(key,  8); W[0][2] = t2;
+            int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3;
+
+            for (int i = 1; i <= 10; ++i)
+            {
+                int u = subWord(shift(t3, 8)) ^ rcon[i - 1];
+                t0 ^= u;  W[i][0] = t0;
+                t1 ^= t0; W[i][1] = t1;
+                t2 ^= t1; W[i][2] = t2;
+                t3 ^= t2; W[i][3] = t3;
+            }
+
+            break;
+        }
+        case 6:
+        {
+            int t0 = Pack.littleEndianToInt(key,  0); W[0][0] = t0;
+            int t1 = Pack.littleEndianToInt(key,  4); W[0][1] = t1;
+            int t2 = Pack.littleEndianToInt(key,  8); W[0][2] = t2;
+            int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3;
+            int t4 = Pack.littleEndianToInt(key, 16); W[1][0] = t4;
+            int t5 = Pack.littleEndianToInt(key, 20); W[1][1] = t5;
+
+            int rcon = 1;
+            int u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1;
+            t0 ^= u;  W[1][2] = t0;
+            t1 ^= t0; W[1][3] = t1;
+            t2 ^= t1; W[2][0] = t2;
+            t3 ^= t2; W[2][1] = t3;
+            t4 ^= t3; W[2][2] = t4;
+            t5 ^= t4; W[2][3] = t5;
+
+            for (int i = 3; i < 12; i += 3)
+            {
+                u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1;
+                t0 ^= u;  W[i    ][0] = t0;
+                t1 ^= t0; W[i    ][1] = t1;
+                t2 ^= t1; W[i    ][2] = t2;
+                t3 ^= t2; W[i    ][3] = t3;
+                t4 ^= t3; W[i + 1][0] = t4;
+                t5 ^= t4; W[i + 1][1] = t5;
+                u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1;
+                t0 ^= u;  W[i + 1][2] = t0;
+                t1 ^= t0; W[i + 1][3] = t1;
+                t2 ^= t1; W[i + 2][0] = t2;
+                t3 ^= t2; W[i + 2][1] = t3;
+                t4 ^= t3; W[i + 2][2] = t4;
+                t5 ^= t4; W[i + 2][3] = t5;
+            }
+
+            u = subWord(shift(t5, 8)) ^ rcon;
+            t0 ^= u;  W[12][0] = t0;
+            t1 ^= t0; W[12][1] = t1;
+            t2 ^= t1; W[12][2] = t2;
+            t3 ^= t2; W[12][3] = t3;
+
+            break;
+        }
+        case 8:
+        {
+            int t0 = Pack.littleEndianToInt(key,  0); W[0][0] = t0;
+            int t1 = Pack.littleEndianToInt(key,  4); W[0][1] = t1;
+            int t2 = Pack.littleEndianToInt(key,  8); W[0][2] = t2;
+            int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3;
+            int t4 = Pack.littleEndianToInt(key, 16); W[1][0] = t4;
+            int t5 = Pack.littleEndianToInt(key, 20); W[1][1] = t5;
+            int t6 = Pack.littleEndianToInt(key, 24); W[1][2] = t6;
+            int t7 = Pack.littleEndianToInt(key, 28); W[1][3] = t7;
+
+            int u, rcon = 1;
+
+            for (int i = 2; i < 14; i += 2)
+            {
+                u = subWord(shift(t7, 8)) ^ rcon; rcon <<= 1;
+                t0 ^= u;  W[i    ][0] = t0;
+                t1 ^= t0; W[i    ][1] = t1;
+                t2 ^= t1; W[i    ][2] = t2;
+                t3 ^= t2; W[i    ][3] = t3;
+                u = subWord(t3);
+                t4 ^= u;  W[i + 1][0] = t4;
+                t5 ^= t4; W[i + 1][1] = t5;
+                t6 ^= t5; W[i + 1][2] = t6;
+                t7 ^= t6; W[i + 1][3] = t7;
+            }
+
+            u = subWord(shift(t7, 8)) ^ rcon;
+            t0 ^= u;  W[14][0] = t0;
+            t1 ^= t0; W[14][1] = t1;
+            t2 ^= t1; W[14][2] = t2;
+            t3 ^= t2; W[14][3] = t3;
+
+            break;
+        }
+        default:
+        {
+            throw new IllegalStateException("Should never get here");
+        }
+        }
+
+        if (!forEncryption)
+        {
+            for (int j = 1; j < ROUNDS; j++)
+            {
+                for (int i = 0; i < 4; i++)
+                {
+                    W[j][i] = inv_mcol(W[j][i]);
+                }
+            }
+        }
+
+        return W;
+    }
+
+    private int         ROUNDS;
+    private int[][]     WorkingKey = null;
+    private int         C0, C1, C2, C3;
+    private boolean     forEncryption;
+
+    private byte[]      s;
+
+    private static final int BLOCK_SIZE = 16;
+
+    /**
+     * default constructor - 128 bit block size.
+     */
+    public AESEngine()
+    {
+    }
+
+    /**
+     * initialise an AES cipher.
+     *
+     * @param forEncryption whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean           forEncryption,
+        CipherParameters  params)
+    {
+        if (params instanceof KeyParameter)
+        {
+            WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption);
+            this.forEncryption = forEncryption;
+            if (forEncryption)
+            {
+                s = Arrays.clone(S);
+            }
+            else
+            {
+                s = Arrays.clone(Si);
+            }
+            return;
+        }
+
+        throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName());
+    }
+
+    public String getAlgorithmName()
+    {
+        return "AES";
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    public int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (WorkingKey == null)
+        {
+            throw new IllegalStateException("AES engine not initialised");
+        }
+
+        if ((inOff + (32 / 2)) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + (32 / 2)) > out.length)
+        {
+            throw new OutputLengthException("output buffer too short");
+        }
+
+        if (forEncryption)
+        {
+            unpackBlock(in, inOff);
+            encryptBlock(WorkingKey);
+            packBlock(out, outOff);
+        }
+        else
+        {
+            unpackBlock(in, inOff);
+            decryptBlock(WorkingKey);
+            packBlock(out, outOff);
+        }
+
+        return BLOCK_SIZE;
+    }
+
+    public void reset()
+    {
+    }
+
+    private void unpackBlock(
+        byte[]      bytes,
+        int         off)
+    {
+        int     index = off;
+
+        C0 = (bytes[index++] & 0xff);
+        C0 |= (bytes[index++] & 0xff) << 8;
+        C0 |= (bytes[index++] & 0xff) << 16;
+        C0 |= bytes[index++] << 24;
+
+        C1 = (bytes[index++] & 0xff);
+        C1 |= (bytes[index++] & 0xff) << 8;
+        C1 |= (bytes[index++] & 0xff) << 16;
+        C1 |= bytes[index++] << 24;
+
+        C2 = (bytes[index++] & 0xff);
+        C2 |= (bytes[index++] & 0xff) << 8;
+        C2 |= (bytes[index++] & 0xff) << 16;
+        C2 |= bytes[index++] << 24;
+
+        C3 = (bytes[index++] & 0xff);
+        C3 |= (bytes[index++] & 0xff) << 8;
+        C3 |= (bytes[index++] & 0xff) << 16;
+        C3 |= bytes[index++] << 24;
+    }
+
+    private void packBlock(
+        byte[]      bytes,
+        int         off)
+    {
+        int     index = off;
+
+        bytes[index++] = (byte)C0;
+        bytes[index++] = (byte)(C0 >> 8);
+        bytes[index++] = (byte)(C0 >> 16);
+        bytes[index++] = (byte)(C0 >> 24);
+
+        bytes[index++] = (byte)C1;
+        bytes[index++] = (byte)(C1 >> 8);
+        bytes[index++] = (byte)(C1 >> 16);
+        bytes[index++] = (byte)(C1 >> 24);
+
+        bytes[index++] = (byte)C2;
+        bytes[index++] = (byte)(C2 >> 8);
+        bytes[index++] = (byte)(C2 >> 16);
+        bytes[index++] = (byte)(C2 >> 24);
+
+        bytes[index++] = (byte)C3;
+        bytes[index++] = (byte)(C3 >> 8);
+        bytes[index++] = (byte)(C3 >> 16);
+        bytes[index++] = (byte)(C3 >> 24);
+    }
+
+
+    private void encryptBlock(int[][] KW)
+    {
+        int t0 = this.C0 ^ KW[0][0];
+        int t1 = this.C1 ^ KW[0][1];
+        int t2 = this.C2 ^ KW[0][2];
+
+        int r = 1, r0, r1, r2, r3 = this.C3 ^ KW[0][3];
+        while (r < ROUNDS - 1)
+        {
+            r0 = T0[t0&255] ^ shift(T0[(t1>>8)&255], 24) ^ shift(T0[(t2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0];
+            r1 = T0[t1&255] ^ shift(T0[(t2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(t0>>24)&255], 8) ^ KW[r][1];
+            r2 = T0[t2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(t0>>16)&255], 16) ^ shift(T0[(t1>>24)&255], 8) ^ KW[r][2];
+            r3 = T0[r3&255] ^ shift(T0[(t0>>8)&255], 24) ^ shift(T0[(t1>>16)&255], 16) ^ shift(T0[(t2>>24)&255], 8) ^ KW[r++][3];
+            t0 = T0[r0&255] ^ shift(T0[(r1>>8)&255], 24) ^ shift(T0[(r2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0];
+            t1 = T0[r1&255] ^ shift(T0[(r2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(r0>>24)&255], 8) ^ KW[r][1];
+            t2 = T0[r2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(r0>>16)&255], 16) ^ shift(T0[(r1>>24)&255], 8) ^ KW[r][2];
+            r3 = T0[r3&255] ^ shift(T0[(r0>>8)&255], 24) ^ shift(T0[(r1>>16)&255], 16) ^ shift(T0[(r2>>24)&255], 8) ^ KW[r++][3];
+        }
+
+        r0 = T0[t0&255] ^ shift(T0[(t1>>8)&255], 24) ^ shift(T0[(t2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0];
+        r1 = T0[t1&255] ^ shift(T0[(t2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(t0>>24)&255], 8) ^ KW[r][1];
+        r2 = T0[t2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(t0>>16)&255], 16) ^ shift(T0[(t1>>24)&255], 8) ^ KW[r][2];
+        r3 = T0[r3&255] ^ shift(T0[(t0>>8)&255], 24) ^ shift(T0[(t1>>16)&255], 16) ^ shift(T0[(t2>>24)&255], 8) ^ KW[r++][3];
+
+        // the final round's table is a simple function of S so we don't use a whole other four tables for it
+
+        this.C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((s[(r2>>16)&255]&255)<<16) ^ (s[(r3>>24)&255]<<24) ^ KW[r][0];
+        this.C1 = (s[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (s[(r0>>24)&255]<<24) ^ KW[r][1];
+        this.C2 = (s[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2];
+        this.C3 = (s[r3&255]&255) ^ ((s[(r0>>8)&255]&255)<<8) ^ ((s[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3];
+    }
+
+    private void decryptBlock(int[][] KW)
+    {
+        int t0 = this.C0 ^ KW[ROUNDS][0];
+        int t1 = this.C1 ^ KW[ROUNDS][1];
+        int t2 = this.C2 ^ KW[ROUNDS][2];
+
+        int r = ROUNDS - 1, r0, r1, r2, r3 = this.C3 ^ KW[ROUNDS][3];
+        while (r > 1)
+        {
+            r0 = Tinv0[t0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(t2>>16)&255], 16) ^ shift(Tinv0[(t1>>24)&255], 8) ^ KW[r][0];
+            r1 = Tinv0[t1&255] ^ shift(Tinv0[(t0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(t2>>24)&255], 8) ^ KW[r][1];
+            r2 = Tinv0[t2&255] ^ shift(Tinv0[(t1>>8)&255], 24) ^ shift(Tinv0[(t0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2];
+            r3 = Tinv0[r3&255] ^ shift(Tinv0[(t2>>8)&255], 24) ^ shift(Tinv0[(t1>>16)&255], 16) ^ shift(Tinv0[(t0>>24)&255], 8) ^ KW[r--][3];
+            t0 = Tinv0[r0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(r2>>16)&255], 16) ^ shift(Tinv0[(r1>>24)&255], 8) ^ KW[r][0];
+            t1 = Tinv0[r1&255] ^ shift(Tinv0[(r0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(r2>>24)&255], 8) ^ KW[r][1];
+            t2 = Tinv0[r2&255] ^ shift(Tinv0[(r1>>8)&255], 24) ^ shift(Tinv0[(r0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2];
+            r3 = Tinv0[r3&255] ^ shift(Tinv0[(r2>>8)&255], 24) ^ shift(Tinv0[(r1>>16)&255], 16) ^ shift(Tinv0[(r0>>24)&255], 8) ^ KW[r--][3];
+        }
+
+        r0 = Tinv0[t0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(t2>>16)&255], 16) ^ shift(Tinv0[(t1>>24)&255], 8) ^ KW[r][0];
+        r1 = Tinv0[t1&255] ^ shift(Tinv0[(t0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(t2>>24)&255], 8) ^ KW[r][1];
+        r2 = Tinv0[t2&255] ^ shift(Tinv0[(t1>>8)&255], 24) ^ shift(Tinv0[(t0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2];
+        r3 = Tinv0[r3&255] ^ shift(Tinv0[(t2>>8)&255], 24) ^ shift(Tinv0[(t1>>16)&255], 16) ^ shift(Tinv0[(t0>>24)&255], 8) ^ KW[r][3];
+        
+        // the final round's table is a simple function of Si so we don't use a whole other four tables for it
+
+        this.C0 = (Si[r0&255]&255) ^ ((s[(r3>>8)&255]&255)<<8) ^ ((s[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0];
+        this.C1 = (s[r1&255]&255) ^ ((s[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (s[(r2>>24)&255]<<24) ^ KW[0][1];
+        this.C2 = (s[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (s[(r3>>24)&255]<<24) ^ KW[0][2];
+        this.C3 = (Si[r3&255]&255) ^ ((s[(r2>>8)&255]&255)<<8) ^ ((s[(r1>>16)&255]&255)<<16) ^ (s[(r0>>24)&255]<<24) ^ KW[0][3];
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/AESFastEngine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/AESFastEngine.java
new file mode 100644
index 0000000..38fe1c4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/AESFastEngine.java
@@ -0,0 +1,1012 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first
+ *
+ * The slowest version uses no static tables at all and computes the values in each round
+ * </p>
+ * <p>
+ * This file contains the fast version with 8Kbytes of static tables for round precomputation.
+ * </p>
+ * @deprecated unfortunately this class is has a few side channel issues. In an environment where encryption/decryption may be closely observed it should not be used.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AESFastEngine
+    implements BlockCipher
+{
+    // The S box
+    private static final byte[] S = {
+        (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
+        (byte)48,   (byte)1, (byte)103,  (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
+        (byte)202, (byte)130, (byte)201, (byte)125, (byte)250,  (byte)89,  (byte)71, (byte)240,
+        (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
+        (byte)183, (byte)253, (byte)147,  (byte)38,  (byte)54,  (byte)63, (byte)247, (byte)204,
+        (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216,  (byte)49,  (byte)21,
+        (byte)4, (byte)199,  (byte)35, (byte)195,  (byte)24, (byte)150,   (byte)5, (byte)154,
+        (byte)7,  (byte)18, (byte)128, (byte)226, (byte)235,  (byte)39, (byte)178, (byte)117,
+        (byte)9, (byte)131,  (byte)44,  (byte)26,  (byte)27, (byte)110,  (byte)90, (byte)160,
+        (byte)82,  (byte)59, (byte)214, (byte)179,  (byte)41, (byte)227,  (byte)47, (byte)132,
+        (byte)83, (byte)209,   (byte)0, (byte)237,  (byte)32, (byte)252, (byte)177,  (byte)91,
+        (byte)106, (byte)203, (byte)190,  (byte)57,  (byte)74,  (byte)76,  (byte)88, (byte)207,
+        (byte)208, (byte)239, (byte)170, (byte)251,  (byte)67,  (byte)77,  (byte)51, (byte)133,
+        (byte)69, (byte)249,   (byte)2, (byte)127,  (byte)80,  (byte)60, (byte)159, (byte)168,
+        (byte)81, (byte)163,  (byte)64, (byte)143, (byte)146, (byte)157,  (byte)56, (byte)245,
+        (byte)188, (byte)182, (byte)218,  (byte)33,  (byte)16, (byte)255, (byte)243, (byte)210,
+        (byte)205,  (byte)12,  (byte)19, (byte)236,  (byte)95, (byte)151,  (byte)68,  (byte)23,
+        (byte)196, (byte)167, (byte)126,  (byte)61, (byte)100,  (byte)93,  (byte)25, (byte)115,
+        (byte)96, (byte)129,  (byte)79, (byte)220,  (byte)34,  (byte)42, (byte)144, (byte)136,
+        (byte)70, (byte)238, (byte)184,  (byte)20, (byte)222,  (byte)94,  (byte)11, (byte)219,
+        (byte)224,  (byte)50,  (byte)58,  (byte)10,  (byte)73,   (byte)6,  (byte)36,  (byte)92,
+        (byte)194, (byte)211, (byte)172,  (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
+        (byte)231, (byte)200,  (byte)55, (byte)109, (byte)141, (byte)213,  (byte)78, (byte)169,
+        (byte)108,  (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174,   (byte)8,
+        (byte)186, (byte)120,  (byte)37,  (byte)46,  (byte)28, (byte)166, (byte)180, (byte)198,
+        (byte)232, (byte)221, (byte)116,  (byte)31,  (byte)75, (byte)189, (byte)139, (byte)138,
+        (byte)112,  (byte)62, (byte)181, (byte)102,  (byte)72,   (byte)3, (byte)246,  (byte)14,
+        (byte)97,  (byte)53,  (byte)87, (byte)185, (byte)134, (byte)193,  (byte)29, (byte)158,
+        (byte)225, (byte)248, (byte)152,  (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
+        (byte)155,  (byte)30, (byte)135, (byte)233, (byte)206,  (byte)85,  (byte)40, (byte)223,
+        (byte)140, (byte)161, (byte)137,  (byte)13, (byte)191, (byte)230,  (byte)66, (byte)104,
+        (byte)65, (byte)153,  (byte)45,  (byte)15, (byte)176,  (byte)84, (byte)187,  (byte)22,
+    };
+
+    // The inverse S-box
+    private static final byte[] Si = {
+        (byte)82,   (byte)9, (byte)106, (byte)213,  (byte)48,  (byte)54, (byte)165,  (byte)56,
+        (byte)191,  (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
+        (byte)124, (byte)227,  (byte)57, (byte)130, (byte)155,  (byte)47, (byte)255, (byte)135,
+        (byte)52, (byte)142,  (byte)67,  (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
+        (byte)84, (byte)123, (byte)148,  (byte)50, (byte)166, (byte)194,  (byte)35,  (byte)61,
+        (byte)238,  (byte)76, (byte)149,  (byte)11,  (byte)66, (byte)250, (byte)195,  (byte)78,
+        (byte)8,  (byte)46, (byte)161, (byte)102,  (byte)40, (byte)217,  (byte)36, (byte)178,
+        (byte)118,  (byte)91, (byte)162,  (byte)73, (byte)109, (byte)139, (byte)209,  (byte)37,
+        (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152,  (byte)22,
+        (byte)212, (byte)164,  (byte)92, (byte)204,  (byte)93, (byte)101, (byte)182, (byte)146,
+        (byte)108, (byte)112,  (byte)72,  (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
+        (byte)94,  (byte)21,  (byte)70,  (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
+        (byte)144, (byte)216, (byte)171,   (byte)0, (byte)140, (byte)188, (byte)211,  (byte)10,
+        (byte)247, (byte)228,  (byte)88,   (byte)5, (byte)184, (byte)179,  (byte)69,   (byte)6,
+        (byte)208,  (byte)44,  (byte)30, (byte)143, (byte)202,  (byte)63,  (byte)15,   (byte)2,
+        (byte)193, (byte)175, (byte)189,   (byte)3,   (byte)1,  (byte)19, (byte)138, (byte)107,
+        (byte)58, (byte)145,  (byte)17,  (byte)65,  (byte)79, (byte)103, (byte)220, (byte)234,
+        (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
+        (byte)150, (byte)172, (byte)116,  (byte)34, (byte)231, (byte)173,  (byte)53, (byte)133,
+        (byte)226, (byte)249,  (byte)55, (byte)232,  (byte)28, (byte)117, (byte)223, (byte)110,
+        (byte)71, (byte)241,  (byte)26, (byte)113,  (byte)29,  (byte)41, (byte)197, (byte)137,
+        (byte)111, (byte)183,  (byte)98,  (byte)14, (byte)170,  (byte)24, (byte)190,  (byte)27,
+        (byte)252,  (byte)86,  (byte)62,  (byte)75, (byte)198, (byte)210, (byte)121,  (byte)32,
+        (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205,  (byte)90, (byte)244,
+        (byte)31, (byte)221, (byte)168,  (byte)51, (byte)136,   (byte)7, (byte)199,  (byte)49,
+        (byte)177,  (byte)18,  (byte)16,  (byte)89,  (byte)39, (byte)128, (byte)236,  (byte)95,
+        (byte)96,  (byte)81, (byte)127, (byte)169,  (byte)25, (byte)181,  (byte)74,  (byte)13,
+        (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
+        (byte)160, (byte)224,  (byte)59,  (byte)77, (byte)174,  (byte)42, (byte)245, (byte)176,
+        (byte)200, (byte)235, (byte)187,  (byte)60, (byte)131,  (byte)83, (byte)153,  (byte)97,
+        (byte)23,  (byte)43,   (byte)4, (byte)126, (byte)186, (byte)119, (byte)214,  (byte)38,
+        (byte)225, (byte)105,  (byte)20,  (byte)99,  (byte)85,  (byte)33,  (byte)12, (byte)125,
+        };
+
+    // vector used in calculating key schedule (powers of x in GF(256))
+    private static final int[] rcon = {
+         0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+         0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
+
+    // precomputation tables of calculations for rounds
+    private static final int[] T =
+    {
+     // T0
+     0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 
+     0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 
+     0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 
+     0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 
+     0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41, 
+     0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 
+     0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 
+     0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, 
+     0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 
+     0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, 
+     0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 
+     0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 
+     0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 
+     0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 
+     0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 
+     0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 
+     0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 
+     0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 
+     0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 
+     0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 
+     0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, 
+     0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 
+     0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, 
+     0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, 
+     0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 
+     0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 
+     0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 
+     0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 
+     0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 
+     0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 
+     0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 
+     0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 
+     0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 
+     0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, 
+     0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 
+     0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 
+     0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 
+     0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 
+     0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, 
+     0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 
+     0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 
+     0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 
+     0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 
+     0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 
+     0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 
+     0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 
+     0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 
+     0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 
+     0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 
+     0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 
+     0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 
+     0x3a16162c, 
+
+     // T1
+     0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 
+     0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203, 
+     0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 
+     0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 
+     0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec, 
+     0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 
+     0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, 
+     0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, 
+     0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 
+     0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552, 
+     0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, 
+     0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 
+     0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b, 
+     0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 
+     0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 
+     0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, 
+     0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, 
+     0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, 
+     0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 
+     0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 
+     0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, 
+     0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 
+     0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 
+     0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, 
+     0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 
+     0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814, 
+     0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 
+     0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 
+     0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, 
+     0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 
+     0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, 
+     0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, 
+     0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, 
+     0x06060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e, 
+     0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 
+     0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 
+     0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, 
+     0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 
+     0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, 
+     0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, 
+     0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 
+     0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, 
+     0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, 
+     0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 
+     0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, 
+     0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 
+     0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 
+     0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, 
+     0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 
+     0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, 
+     0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 
+     0x16162c3a, 
+
+     // T2
+     0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 
+     0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301, 
+     0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 
+     0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 
+     0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad, 
+     0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 
+     0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, 
+     0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, 
+     0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 
+     0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7, 
+     0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, 
+     0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 
+     0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09, 
+     0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 
+     0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 
+     0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, 
+     0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, 
+     0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, 
+     0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 
+     0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 
+     0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, 
+     0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 
+     0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040, 
+     0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, 
+     0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 
+     0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c, 
+     0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 
+     0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 
+     0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, 
+     0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 
+     0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, 
+     0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, 
+     0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, 
+     0x060c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3, 
+     0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 
+     0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 
+     0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, 
+     0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 
+     0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, 
+     0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, 
+     0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 
+     0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, 
+     0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, 
+     0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 
+     0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, 
+     0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 
+     0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, 
+     0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, 
+     0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 
+     0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, 
+     0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 
+     0x162c3a16, 
+
+     // T3
+     0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 
+     0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101, 
+     0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 
+     0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 
+     0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad, 
+     0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 
+     0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 
+     0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, 
+     0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 
+     0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7, 
+     0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, 
+     0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 
+     0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, 
+     0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 
+     0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 
+     0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, 
+     0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, 
+     0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, 
+     0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 
+     0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 
+     0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, 
+     0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 
+     0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040, 
+     0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, 
+     0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 
+     0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, 
+     0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 
+     0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 
+     0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, 
+     0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 
+     0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 
+     0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, 
+     0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 
+     0x0c0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3, 
+     0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 
+     0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 
+     0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, 
+     0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 
+     0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, 
+     0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, 
+     0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 
+     0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e, 
+     0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, 
+     0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 
+     0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, 
+     0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 
+     0x07898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, 
+     0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, 
+     0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 
+     0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, 
+     0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 
+     0x2c3a1616};
+
+    private static final int[] Tinv =
+    {
+     // Tinv0
+     0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 
+     0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 
+     0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 
+     0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 
+     0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, 
+     0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 
+     0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, 
+     0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 
+     0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 
+     0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, 
+     0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 
+     0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, 
+     0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 
+     0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 
+     0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, 
+     0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, 
+     0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 
+     0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, 
+     0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 
+     0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, 
+     0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, 
+     0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 
+     0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4, 
+     0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 
+     0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, 
+     0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 
+     0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 
+     0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 
+     0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, 
+     0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 
+     0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 
+     0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 
+     0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 
+     0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850, 
+     0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 
+     0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 
+     0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, 
+     0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 
+     0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, 
+     0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 
+     0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 
+     0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, 
+     0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 
+     0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 
+     0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, 
+     0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 
+     0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, 
+     0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, 
+     0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 
+     0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 
+     0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 
+     0x4257b8d0, 
+
+     // Tinv1
+     0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 
+     0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6, 
+     0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 
+     0xa362b58f, 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, 
+     0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7, 
+     0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, 
+     0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b, 
+     0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, 
+     0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, 
+     0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, 
+     0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357, 
+     0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5, 
+     0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, 
+     0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, 
+     0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, 
+     0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, 
+     0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5, 
+     0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697, 
+     0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 
+     0xeec879db, 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, 
+     0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb, 
+     0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, 
+     0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 
+     0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, 
+     0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b, 
+     0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c, 
+     0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 
+     0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, 
+     0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d, 
+     0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, 
+     0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, 
+     0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, 
+     0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf, 
+     0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d, 
+     0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 
+     0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, 
+     0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, 
+     0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 
+     0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x099fead4, 
+     0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, 
+     0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, 
+     0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, 
+     0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 
+     0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 
+     0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c, 
+     0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, 
+     0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, 
+     0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, 
+     0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 
+     0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de, 
+     0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, 
+     0x57b8d042, 
+
+     // Tinv2
+     0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 
+     0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, 
+     0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 
+     0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, 
+     0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f, 
+     0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, 
+     0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e, 
+     0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, 
+     0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, 
+     0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, 0x48705868, 0x458f19fd, 
+     0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 
+     0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, 
+     0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c, 
+     0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be, 
+     0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 
+     0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, 
+     0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, 
+     0xc471055d, 0x06046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9, 
+     0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 
+     0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, 
+     0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0x0efdfbff, 
+     0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6, 
+     0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7, 0xeeb4d296, 
+     0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, 
+     0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d, 
+     0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, 
+     0x99eebbdd, 0x7fa3fd60, 0x01f79f26, 0x725cbcf5, 0x6644c53b, 
+     0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, 
+     0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, 
+     0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, 
+     0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, 
+     0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, 
+     0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, 
+     0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92, 
+     0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 
+     0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, 
+     0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, 
+     0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 
+     0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409, 
+     0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, 
+     0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x04f14a98, 
+     0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, 
+     0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 
+     0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, 
+     0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61, 
+     0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, 
+     0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, 
+     0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, 
+     0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 
+     0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3, 
+     0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, 
+     0xb8d04257, 
+
+     // Tinv3
+     0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 
+     0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, 
+     0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 
+     0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, 
+     0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x03e75f8f, 
+     0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, 
+     0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58, 
+     0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, 
+     0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, 
+     0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, 
+     0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, 
+     0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, 
+     0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf, 
+     0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05, 
+     0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x0532e18a, 
+     0xa475ebf6, 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, 
+     0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, 
+     0x71055dc4, 0x046fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd, 
+     0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19, 
+     0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, 
+     0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e, 
+     0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c, 
+     0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757, 0xb4d296ee, 
+     0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, 
+     0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09, 
+     0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, 
+     0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, 
+     0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, 
+     0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a, 
+     0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, 
+     0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, 
+     0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, 
+     0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 
+     0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278, 
+     0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 
+     0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, 
+     0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, 
+     0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 
+     0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f, 
+     0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, 
+     0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, 
+     0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, 
+     0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 
+     0x467f5165, 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, 
+     0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7, 
+     0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, 
+     0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 
+     0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, 
+     0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 
+     0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x08deb30c, 
+     0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 
+     0xd04257b8};
+
+    private static int shift(int r, int shift)
+    {
+        return (r >>> shift) | (r << -shift);
+    }
+
+    /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+    private static final int m1 = 0x80808080;
+    private static final int m2 = 0x7f7f7f7f;
+    private static final int m3 = 0x0000001b;
+    private static final int m4 = 0xC0C0C0C0;
+    private static final int m5 = 0x3f3f3f3f;
+
+    private static int FFmulX(int x)
+    {
+        return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
+    }
+
+    private static int FFmulX2(int x)
+    {
+        int t0  = (x & m5) << 2;
+        int t1  = (x & m4);
+            t1 ^= (t1 >>> 1);
+        return t0 ^ (t1 >>> 2) ^ (t1 >>> 5);
+    }
+
+    /* 
+       The following defines provide alternative definitions of FFmulX that might
+       give improved performance if a fast 32-bit multiply is not available.
+       
+       private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } 
+       private static final int  m4 = 0x1b1b1b1b;
+       private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } 
+
+    */
+
+    private static int inv_mcol(int x)
+    {
+        int t0, t1;
+        t0  = x;
+        t1  = t0 ^ shift(t0, 8);
+        t0 ^= FFmulX(t1);
+        t1 ^= FFmulX2(t0);
+        t0 ^= t1 ^ shift(t1, 16);
+        return t0;
+    }
+
+    private static int subWord(int x)
+    {
+        int i0 = x, i1 = x >>> 8, i2 = x >>> 16, i3 = x >>> 24;
+        i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255;
+        return i0 | i1 << 8 | i2 << 16 | i3 << 24;
+    }
+
+    /**
+     * Calculate the necessary round keys
+     * The number of calculations depends on key size and block size
+     * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+     * This code is written assuming those are the only possible values
+     */
+    private int[][] generateWorkingKey(byte[] key, boolean forEncryption)
+    {
+        int keyLen = key.length;
+        if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0)
+        {
+            throw new IllegalArgumentException("Key length not 128/192/256 bits.");
+        }
+
+        int KC = keyLen >>> 2;
+        ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
+        int[][] W = new int[ROUNDS+1][4];   // 4 words in a block
+
+        switch (KC)
+        {
+        case 4:
+        {
+            int t0 = Pack.littleEndianToInt(key,  0); W[0][0] = t0;
+            int t1 = Pack.littleEndianToInt(key,  4); W[0][1] = t1;
+            int t2 = Pack.littleEndianToInt(key,  8); W[0][2] = t2;
+            int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3;
+
+            for (int i = 1; i <= 10; ++i)
+            {
+                int u = subWord(shift(t3, 8)) ^ rcon[i - 1];
+                t0 ^= u;  W[i][0] = t0;
+                t1 ^= t0; W[i][1] = t1;
+                t2 ^= t1; W[i][2] = t2;
+                t3 ^= t2; W[i][3] = t3;
+            }
+
+            break;
+        }
+        case 6:
+        {
+            int t0 = Pack.littleEndianToInt(key,  0); W[0][0] = t0;
+            int t1 = Pack.littleEndianToInt(key,  4); W[0][1] = t1;
+            int t2 = Pack.littleEndianToInt(key,  8); W[0][2] = t2;
+            int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3;
+            int t4 = Pack.littleEndianToInt(key, 16); W[1][0] = t4;
+            int t5 = Pack.littleEndianToInt(key, 20); W[1][1] = t5;
+
+            int rcon = 1;
+            int u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1;
+            t0 ^= u;  W[1][2] = t0;
+            t1 ^= t0; W[1][3] = t1;
+            t2 ^= t1; W[2][0] = t2;
+            t3 ^= t2; W[2][1] = t3;
+            t4 ^= t3; W[2][2] = t4;
+            t5 ^= t4; W[2][3] = t5;
+
+            for (int i = 3; i < 12; i += 3)
+            {
+                u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1;
+                t0 ^= u;  W[i    ][0] = t0;
+                t1 ^= t0; W[i    ][1] = t1;
+                t2 ^= t1; W[i    ][2] = t2;
+                t3 ^= t2; W[i    ][3] = t3;
+                t4 ^= t3; W[i + 1][0] = t4;
+                t5 ^= t4; W[i + 1][1] = t5;
+                u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1;
+                t0 ^= u;  W[i + 1][2] = t0;
+                t1 ^= t0; W[i + 1][3] = t1;
+                t2 ^= t1; W[i + 2][0] = t2;
+                t3 ^= t2; W[i + 2][1] = t3;
+                t4 ^= t3; W[i + 2][2] = t4;
+                t5 ^= t4; W[i + 2][3] = t5;
+            }
+
+            u = subWord(shift(t5, 8)) ^ rcon;
+            t0 ^= u;  W[12][0] = t0;
+            t1 ^= t0; W[12][1] = t1;
+            t2 ^= t1; W[12][2] = t2;
+            t3 ^= t2; W[12][3] = t3;
+
+            break;
+        }
+        case 8:
+        {
+            int t0 = Pack.littleEndianToInt(key,  0); W[0][0] = t0;
+            int t1 = Pack.littleEndianToInt(key,  4); W[0][1] = t1;
+            int t2 = Pack.littleEndianToInt(key,  8); W[0][2] = t2;
+            int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3;
+            int t4 = Pack.littleEndianToInt(key, 16); W[1][0] = t4;
+            int t5 = Pack.littleEndianToInt(key, 20); W[1][1] = t5;
+            int t6 = Pack.littleEndianToInt(key, 24); W[1][2] = t6;
+            int t7 = Pack.littleEndianToInt(key, 28); W[1][3] = t7;
+
+            int u, rcon = 1;
+
+            for (int i = 2; i < 14; i += 2)
+            {
+                u = subWord(shift(t7, 8)) ^ rcon; rcon <<= 1;
+                t0 ^= u;  W[i    ][0] = t0;
+                t1 ^= t0; W[i    ][1] = t1;
+                t2 ^= t1; W[i    ][2] = t2;
+                t3 ^= t2; W[i    ][3] = t3;
+                u = subWord(t3);
+                t4 ^= u;  W[i + 1][0] = t4;
+                t5 ^= t4; W[i + 1][1] = t5;
+                t6 ^= t5; W[i + 1][2] = t6;
+                t7 ^= t6; W[i + 1][3] = t7;
+            }
+
+            u = subWord(shift(t7, 8)) ^ rcon;
+            t0 ^= u;  W[14][0] = t0;
+            t1 ^= t0; W[14][1] = t1;
+            t2 ^= t1; W[14][2] = t2;
+            t3 ^= t2; W[14][3] = t3;
+
+            break;
+        }
+        default:
+        {
+            throw new IllegalStateException("Should never get here");
+        }
+        }
+
+        if (!forEncryption)
+        {
+            for (int j = 1; j < ROUNDS; j++)
+            {
+                for (int i = 0; i < 4; i++)
+                {
+                    W[j][i] = inv_mcol(W[j][i]);
+                }
+            }
+        }
+
+        return W;
+    }
+
+    private int         ROUNDS;
+    private int[][]     WorkingKey = null;
+    private int         C0, C1, C2, C3;
+    private boolean     forEncryption;
+
+    private static final int BLOCK_SIZE = 16;
+
+    /**
+     * default constructor - 128 bit block size.
+     */
+    public AESFastEngine()
+    {
+    }
+
+    /**
+     * initialise an AES cipher.
+     *
+     * @param forEncryption whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean           forEncryption,
+        CipherParameters  params)
+    {
+        if (params instanceof KeyParameter)
+        {
+            WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption);
+            this.forEncryption = forEncryption;
+            return;
+        }
+
+        throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName());
+    }
+
+    public String getAlgorithmName()
+    {
+        return "AES";
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    public int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (WorkingKey == null)
+        {
+            throw new IllegalStateException("AES engine not initialised");
+        }
+
+        if ((inOff + (32 / 2)) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + (32 / 2)) > out.length)
+        {
+            throw new OutputLengthException("output buffer too short");
+        }
+
+        unpackBlock(in, inOff);
+
+        if (forEncryption)
+        {
+            encryptBlock(WorkingKey);
+        }
+        else
+        {
+            decryptBlock(WorkingKey);
+        }
+
+        packBlock(out, outOff);
+
+        return BLOCK_SIZE;
+    }
+
+    public void reset()
+    {
+    }
+
+    private void unpackBlock(byte[] bytes, int off)
+    {
+        this.C0 = Pack.littleEndianToInt(bytes, off);
+        this.C1 = Pack.littleEndianToInt(bytes, off + 4);
+        this.C2 = Pack.littleEndianToInt(bytes, off + 8);
+        this.C3 = Pack.littleEndianToInt(bytes, off + 12);
+    }
+
+    private void packBlock(byte[] bytes, int off)
+    {
+        Pack.intToLittleEndian(this.C0, bytes, off);
+        Pack.intToLittleEndian(this.C1, bytes, off + 4);
+        Pack.intToLittleEndian(this.C2, bytes, off + 8);
+        Pack.intToLittleEndian(this.C3, bytes, off + 12);
+    }
+
+    private void encryptBlock(int[][] KW)
+    {
+        int t0 = this.C0 ^ KW[0][0];
+        int t1 = this.C1 ^ KW[0][1];
+        int t2 = this.C2 ^ KW[0][2];
+
+        /*
+         * Fast engine has precomputed rotr(T0, 8/16/24) tables T1/T2/T3.
+         *
+         * Placing all precomputes in one array requires offsets additions for 8/16/24 rotations but
+         * avoids additional array range checks on 3 more arrays (which on HotSpot are more
+         * expensive than the offset additions).
+         */
+        int r = 1, r0, r1, r2, r3 = this.C3 ^ KW[0][3];
+        int i0, i1, i2, i3;
+
+        while (r < ROUNDS - 1)
+        {
+            i0 = t0; i1 = t1 >>> 8; i2 = t2 >>> 16; i3 = r3 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            r0 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][0];
+
+            i0 = t1; i1 = t2 >>> 8; i2 = r3 >>> 16; i3 = t0 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            r1 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][1];
+
+            i0 = t2; i1 = r3 >>> 8; i2 = t0 >>> 16; i3 = t1 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            r2 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][2];
+
+            i0 = r3; i1 = t0 >>> 8; i2 = t1 >>> 16; i3 = t2 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            r3 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r++][3];
+
+            i0 = r0; i1 = r1 >>> 8; i2 = r2 >>> 16; i3 = r3 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            t0 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][0];
+
+            i0 = r1; i1 = r2 >>> 8; i2 = r3 >>> 16; i3 = r0 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            t1 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][1];
+
+            i0 = r2; i1 = r3 >>> 8; i2 = r0 >>> 16; i3 = r1 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            t2 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][2];
+
+            i0 = r3; i1 = r0 >>> 8; i2 = r1 >>> 16; i3 = r2 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            r3 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r++][3];
+        }
+
+        i0 = t0; i1 = t1 >>> 8; i2 = t2 >>> 16; i3 = r3 >>> 24;
+        i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+        r0 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][0];
+
+        i0 = t1; i1 = t2 >>> 8; i2 = r3 >>> 16; i3 = t0 >>> 24;
+        i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+        r1 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][1];
+
+        i0 = t2; i1 = r3 >>> 8; i2 = t0 >>> 16; i3 = t1 >>> 24;
+        i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+        r2 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][2];
+
+        i0 = r3; i1 = t0 >>> 8; i2 = t1 >>> 16; i3 = t2 >>> 24;
+        i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+        r3 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r++][3];
+
+        // the final round's table is a simple function of S so we don't use a whole other four tables for it
+
+        i0 = r0; i1 = r1 >>> 8; i2 = r2 >>> 16; i3 = r3 >>> 24;
+        i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255;
+        this.C0 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][0];
+
+        i0 = r1; i1 = r2 >>> 8; i2 = r3 >>> 16; i3 = r0 >>> 24;
+        i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255;
+        this.C1 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][1];
+
+        i0 = r2; i1 = r3 >>> 8; i2 = r0 >>> 16; i3 = r1 >>> 24;
+        i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255;
+        this.C2 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][2];
+
+        i0 = r3; i1 = r0 >>> 8; i2 = r1 >>> 16; i3 = r2 >>> 24;
+        i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255;
+        this.C3 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][3];
+    }
+
+    private void decryptBlock(int[][] KW)
+    {
+        int t0 = this.C0 ^ KW[ROUNDS][0];
+        int t1 = this.C1 ^ KW[ROUNDS][1];
+        int t2 = this.C2 ^ KW[ROUNDS][2];
+
+        int r = ROUNDS - 1, r0, r1, r2, r3 = this.C3 ^ KW[ROUNDS][3];
+        int i0, i1, i2, i3;
+
+        while (r > 1)
+        {
+            i0 = t0; i1 = r3 >>> 8; i2 = t2 >>> 16; i3 = t1 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            r0 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][0];
+
+            i0 = t1; i1 = t0 >>> 8; i2 = r3 >>> 16; i3 = t2 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            r1 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][1];
+
+            i0 = t2; i1 = t1 >>> 8; i2 = t0 >>> 16; i3 = r3 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            r2 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][2];
+
+            i0 = r3; i1 = t2 >>> 8; i2 = t1 >>> 16; i3 = t0 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            r3 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r--][3];
+
+            i0 = r0; i1 = r3 >>> 8; i2 = r2 >>> 16; i3 = r1 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            t0 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][0];
+
+            i0 = r1; i1 = r0 >>> 8; i2 = r3 >>> 16; i3 = r2 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            t1 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][1];
+
+            i0 = r2; i1 = r1 >>> 8; i2 = r0 >>> 16; i3 = r3 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            t2 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][2];
+
+            i0 = r3; i1 = r2 >>> 8; i2 = r1 >>> 16; i3 = r0 >>> 24;
+            i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+            r3 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r--][3];
+        }
+
+        i0 = t0; i1 = r3 >>> 8; i2 = t2 >>> 16; i3 = t1 >>> 24;
+        i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+        r0 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][0];
+
+        i0 = t1; i1 = t0 >>> 8; i2 = r3 >>> 16; i3 = t2 >>> 24;
+        i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+        r1 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][1];
+
+        i0 = t2; i1 = t1 >>> 8; i2 = t0 >>> 16; i3 = r3 >>> 24;
+        i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+        r2 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][2];
+
+        i0 = r3; i1 = t2 >>> 8; i2 = t1 >>> 16; i3 = t0 >>> 24;
+        i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255;
+        r3 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][3];
+
+        // the final round's table is a simple function of Si so we don't use a whole other four tables for it
+
+        i0 = r0; i1 = r3 >>> 8; i2 = r2 >>> 16; i3 = r1 >>> 24;
+        i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255;
+        this.C0 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][0];
+
+        i0 = r1; i1 = r0 >>> 8; i2 = r3 >>> 16; i3 = r2 >>> 24;
+        i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255;
+        this.C1 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][1];
+
+        i0 = r2; i1 = r1 >>> 8; i2 = r0 >>> 16; i3 = r3 >>> 24;
+        i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255;
+        this.C2 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][2];
+
+        i0 = r3; i1 = r2 >>> 8; i2 = r1 >>> 16; i3 = r0 >>> 24;
+        i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255;
+        this.C3 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][3];
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/AESWrapEngine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/AESWrapEngine.java
new file mode 100644
index 0000000..6a54a93
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/AESWrapEngine.java
@@ -0,0 +1,31 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+/**
+ * an implementation of the AES Key Wrapper from the NIST Key Wrap
+ * Specification.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AESWrapEngine
+    extends RFC3394WrapEngine
+{
+    /**
+     * Create a regular AESWrapEngine specifying the encrypt for wrapping, decrypt for unwrapping.
+     */
+    public AESWrapEngine()
+    {
+        super(new AESEngine());
+    }
+
+    /**
+     * Create an AESWrapEngine where the underlying cipher is set to decrypt for wrapping, encrypt for unwrapping.
+     *
+     * @param useReverseDirection true if underlying cipher should be used in decryption mode, false otherwise.
+     */
+    public AESWrapEngine(boolean useReverseDirection)
+    {
+        super(new AESEngine(), useReverseDirection);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/BlowfishEngine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/BlowfishEngine.java
new file mode 100644
index 0000000..73ee165
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/BlowfishEngine.java
@@ -0,0 +1,579 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * A class that provides Blowfish key encryption operations,
+ * such as encoding data and generating keys.
+ * All the algorithms herein are from Applied Cryptography
+ * and implement a simplified cryptography interface.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class BlowfishEngine
+implements BlockCipher
+{
+    private final static int[] 
+        KP = {
+                0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
+                0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
+                0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
+                0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
+                0x9216D5D9, 0x8979FB1B
+             },
+
+        KS0 = {
+                0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
+                0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
+                0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
+                0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
+                0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE,
+                0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
+                0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
+                0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
+                0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
+                0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440,
+                0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE,
+                0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
+                0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E,
+                0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
+                0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
+                0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
+                0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88,
+                0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
+                0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E,
+                0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
+                0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
+                0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98,
+                0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88,
+                0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
+                0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6,
+                0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D,
+                0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
+                0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
+                0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA,
+                0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
+                0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F,
+                0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
+                0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
+                0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB,
+                0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
+                0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
+                0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB,
+                0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82,
+                0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
+                0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
+                0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0,
+                0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
+                0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790,
+                0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
+                0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
+                0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0,
+                0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7,
+                0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
+                0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
+                0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1,
+                0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
+                0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
+                0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477,
+                0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
+                0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49,
+                0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
+                0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
+                0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5,
+                0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41,
+                0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
+                0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
+                0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915,
+                0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
+                0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
+            },
+
+        KS1 = {
+                0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
+                0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
+                0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1,
+                0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
+                0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
+                0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
+                0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
+                0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
+                0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
+                0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8,
+                0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
+                0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
+                0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701,
+                0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
+                0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41,
+                0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
+                0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
+                0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
+                0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E,
+                0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
+                0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
+                0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2,
+                0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
+                0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
+                0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B,
+                0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
+                0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
+                0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
+                0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
+                0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A,
+                0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4,
+                0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
+                0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66,
+                0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28,
+                0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
+                0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
+                0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510,
+                0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
+                0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14,
+                0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
+                0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
+                0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
+                0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8,
+                0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
+                0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
+                0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696,
+                0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
+                0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
+                0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
+                0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
+                0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105,
+                0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
+                0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
+                0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
+                0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00,
+                0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
+                0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB,
+                0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E,
+                0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
+                0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
+                0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9,
+                0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
+                0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
+                0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
+            },
+
+        KS2 = {
+                0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
+                0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
+                0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF,
+                0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
+                0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45,
+                0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504,
+                0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
+                0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
+                0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
+                0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
+                0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42,
+                0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
+                0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
+                0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
+                0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527,
+                0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
+                0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33,
+                0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
+                0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
+                0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
+                0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
+                0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
+                0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B,
+                0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
+                0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
+                0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728,
+                0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
+                0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
+                0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37,
+                0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D,
+                0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
+                0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
+                0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3,
+                0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
+                0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
+                0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
+                0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
+                0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9,
+                0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A,
+                0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
+                0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D,
+                0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
+                0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
+                0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
+                0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
+                0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
+                0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2,
+                0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
+                0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
+                0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633,
+                0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10,
+                0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
+                0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52,
+                0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
+                0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
+                0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
+                0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634,
+                0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
+                0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24,
+                0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
+                0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
+                0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C,
+                0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
+                0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
+            },
+
+        KS3 = {
+                0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
+                0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
+                0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
+                0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
+                0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8,
+                0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
+                0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
+                0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
+                0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
+                0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6,
+                0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9,
+                0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
+                0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593,
+                0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
+                0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
+                0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
+                0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B,
+                0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
+                0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C,
+                0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
+                0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
+                0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319,
+                0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB,
+                0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
+                0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991,
+                0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32,
+                0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
+                0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
+                0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE,
+                0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
+                0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5,
+                0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
+                0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
+                0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D,
+                0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
+                0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
+                0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8,
+                0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
+                0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
+                0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
+                0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
+                0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
+                0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
+                0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
+                0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
+                0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
+                0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
+                0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
+                0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
+                0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
+                0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
+                0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
+                0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
+                0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
+                0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
+                0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
+                0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
+                0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
+                0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
+                0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
+                0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
+                0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
+                0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
+                0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
+            };
+
+    //====================================
+    // Useful constants
+    //====================================
+
+    private static final int    ROUNDS = 16;
+    private static final int    BLOCK_SIZE = 8;  // bytes = 64 bits
+    private static final int    SBOX_SK = 256;
+    private static final int    P_SZ = ROUNDS+2;
+
+    private final int[] S0, S1, S2, S3;     // the s-boxes
+    private final int[] P;                  // the p-array
+
+    private boolean encrypting = false;
+
+    private byte[] workingKey = null;
+
+    public BlowfishEngine()
+    {
+        S0 = new int[SBOX_SK];
+        S1 = new int[SBOX_SK];
+        S2 = new int[SBOX_SK];
+        S3 = new int[SBOX_SK];
+        P = new int[P_SZ];
+    }
+
+    /**
+     * initialise a Blowfish cipher.
+     *
+     * @param encrypting whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             encrypting,
+        CipherParameters    params)
+    {
+        if (params instanceof KeyParameter)
+        {
+            this.encrypting = encrypting;
+            this.workingKey = ((KeyParameter)params).getKey();
+            setKey(this.workingKey);
+
+            return;
+        }
+
+        throw new IllegalArgumentException("invalid parameter passed to Blowfish init - " + params.getClass().getName());
+    }
+
+    public String getAlgorithmName()
+    {
+        return "Blowfish";
+    }
+
+    public final int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (workingKey == null)
+        {
+            throw new IllegalStateException("Blowfish not initialised");
+        }
+
+        if ((inOff + BLOCK_SIZE) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + BLOCK_SIZE) > out.length)
+        {
+            throw new OutputLengthException("output buffer too short");
+        }
+
+        if (encrypting)
+        {
+            encryptBlock(in, inOff, out, outOff);
+        }
+        else
+        {    
+            decryptBlock(in, inOff, out, outOff);
+        }
+
+        return BLOCK_SIZE;
+    }
+
+    public void reset()
+    {
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    //==================================
+    // Private Implementation
+    //==================================
+
+    private int F(int x)
+    {
+        return (((S0[(x >>> 24)] + S1[(x >>> 16) & 0xff])
+                            ^ S2[(x >>> 8) & 0xff]) + S3[x & 0xff]);
+    }
+
+    /**
+     * apply the encryption cycle to each value pair in the table.
+     */
+    private void processTable(
+        int     xl,
+        int     xr,
+        int[]   table)
+    {
+        int size = table.length;
+
+        for (int s = 0; s < size; s += 2)
+        {
+            xl ^= P[0];
+
+            for (int i = 1; i < ROUNDS; i += 2)
+            {
+                xr ^= F(xl) ^ P[i];
+                xl ^= F(xr) ^ P[i + 1];
+            }
+
+            xr ^= P[ROUNDS + 1];
+
+            table[s] = xr;
+            table[s + 1] = xl;
+
+            xr = xl;            // end of cycle swap
+            xl = table[s];
+        }
+    }
+
+    private void setKey(byte[] key)
+    {
+        /*
+         * - comments are from _Applied Crypto_, Schneier, p338
+         * please be careful comparing the two, AC numbers the
+         * arrays from 1, the enclosed code from 0.
+         *
+         * (1)
+         * Initialise the S-boxes and the P-array, with a fixed string
+         * This string contains the hexadecimal digits of pi (3.141...)
+         */
+        System.arraycopy(KS0, 0, S0, 0, SBOX_SK);
+        System.arraycopy(KS1, 0, S1, 0, SBOX_SK);
+        System.arraycopy(KS2, 0, S2, 0, SBOX_SK);
+        System.arraycopy(KS3, 0, S3, 0, SBOX_SK);
+
+        System.arraycopy(KP, 0, P, 0, P_SZ);
+
+        /*
+         * (2)
+         * Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with the
+         * second 32-bits of the key, and so on for all bits of the key
+         * (up to P[17]).  Repeatedly cycle through the key bits until the
+         * entire P-array has been XOR-ed with the key bits
+         */
+        int keyLength = key.length;
+        int keyIndex = 0;
+
+        for (int i=0; i < P_SZ; i++)
+        {
+            // get the 32 bits of the key, in 4 * 8 bit chunks
+            int data = 0x0000000;
+            for (int j=0; j < 4; j++)
+            {
+                // create a 32 bit block
+                data = (data << 8) | (key[keyIndex++] & 0xff);
+
+                // wrap when we get to the end of the key
+                if (keyIndex >= keyLength)
+                {
+                    keyIndex = 0;
+                }
+            }
+            // XOR the newly created 32 bit chunk onto the P-array
+            P[i] ^= data;
+        }
+
+        /*
+         * (3)
+         * Encrypt the all-zero string with the Blowfish algorithm, using
+         * the subkeys described in (1) and (2)
+         *
+         * (4)
+         * Replace P1 and P2 with the output of step (3)
+         *
+         * (5)
+         * Encrypt the output of step(3) using the Blowfish algorithm,
+         * with the modified subkeys.
+         *
+         * (6)
+         * Replace P3 and P4 with the output of step (5)
+         *
+         * (7)
+         * Continue the process, replacing all elements of the P-array
+         * and then all four S-boxes in order, with the output of the
+         * continuously changing Blowfish algorithm
+         */
+
+        processTable(0, 0, P);
+        processTable(P[P_SZ - 2], P[P_SZ - 1], S0);
+        processTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);
+        processTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);
+        processTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);
+    }
+
+    /**
+     * Encrypt the given input starting at the given offset and place
+     * the result in the provided buffer starting at the given offset.
+     * The input will be an exact multiple of our blocksize.
+     */
+    private void encryptBlock(
+        byte[]  src,
+        int     srcIndex,
+        byte[]  dst,
+        int     dstIndex)
+    {
+        int xl = BytesTo32bits(src, srcIndex);
+        int xr = BytesTo32bits(src, srcIndex+4);
+
+        xl ^= P[0];
+
+        for (int i = 1; i < ROUNDS; i += 2)
+        {
+            xr ^= F(xl) ^ P[i];
+            xl ^= F(xr) ^ P[i + 1];
+        }
+
+        xr ^= P[ROUNDS + 1];
+
+        Bits32ToBytes(xr, dst, dstIndex);
+        Bits32ToBytes(xl, dst, dstIndex + 4);
+    }
+
+    /**
+     * Decrypt the given input starting at the given offset and place
+     * the result in the provided buffer starting at the given offset.
+     * The input will be an exact multiple of our blocksize.
+     */
+    private void decryptBlock(
+        byte[] src, 
+        int srcIndex,
+        byte[] dst,
+        int dstIndex)
+    {
+        int xl = BytesTo32bits(src, srcIndex);
+        int xr = BytesTo32bits(src, srcIndex + 4);
+
+        xl ^= P[ROUNDS + 1];
+
+        for (int i = ROUNDS; i > 0 ; i -= 2)
+        {
+            xr ^= F(xl) ^ P[i];
+            xl ^= F(xr) ^ P[i - 1];
+        }
+
+        xr ^= P[0];
+
+        Bits32ToBytes(xr, dst, dstIndex);
+        Bits32ToBytes(xl, dst, dstIndex+4);
+    }
+
+    private int BytesTo32bits(byte[] b, int i)
+    {
+        return ((b[i]   & 0xff) << 24) | 
+             ((b[i+1] & 0xff) << 16) |
+             ((b[i+2] & 0xff) << 8) |
+             ((b[i+3] & 0xff));
+    }
+
+    private void Bits32ToBytes(int in,  byte[] b, int offset)
+    {
+        b[offset + 3] = (byte)in;
+        b[offset + 2] = (byte)(in >> 8);
+        b[offset + 1] = (byte)(in >> 16);
+        b[offset]     = (byte)(in >> 24);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/DESEngine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/DESEngine.java
new file mode 100644
index 0000000..dbef671
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/DESEngine.java
@@ -0,0 +1,485 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * a class that provides a basic DES engine.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DESEngine
+    implements BlockCipher
+{
+    protected static final int  BLOCK_SIZE = 8;
+
+    private int[]               workingKey = null;
+
+    /**
+     * standard constructor.
+     */
+    public DESEngine()
+    {
+    }
+
+    /**
+     * initialise a DES cipher.
+     *
+     * @param encrypting whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean           encrypting,
+        CipherParameters  params)
+    {
+        if (params instanceof KeyParameter)
+        {
+            if (((KeyParameter)params).getKey().length > 8)
+            {
+                throw new IllegalArgumentException("DES key too long - should be 8 bytes");
+            }
+            
+            workingKey = generateWorkingKey(encrypting,
+                                  ((KeyParameter)params).getKey());
+
+            return;
+        }
+
+        throw new IllegalArgumentException("invalid parameter passed to DES init - " + params.getClass().getName());
+    }
+
+    public String getAlgorithmName()
+    {
+        return "DES";
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    public int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (workingKey == null)
+        {
+            throw new IllegalStateException("DES engine not initialised");
+        }
+
+        if ((inOff + BLOCK_SIZE) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + BLOCK_SIZE) > out.length)
+        {
+            throw new OutputLengthException("output buffer too short");
+        }
+
+        desFunc(workingKey, in, inOff, out, outOff);
+
+        return BLOCK_SIZE;
+    }
+
+    public void reset()
+    {
+    }
+
+    /**
+     * what follows is mainly taken from "Applied Cryptography", by
+     * Bruce Schneier, however it also bears great resemblance to Richard
+     * Outerbridge's D3DES...
+     */
+
+//    private static final short[]    Df_Key =
+//        {
+//            0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
+//            0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
+//            0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67
+//        };
+
+    private static final short[]    bytebit =
+        {
+            0200, 0100, 040, 020, 010, 04, 02, 01
+        };
+
+    private static final int[]    bigbyte =
+        {
+            0x800000, 0x400000, 0x200000, 0x100000,
+            0x80000,  0x40000,  0x20000,  0x10000,
+            0x8000,      0x4000,   0x2000,   0x1000,
+            0x800,    0x400,    0x200,    0x100,
+            0x80,      0x40,        0x20,     0x10,
+            0x8,      0x4,      0x2,      0x1
+        };
+
+    /*
+     * Use the key schedule specified in the Standard (ANSI X3.92-1981).
+     */
+
+    private static final byte[]    pc1 =
+        {
+            56, 48, 40, 32, 24, 16,  8,   0, 57, 49, 41, 33, 25, 17,
+             9,  1, 58, 50, 42, 34, 26,  18, 10,  2, 59, 51, 43, 35,
+            62, 54, 46, 38, 30, 22, 14,   6, 61, 53, 45, 37, 29, 21,
+            13,  5, 60, 52, 44, 36, 28,  20, 12,  4, 27, 19, 11,  3
+        };
+
+    private static final byte[] totrot =
+        {
+            1, 2, 4, 6, 8, 10, 12, 14,
+            15, 17, 19, 21, 23, 25, 27, 28
+        };
+
+    private static final byte[] pc2 =
+        {
+            13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
+            22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
+            40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+            43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
+        };
+
+    private static final int[] SP1 = {
+        0x01010400, 0x00000000, 0x00010000, 0x01010404,
+        0x01010004, 0x00010404, 0x00000004, 0x00010000,
+        0x00000400, 0x01010400, 0x01010404, 0x00000400,
+        0x01000404, 0x01010004, 0x01000000, 0x00000004,
+        0x00000404, 0x01000400, 0x01000400, 0x00010400,
+        0x00010400, 0x01010000, 0x01010000, 0x01000404,
+        0x00010004, 0x01000004, 0x01000004, 0x00010004,
+        0x00000000, 0x00000404, 0x00010404, 0x01000000,
+        0x00010000, 0x01010404, 0x00000004, 0x01010000,
+        0x01010400, 0x01000000, 0x01000000, 0x00000400,
+        0x01010004, 0x00010000, 0x00010400, 0x01000004,
+        0x00000400, 0x00000004, 0x01000404, 0x00010404,
+        0x01010404, 0x00010004, 0x01010000, 0x01000404,
+        0x01000004, 0x00000404, 0x00010404, 0x01010400,
+        0x00000404, 0x01000400, 0x01000400, 0x00000000,
+        0x00010004, 0x00010400, 0x00000000, 0x01010004
+    };
+
+    private static final int[] SP2 = {
+        0x80108020, 0x80008000, 0x00008000, 0x00108020,
+        0x00100000, 0x00000020, 0x80100020, 0x80008020,
+        0x80000020, 0x80108020, 0x80108000, 0x80000000,
+        0x80008000, 0x00100000, 0x00000020, 0x80100020,
+        0x00108000, 0x00100020, 0x80008020, 0x00000000,
+        0x80000000, 0x00008000, 0x00108020, 0x80100000,
+        0x00100020, 0x80000020, 0x00000000, 0x00108000,
+        0x00008020, 0x80108000, 0x80100000, 0x00008020,
+        0x00000000, 0x00108020, 0x80100020, 0x00100000,
+        0x80008020, 0x80100000, 0x80108000, 0x00008000,
+        0x80100000, 0x80008000, 0x00000020, 0x80108020,
+        0x00108020, 0x00000020, 0x00008000, 0x80000000,
+        0x00008020, 0x80108000, 0x00100000, 0x80000020,
+        0x00100020, 0x80008020, 0x80000020, 0x00100020,
+        0x00108000, 0x00000000, 0x80008000, 0x00008020,
+        0x80000000, 0x80100020, 0x80108020, 0x00108000
+    };
+
+    private static final int[] SP3 = {
+        0x00000208, 0x08020200, 0x00000000, 0x08020008,
+        0x08000200, 0x00000000, 0x00020208, 0x08000200,
+        0x00020008, 0x08000008, 0x08000008, 0x00020000,
+        0x08020208, 0x00020008, 0x08020000, 0x00000208,
+        0x08000000, 0x00000008, 0x08020200, 0x00000200,
+        0x00020200, 0x08020000, 0x08020008, 0x00020208,
+        0x08000208, 0x00020200, 0x00020000, 0x08000208,
+        0x00000008, 0x08020208, 0x00000200, 0x08000000,
+        0x08020200, 0x08000000, 0x00020008, 0x00000208,
+        0x00020000, 0x08020200, 0x08000200, 0x00000000,
+        0x00000200, 0x00020008, 0x08020208, 0x08000200,
+        0x08000008, 0x00000200, 0x00000000, 0x08020008,
+        0x08000208, 0x00020000, 0x08000000, 0x08020208,
+        0x00000008, 0x00020208, 0x00020200, 0x08000008,
+        0x08020000, 0x08000208, 0x00000208, 0x08020000,
+        0x00020208, 0x00000008, 0x08020008, 0x00020200
+    };
+
+    private static final int[] SP4 = {
+        0x00802001, 0x00002081, 0x00002081, 0x00000080,
+        0x00802080, 0x00800081, 0x00800001, 0x00002001,
+        0x00000000, 0x00802000, 0x00802000, 0x00802081,
+        0x00000081, 0x00000000, 0x00800080, 0x00800001,
+        0x00000001, 0x00002000, 0x00800000, 0x00802001,
+        0x00000080, 0x00800000, 0x00002001, 0x00002080,
+        0x00800081, 0x00000001, 0x00002080, 0x00800080,
+        0x00002000, 0x00802080, 0x00802081, 0x00000081,
+        0x00800080, 0x00800001, 0x00802000, 0x00802081,
+        0x00000081, 0x00000000, 0x00000000, 0x00802000,
+        0x00002080, 0x00800080, 0x00800081, 0x00000001,
+        0x00802001, 0x00002081, 0x00002081, 0x00000080,
+        0x00802081, 0x00000081, 0x00000001, 0x00002000,
+        0x00800001, 0x00002001, 0x00802080, 0x00800081,
+        0x00002001, 0x00002080, 0x00800000, 0x00802001,
+        0x00000080, 0x00800000, 0x00002000, 0x00802080
+    };
+
+    private static final int[] SP5 = {
+        0x00000100, 0x02080100, 0x02080000, 0x42000100,
+        0x00080000, 0x00000100, 0x40000000, 0x02080000,
+        0x40080100, 0x00080000, 0x02000100, 0x40080100,
+        0x42000100, 0x42080000, 0x00080100, 0x40000000,
+        0x02000000, 0x40080000, 0x40080000, 0x00000000,
+        0x40000100, 0x42080100, 0x42080100, 0x02000100,
+        0x42080000, 0x40000100, 0x00000000, 0x42000000,
+        0x02080100, 0x02000000, 0x42000000, 0x00080100,
+        0x00080000, 0x42000100, 0x00000100, 0x02000000,
+        0x40000000, 0x02080000, 0x42000100, 0x40080100,
+        0x02000100, 0x40000000, 0x42080000, 0x02080100,
+        0x40080100, 0x00000100, 0x02000000, 0x42080000,
+        0x42080100, 0x00080100, 0x42000000, 0x42080100,
+        0x02080000, 0x00000000, 0x40080000, 0x42000000,
+        0x00080100, 0x02000100, 0x40000100, 0x00080000,
+        0x00000000, 0x40080000, 0x02080100, 0x40000100
+    };
+
+    private static final int[] SP6 = {
+        0x20000010, 0x20400000, 0x00004000, 0x20404010,
+        0x20400000, 0x00000010, 0x20404010, 0x00400000,
+        0x20004000, 0x00404010, 0x00400000, 0x20000010,
+        0x00400010, 0x20004000, 0x20000000, 0x00004010,
+        0x00000000, 0x00400010, 0x20004010, 0x00004000,
+        0x00404000, 0x20004010, 0x00000010, 0x20400010,
+        0x20400010, 0x00000000, 0x00404010, 0x20404000,
+        0x00004010, 0x00404000, 0x20404000, 0x20000000,
+        0x20004000, 0x00000010, 0x20400010, 0x00404000,
+        0x20404010, 0x00400000, 0x00004010, 0x20000010,
+        0x00400000, 0x20004000, 0x20000000, 0x00004010,
+        0x20000010, 0x20404010, 0x00404000, 0x20400000,
+        0x00404010, 0x20404000, 0x00000000, 0x20400010,
+        0x00000010, 0x00004000, 0x20400000, 0x00404010,
+        0x00004000, 0x00400010, 0x20004010, 0x00000000,
+        0x20404000, 0x20000000, 0x00400010, 0x20004010
+    };
+
+    private static final int[] SP7 = {
+        0x00200000, 0x04200002, 0x04000802, 0x00000000,
+        0x00000800, 0x04000802, 0x00200802, 0x04200800,
+        0x04200802, 0x00200000, 0x00000000, 0x04000002,
+        0x00000002, 0x04000000, 0x04200002, 0x00000802,
+        0x04000800, 0x00200802, 0x00200002, 0x04000800,
+        0x04000002, 0x04200000, 0x04200800, 0x00200002,
+        0x04200000, 0x00000800, 0x00000802, 0x04200802,
+        0x00200800, 0x00000002, 0x04000000, 0x00200800,
+        0x04000000, 0x00200800, 0x00200000, 0x04000802,
+        0x04000802, 0x04200002, 0x04200002, 0x00000002,
+        0x00200002, 0x04000000, 0x04000800, 0x00200000,
+        0x04200800, 0x00000802, 0x00200802, 0x04200800,
+        0x00000802, 0x04000002, 0x04200802, 0x04200000,
+        0x00200800, 0x00000000, 0x00000002, 0x04200802,
+        0x00000000, 0x00200802, 0x04200000, 0x00000800,
+        0x04000002, 0x04000800, 0x00000800, 0x00200002
+    };
+
+    private static final int[] SP8 = {
+        0x10001040, 0x00001000, 0x00040000, 0x10041040,
+        0x10000000, 0x10001040, 0x00000040, 0x10000000,
+        0x00040040, 0x10040000, 0x10041040, 0x00041000,
+        0x10041000, 0x00041040, 0x00001000, 0x00000040,
+        0x10040000, 0x10000040, 0x10001000, 0x00001040,
+        0x00041000, 0x00040040, 0x10040040, 0x10041000,
+        0x00001040, 0x00000000, 0x00000000, 0x10040040,
+        0x10000040, 0x10001000, 0x00041040, 0x00040000,
+        0x00041040, 0x00040000, 0x10041000, 0x00001000,
+        0x00000040, 0x10040040, 0x00001000, 0x00041040,
+        0x10001000, 0x00000040, 0x10000040, 0x10040000,
+        0x10040040, 0x10000000, 0x00040000, 0x10001040,
+        0x00000000, 0x10041040, 0x00040040, 0x10000040,
+        0x10040000, 0x10001000, 0x10001040, 0x00000000,
+        0x10041040, 0x00041000, 0x00041000, 0x00001040,
+        0x00001040, 0x00040040, 0x10000000, 0x10041000
+    };
+
+    /**
+     * generate an integer based working key based on our secret key
+     * and what we processing we are planning to do.
+     *
+     * Acknowledgements for this routine go to James Gillogly &amp; Phil Karn.
+     *         (whoever, and wherever they are!).
+     */
+    protected int[] generateWorkingKey(
+        boolean encrypting,
+        byte[]  key)
+    {
+        int[]       newKey = new int[32];
+        boolean[]   pc1m = new boolean[56],
+                    pcr = new boolean[56];
+
+        for (int j = 0; j < 56; j++)
+        {
+            int    l = pc1[j];
+
+            pc1m[j] = ((key[l >>> 3] & bytebit[l & 07]) != 0);
+        }
+
+        for (int i = 0; i < 16; i++)
+        {
+            int    l, m, n;
+
+            if (encrypting)
+            {
+                m = i << 1;
+            }
+            else
+            {
+                m = (15 - i) << 1;
+            }
+
+            n = m + 1;
+            newKey[m] = newKey[n] = 0;
+
+            for (int j = 0; j < 28; j++)
+            {
+                l = j + totrot[i];
+                if (l < 28)
+                {
+                    pcr[j] = pc1m[l];
+                }
+                else
+                {
+                    pcr[j] = pc1m[l - 28];
+                }
+            }
+
+            for (int j = 28; j < 56; j++)
+            {
+                l = j + totrot[i];
+                if (l < 56)
+                {
+                    pcr[j] = pc1m[l];
+                }
+                else
+                {
+                    pcr[j] = pc1m[l - 28];
+                }
+            }
+
+            for (int j = 0; j < 24; j++)
+            {
+                if (pcr[pc2[j]])
+                {
+                    newKey[m] |= bigbyte[j];
+                }
+
+                if (pcr[pc2[j + 24]])
+                {
+                    newKey[n] |= bigbyte[j];
+                }
+            }
+        }
+
+        //
+        // store the processed key
+        //
+        for (int i = 0; i != 32; i += 2)
+        {
+            int    i1, i2;
+
+            i1 = newKey[i];
+            i2 = newKey[i + 1];
+
+            newKey[i] = ((i1 & 0x00fc0000) << 6) | ((i1 & 0x00000fc0) << 10)
+                                   | ((i2 & 0x00fc0000) >>> 10) | ((i2 & 0x00000fc0) >>> 6);
+
+            newKey[i + 1] = ((i1 & 0x0003f000) << 12) | ((i1 & 0x0000003f) << 16)
+                                   | ((i2 & 0x0003f000) >>> 4) | (i2 & 0x0000003f);
+        }
+
+        return newKey;
+    }
+
+    /**
+     * the DES engine.
+     */
+    protected void desFunc(
+        int[]   wKey,
+        byte[]  in,
+        int     inOff,
+        byte[]  out,
+        int     outOff)
+    {
+        int     work, right, left;
+
+        left = Pack.bigEndianToInt(in, inOff);
+        right = Pack.bigEndianToInt(in, inOff + 4);
+
+        work = ((left >>> 4) ^ right) & 0x0f0f0f0f;
+        right ^= work;
+        left ^= (work << 4);
+        work = ((left >>> 16) ^ right) & 0x0000ffff;
+        right ^= work;
+        left ^= (work << 16);
+        work = ((right >>> 2) ^ left) & 0x33333333;
+        left ^= work;
+        right ^= (work << 2);
+        work = ((right >>> 8) ^ left) & 0x00ff00ff;
+        left ^= work;
+        right ^= (work << 8);
+        right = (right << 1) | (right >>> 31);
+        work = (left ^ right) & 0xaaaaaaaa;
+        left ^= work;
+        right ^= work;
+        left = (left << 1) | (left >>> 31);
+
+        for (int round = 0; round < 8; round++)
+        {
+            int     fval;
+
+            work  = (right << 28) | (right >>> 4);
+            work ^= wKey[round * 4 + 0];
+            fval  = SP7[ work      & 0x3f];
+            fval |= SP5[(work >>>  8) & 0x3f];
+            fval |= SP3[(work >>> 16) & 0x3f];
+            fval |= SP1[(work >>> 24) & 0x3f];
+            work  = right ^ wKey[round * 4 + 1];
+            fval |= SP8[ work      & 0x3f];
+            fval |= SP6[(work >>>  8) & 0x3f];
+            fval |= SP4[(work >>> 16) & 0x3f];
+            fval |= SP2[(work >>> 24) & 0x3f];
+            left ^= fval;
+            work  = (left << 28) | (left >>> 4);
+            work ^= wKey[round * 4 + 2];
+            fval  = SP7[ work      & 0x3f];
+            fval |= SP5[(work >>>  8) & 0x3f];
+            fval |= SP3[(work >>> 16) & 0x3f];
+            fval |= SP1[(work >>> 24) & 0x3f];
+            work  = left ^ wKey[round * 4 + 3];
+            fval |= SP8[ work      & 0x3f];
+            fval |= SP6[(work >>>  8) & 0x3f];
+            fval |= SP4[(work >>> 16) & 0x3f];
+            fval |= SP2[(work >>> 24) & 0x3f];
+            right ^= fval;
+        }
+
+        right = (right << 31) | (right >>> 1);
+        work = (left ^ right) & 0xaaaaaaaa;
+        left ^= work;
+        right ^= work;
+        left = (left << 31) | (left >>> 1);
+        work = ((left >>> 8) ^ right) & 0x00ff00ff;
+        right ^= work;
+        left ^= (work << 8);
+        work = ((left >>> 2) ^ right) & 0x33333333;
+        right ^= work;
+        left ^= (work << 2);
+        work = ((right >>> 16) ^ left) & 0x0000ffff;
+        left ^= work;
+        right ^= (work << 16);
+        work = ((right >>> 4) ^ left) & 0x0f0f0f0f;
+        left ^= work;
+        right ^= (work << 4);
+
+        Pack.intToBigEndian(right, out, outOff);
+        Pack.intToBigEndian(left, out, outOff + 4);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/DESedeEngine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/DESedeEngine.java
new file mode 100644
index 0000000..7fa0b9f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/DESedeEngine.java
@@ -0,0 +1,129 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * a class that provides a basic DESede (or Triple DES) engine.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DESedeEngine
+    extends DESEngine
+{
+    protected static final int  BLOCK_SIZE = 8;
+
+    private int[]               workingKey1 = null;
+    private int[]               workingKey2 = null;
+    private int[]               workingKey3 = null;
+
+    private boolean             forEncryption;
+
+    /**
+     * standard constructor.
+     */
+    public DESedeEngine()
+    {
+    }
+
+    /**
+     * initialise a DESede cipher.
+     *
+     * @param encrypting whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean           encrypting,
+        CipherParameters  params)
+    {
+        if (!(params instanceof KeyParameter))
+        {
+            throw new IllegalArgumentException("invalid parameter passed to DESede init - " + params.getClass().getName());
+        }
+
+        byte[] keyMaster = ((KeyParameter)params).getKey();
+
+        if (keyMaster.length != 24 && keyMaster.length != 16)
+        {
+            throw new IllegalArgumentException("key size must be 16 or 24 bytes.");
+        }
+
+        this.forEncryption = encrypting;
+
+        byte[] key1 = new byte[8];
+        System.arraycopy(keyMaster, 0, key1, 0, key1.length);
+        workingKey1 = generateWorkingKey(encrypting, key1);
+
+        byte[] key2 = new byte[8];
+        System.arraycopy(keyMaster, 8, key2, 0, key2.length);
+        workingKey2 = generateWorkingKey(!encrypting, key2);
+
+        if (keyMaster.length == 24)
+        {
+            byte[] key3 = new byte[8];
+            System.arraycopy(keyMaster, 16, key3, 0, key3.length);
+            workingKey3 = generateWorkingKey(encrypting, key3);
+        }
+        else    // 16 byte key
+        {
+            workingKey3 = workingKey1;
+        }
+    }
+
+    public String getAlgorithmName()
+    {
+        return "DESede";
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    public int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (workingKey1 == null)
+        {
+            throw new IllegalStateException("DESede engine not initialised");
+        }
+
+        if ((inOff + BLOCK_SIZE) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + BLOCK_SIZE) > out.length)
+        {
+            throw new OutputLengthException("output buffer too short");
+        }
+
+        byte[] temp = new byte[BLOCK_SIZE];
+
+        if (forEncryption)
+        {
+            desFunc(workingKey1, in, inOff, temp, 0);
+            desFunc(workingKey2, temp, 0, temp, 0);
+            desFunc(workingKey3, temp, 0, out, outOff);
+        }
+        else
+        {
+            desFunc(workingKey3, in, inOff, temp, 0);
+            desFunc(workingKey2, temp, 0, temp, 0);
+            desFunc(workingKey1, temp, 0, out, outOff);
+        }
+
+        return BLOCK_SIZE;
+    }
+
+    public void reset()
+    {
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/DESedeWrapEngine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
new file mode 100644
index 0000000..91aa366
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
@@ -0,0 +1,356 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.Wrapper;
+import com.android.internal.org.bouncycastle.crypto.modes.CBCBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+// Android-changed: Use Android digests
+// import org.bouncycastle.crypto.util.DigestFactory;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * Wrap keys according to
+ * <A HREF="https://www.ietf.org/rfc/rfc3217.txt">
+ * RFC 3217</A>.
+ * <p>
+ * Note: 
+ * <ul>
+ * <li>if you are using this to wrap triple-des keys you need to set the
+ * parity bits on the key and, if it's a two-key triple-des key, pad it
+ * yourself.
+ * </ul>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DESedeWrapEngine
+    implements Wrapper
+{
+   /** Field engine */
+   private CBCBlockCipher engine;
+
+   /** Field param */
+   private KeyParameter param;
+
+   /** Field paramPlusIV */
+   private ParametersWithIV paramPlusIV;
+
+   /** Field iv */
+   private byte[] iv;
+
+   /** Field forWrapping */
+   private boolean forWrapping;
+
+   /** Field IV2           */
+   private static final byte[] IV2 = { (byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
+                                       (byte) 0x2c, (byte) 0x79, (byte) 0xe8,
+                                       (byte) 0x21, (byte) 0x05 };
+
+    //
+    // checksum digest
+    //
+    // Android-changed: Use Android digests
+    // Digest  sha1 = DigestFactory.createSHA1();
+    Digest  sha1 = AndroidDigestFactory.getSHA1();
+    byte[]  digest = new byte[20];
+
+   /**
+    * Method init
+    *
+    * @param forWrapping true if for wrapping, false otherwise.
+    * @param param necessary parameters, may include KeyParameter, ParametersWithRandom, and ParametersWithIV
+    */
+    public void init(boolean forWrapping, CipherParameters param)
+    {
+
+        this.forWrapping = forWrapping;
+        this.engine = new CBCBlockCipher(new DESedeEngine());
+
+        SecureRandom sr;
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom pr = (ParametersWithRandom) param;
+            param = pr.getParameters();
+            sr = pr.getRandom();
+        }
+        else
+        {
+            sr = CryptoServicesRegistrar.getSecureRandom();
+        }
+
+        if (param instanceof KeyParameter)
+        {
+            this.param = (KeyParameter)param;
+
+            if (this.forWrapping)
+            {
+
+                // Hm, we have no IV but we want to wrap ?!?
+                // well, then we have to create our own IV.
+                this.iv = new byte[8];
+                sr.nextBytes(iv);
+
+                this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+            }
+        }
+        else if (param instanceof ParametersWithIV)
+        {
+            this.paramPlusIV = (ParametersWithIV)param;
+            this.iv = this.paramPlusIV.getIV();
+            this.param = (KeyParameter)this.paramPlusIV.getParameters();
+
+            if (this.forWrapping)
+            {
+                if ((this.iv == null) || (this.iv.length != 8))
+                {
+                    throw new IllegalArgumentException("IV is not 8 octets");
+                }
+            }
+            else
+            {
+                throw new IllegalArgumentException(
+                        "You should not supply an IV for unwrapping");
+            }
+        }
+    }
+
+   /**
+    * Method getAlgorithmName
+    *
+    * @return the algorithm name "DESede".
+    */
+   public String getAlgorithmName() 
+   {
+      return "DESede";
+   }
+
+   /**
+    * Method wrap
+    *
+    * @param in byte array containing the encoded key.
+    * @param inOff off set into in that the data starts at.
+    * @param inLen  length of the data.
+    * @return the wrapped bytes.
+    */
+   public byte[] wrap(byte[] in, int inOff, int inLen) 
+   {
+      if (!forWrapping) 
+      {
+         throw new IllegalStateException("Not initialized for wrapping");
+      }
+
+      byte keyToBeWrapped[] = new byte[inLen];
+
+      System.arraycopy(in, inOff, keyToBeWrapped, 0, inLen);
+
+      // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
+      byte[] CKS = calculateCMSKeyChecksum(keyToBeWrapped);
+
+      // Let WKCKS = WK || CKS where || is concatenation.
+      byte[] WKCKS = new byte[keyToBeWrapped.length + CKS.length];
+
+      System.arraycopy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.length);
+      System.arraycopy(CKS, 0, WKCKS, keyToBeWrapped.length, CKS.length);
+
+      // Encrypt WKCKS in CBC mode using KEK as the key and IV as the
+      // initialization vector. Call the results TEMP1.
+
+      int blockSize = engine.getBlockSize();
+
+      if (WKCKS.length % blockSize != 0) 
+      {
+         throw new IllegalStateException("Not multiple of block length");
+      }
+
+      engine.init(true, paramPlusIV);
+
+      byte TEMP1[] = new byte[WKCKS.length];
+
+      for (int currentBytePos = 0; currentBytePos != WKCKS.length; currentBytePos += blockSize) 
+      {
+         engine.processBlock(WKCKS, currentBytePos, TEMP1, currentBytePos);
+      }
+
+      // Let TEMP2 = IV || TEMP1.
+      byte[] TEMP2 = new byte[this.iv.length + TEMP1.length];
+
+      System.arraycopy(this.iv, 0, TEMP2, 0, this.iv.length);
+      System.arraycopy(TEMP1, 0, TEMP2, this.iv.length, TEMP1.length);
+
+      // Reverse the order of the octets in TEMP2 and call the result TEMP3.
+      byte[] TEMP3 = reverse(TEMP2);
+
+      // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+      // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
+      // result. It is 40 octets long if a 168 bit key is being wrapped.
+      ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+
+      this.engine.init(true, param2);
+
+      for (int currentBytePos = 0; currentBytePos != TEMP3.length; currentBytePos += blockSize) 
+      {
+         engine.processBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+      }
+
+      return TEMP3;
+   }
+
+   /**
+    * Method unwrap
+    *
+    * @param in byte array containing the wrapped key.
+    * @param inOff off set into in that the data starts at.
+    * @param inLen  length of the data.
+    * @return the unwrapped bytes.
+    * @throws InvalidCipherTextException
+    */
+    public byte[] unwrap(byte[] in, int inOff, int inLen)
+           throws InvalidCipherTextException 
+    {
+        if (forWrapping)
+        {
+            throw new IllegalStateException("Not set for unwrapping");
+        }
+        
+        if (in == null)
+        {
+            throw new InvalidCipherTextException("Null pointer as ciphertext");
+        }
+
+        final int blockSize = engine.getBlockSize();
+        if (inLen % blockSize != 0)
+        {
+            throw new InvalidCipherTextException("Ciphertext not multiple of " + blockSize);
+        }
+
+      /*
+      // Check if the length of the cipher text is reasonable given the key
+      // type. It must be 40 bytes for a 168 bit key and either 32, 40, or
+      // 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
+      // or inconsistent with the algorithm for which the key is intended,
+      // return error.
+      //
+      // we do not accept 168 bit keys. it has to be 192 bit.
+      int lengthA = (estimatedKeyLengthInBit / 8) + 16;
+      int lengthB = estimatedKeyLengthInBit % 8;
+
+      if ((lengthA != keyToBeUnwrapped.length) || (lengthB != 0)) {
+         throw new XMLSecurityException("empty");
+      }
+      */
+
+      // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
+      // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
+      ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+
+      this.engine.init(false, param2);
+
+      byte TEMP3[] = new byte[inLen];
+
+      for (int currentBytePos = 0; currentBytePos != inLen; currentBytePos += blockSize) 
+      {
+         engine.processBlock(in, inOff + currentBytePos, TEMP3, currentBytePos);
+      }
+
+      // Reverse the order of the octets in TEMP3 and call the result TEMP2.
+      byte[] TEMP2 = reverse(TEMP3);
+
+      // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
+      this.iv = new byte[8];
+
+      byte[] TEMP1 = new byte[TEMP2.length - 8];
+
+      System.arraycopy(TEMP2, 0, this.iv, 0, 8);
+      System.arraycopy(TEMP2, 8, TEMP1, 0, TEMP2.length - 8);
+
+      // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
+      // found in the previous step. Call the result WKCKS.
+      this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+
+      this.engine.init(false, this.paramPlusIV);
+
+      byte[] WKCKS = new byte[TEMP1.length];
+
+      for (int currentBytePos = 0; currentBytePos != WKCKS.length; currentBytePos += blockSize) 
+      {
+         engine.processBlock(TEMP1, currentBytePos, WKCKS, currentBytePos);
+      }
+
+      // Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are
+      // those octets before the CKS.
+      byte[] result = new byte[WKCKS.length - 8];
+      byte[] CKStoBeVerified = new byte[8];
+
+      System.arraycopy(WKCKS, 0, result, 0, WKCKS.length - 8);
+      System.arraycopy(WKCKS, WKCKS.length - 8, CKStoBeVerified, 0, 8);
+
+      // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
+      // with the CKS extracted in the above step. If they are not equal, return error.
+      if (!checkCMSKeyChecksum(result, CKStoBeVerified)) 
+      {
+         throw new InvalidCipherTextException(
+            "Checksum inside ciphertext is corrupted");
+      }
+
+      // WK is the wrapped key, now extracted for use in data decryption.
+      return result;
+   }
+
+    /**
+     * Some key wrap algorithms make use of the Key Checksum defined
+     * in CMS [CMS-Algorithms]. This is used to provide an integrity
+     * check value for the key being wrapped. The algorithm is
+     *
+     * - Compute the 20 octet SHA-1 hash on the key being wrapped.
+     * - Use the first 8 octets of this hash as the checksum value.
+     *
+     * For details see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum.
+     *
+     * @param key the key to check,
+     * @return the CMS checksum.
+     * @throws RuntimeException
+     */
+    private byte[] calculateCMSKeyChecksum(
+        byte[] key)
+    {
+        byte[]  result = new byte[8];
+
+        sha1.update(key, 0, key.length);
+        sha1.doFinal(digest, 0);
+
+        System.arraycopy(digest, 0, result, 0, 8);
+
+        return result;
+    }
+
+    /**
+     * For details see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+     *
+     * @param key key to be validated.
+     * @param checksum the checksum.
+     * @return true if okay, false otherwise.
+     */
+    private boolean checkCMSKeyChecksum(
+        byte[] key,
+        byte[] checksum)
+    {
+        return Arrays.constantTimeAreEqual(calculateCMSKeyChecksum(key), checksum);
+    }
+
+    private static byte[] reverse(byte[] bs)
+    {
+        byte[] result = new byte[bs.length];
+        for (int i = 0; i < bs.length; i++) 
+        {
+           result[i] = bs[bs.length - (i + 1)];
+        }
+        return result;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RC2Engine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RC2Engine.java
new file mode 100644
index 0000000..997f854
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RC2Engine.java
@@ -0,0 +1,319 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.RC2Parameters;
+
+/**
+ * an implementation of RC2 as described in RFC 2268
+ *      "A Description of the RC2(r) Encryption Algorithm" R. Rivest.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RC2Engine
+    implements BlockCipher
+{
+    //
+    // the values we use for key expansion (based on the digits of PI)
+    //
+    private static byte[] piTable =
+    {
+        (byte)0xd9, (byte)0x78, (byte)0xf9, (byte)0xc4, (byte)0x19, (byte)0xdd, (byte)0xb5, (byte)0xed, 
+        (byte)0x28, (byte)0xe9, (byte)0xfd, (byte)0x79, (byte)0x4a, (byte)0xa0, (byte)0xd8, (byte)0x9d, 
+        (byte)0xc6, (byte)0x7e, (byte)0x37, (byte)0x83, (byte)0x2b, (byte)0x76, (byte)0x53, (byte)0x8e, 
+        (byte)0x62, (byte)0x4c, (byte)0x64, (byte)0x88, (byte)0x44, (byte)0x8b, (byte)0xfb, (byte)0xa2, 
+        (byte)0x17, (byte)0x9a, (byte)0x59, (byte)0xf5, (byte)0x87, (byte)0xb3, (byte)0x4f, (byte)0x13, 
+        (byte)0x61, (byte)0x45, (byte)0x6d, (byte)0x8d, (byte)0x9, (byte)0x81, (byte)0x7d, (byte)0x32, 
+        (byte)0xbd, (byte)0x8f, (byte)0x40, (byte)0xeb, (byte)0x86, (byte)0xb7, (byte)0x7b, (byte)0xb, 
+        (byte)0xf0, (byte)0x95, (byte)0x21, (byte)0x22, (byte)0x5c, (byte)0x6b, (byte)0x4e, (byte)0x82, 
+        (byte)0x54, (byte)0xd6, (byte)0x65, (byte)0x93, (byte)0xce, (byte)0x60, (byte)0xb2, (byte)0x1c, 
+        (byte)0x73, (byte)0x56, (byte)0xc0, (byte)0x14, (byte)0xa7, (byte)0x8c, (byte)0xf1, (byte)0xdc, 
+        (byte)0x12, (byte)0x75, (byte)0xca, (byte)0x1f, (byte)0x3b, (byte)0xbe, (byte)0xe4, (byte)0xd1, 
+        (byte)0x42, (byte)0x3d, (byte)0xd4, (byte)0x30, (byte)0xa3, (byte)0x3c, (byte)0xb6, (byte)0x26, 
+        (byte)0x6f, (byte)0xbf, (byte)0xe, (byte)0xda, (byte)0x46, (byte)0x69, (byte)0x7, (byte)0x57, 
+        (byte)0x27, (byte)0xf2, (byte)0x1d, (byte)0x9b, (byte)0xbc, (byte)0x94, (byte)0x43, (byte)0x3, 
+        (byte)0xf8, (byte)0x11, (byte)0xc7, (byte)0xf6, (byte)0x90, (byte)0xef, (byte)0x3e, (byte)0xe7, 
+        (byte)0x6, (byte)0xc3, (byte)0xd5, (byte)0x2f, (byte)0xc8, (byte)0x66, (byte)0x1e, (byte)0xd7, 
+        (byte)0x8, (byte)0xe8, (byte)0xea, (byte)0xde, (byte)0x80, (byte)0x52, (byte)0xee, (byte)0xf7, 
+        (byte)0x84, (byte)0xaa, (byte)0x72, (byte)0xac, (byte)0x35, (byte)0x4d, (byte)0x6a, (byte)0x2a, 
+        (byte)0x96, (byte)0x1a, (byte)0xd2, (byte)0x71, (byte)0x5a, (byte)0x15, (byte)0x49, (byte)0x74, 
+        (byte)0x4b, (byte)0x9f, (byte)0xd0, (byte)0x5e, (byte)0x4, (byte)0x18, (byte)0xa4, (byte)0xec, 
+        (byte)0xc2, (byte)0xe0, (byte)0x41, (byte)0x6e, (byte)0xf, (byte)0x51, (byte)0xcb, (byte)0xcc, 
+        (byte)0x24, (byte)0x91, (byte)0xaf, (byte)0x50, (byte)0xa1, (byte)0xf4, (byte)0x70, (byte)0x39, 
+        (byte)0x99, (byte)0x7c, (byte)0x3a, (byte)0x85, (byte)0x23, (byte)0xb8, (byte)0xb4, (byte)0x7a, 
+        (byte)0xfc, (byte)0x2, (byte)0x36, (byte)0x5b, (byte)0x25, (byte)0x55, (byte)0x97, (byte)0x31, 
+        (byte)0x2d, (byte)0x5d, (byte)0xfa, (byte)0x98, (byte)0xe3, (byte)0x8a, (byte)0x92, (byte)0xae, 
+        (byte)0x5, (byte)0xdf, (byte)0x29, (byte)0x10, (byte)0x67, (byte)0x6c, (byte)0xba, (byte)0xc9, 
+        (byte)0xd3, (byte)0x0, (byte)0xe6, (byte)0xcf, (byte)0xe1, (byte)0x9e, (byte)0xa8, (byte)0x2c, 
+        (byte)0x63, (byte)0x16, (byte)0x1, (byte)0x3f, (byte)0x58, (byte)0xe2, (byte)0x89, (byte)0xa9, 
+        (byte)0xd, (byte)0x38, (byte)0x34, (byte)0x1b, (byte)0xab, (byte)0x33, (byte)0xff, (byte)0xb0, 
+        (byte)0xbb, (byte)0x48, (byte)0xc, (byte)0x5f, (byte)0xb9, (byte)0xb1, (byte)0xcd, (byte)0x2e, 
+        (byte)0xc5, (byte)0xf3, (byte)0xdb, (byte)0x47, (byte)0xe5, (byte)0xa5, (byte)0x9c, (byte)0x77, 
+        (byte)0xa, (byte)0xa6, (byte)0x20, (byte)0x68, (byte)0xfe, (byte)0x7f, (byte)0xc1, (byte)0xad 
+    };
+
+    private static final int BLOCK_SIZE = 8;
+
+    private int[]   workingKey;
+    private boolean encrypting;
+
+    private int[] generateWorkingKey(
+        byte[]      key,
+        int         bits)
+    {
+        int     x;
+        int[]   xKey = new int[128];
+
+        for (int i = 0; i != key.length; i++)
+        {
+            xKey[i] = key[i] & 0xff;
+        }
+
+        // Phase 1: Expand input key to 128 bytes
+        int len = key.length;
+
+        if (len < 128)
+        {
+            int     index = 0;
+
+            x = xKey[len - 1];
+
+            do
+            {
+                x = piTable[(x + xKey[index++]) & 255] & 0xff;
+                xKey[len++] = x;
+            }
+            while (len < 128);
+        }
+
+        // Phase 2 - reduce effective key size to "bits"
+        len = (bits + 7) >> 3;
+        x = piTable[xKey[128 - len] & (255 >> (7 & -bits))] & 0xff;
+        xKey[128 - len] = x;
+
+        for (int i = 128 - len - 1; i >= 0; i--)
+        {
+                x = piTable[x ^ xKey[i + len]] & 0xff;
+                xKey[i] = x;
+        }
+
+        // Phase 3 - copy to newKey in little-endian order 
+        int[] newKey = new int[64];
+
+        for (int i = 0; i != newKey.length; i++)
+        {
+            newKey[i] = (xKey[2 * i] + (xKey[2 * i + 1] << 8));
+        }
+
+        return newKey;
+    }
+
+    /**
+     * initialise a RC2 cipher.
+     *
+     * @param encrypting whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean           encrypting,
+        CipherParameters  params)
+    {
+        this.encrypting = encrypting;
+
+        if (params instanceof RC2Parameters)
+        {
+            RC2Parameters   param = (RC2Parameters)params;
+
+            workingKey = generateWorkingKey(param.getKey(),
+                                            param.getEffectiveKeyBits());
+        }
+        else if (params instanceof KeyParameter)
+        {
+            byte[]    key = ((KeyParameter)params).getKey();
+
+            workingKey = generateWorkingKey(key, key.length * 8);
+        }
+        else
+        {
+            throw new IllegalArgumentException("invalid parameter passed to RC2 init - " + params.getClass().getName());
+        }
+
+    }
+
+    public void reset()
+    {
+    }
+
+    public String getAlgorithmName()
+    {
+        return "RC2";
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    public final int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (workingKey == null)
+        {
+            throw new IllegalStateException("RC2 engine not initialised");
+        }
+
+        if ((inOff + BLOCK_SIZE) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + BLOCK_SIZE) > out.length)
+        {
+            throw new OutputLengthException("output buffer too short");
+        }
+
+        if (encrypting)
+        {
+            encryptBlock(in, inOff, out, outOff);
+        }
+        else
+        {
+            decryptBlock(in, inOff, out, outOff);
+        }
+
+        return BLOCK_SIZE;
+    }
+
+    /**
+     * return the result rotating the 16 bit number in x left by y
+     */
+    private int rotateWordLeft(
+        int x,
+        int y)
+    {
+        x &= 0xffff;
+        return (x << y) | (x >> (16 - y));
+    }
+
+    private void encryptBlock(
+        byte[]  in,
+        int     inOff,
+        byte[]  out,
+        int     outOff)
+    {
+        int x76, x54, x32, x10;
+
+        x76 = ((in[inOff + 7] & 0xff) << 8) + (in[inOff + 6] & 0xff);
+        x54 = ((in[inOff + 5] & 0xff) << 8) + (in[inOff + 4] & 0xff);
+        x32 = ((in[inOff + 3] & 0xff) << 8) + (in[inOff + 2] & 0xff);
+        x10 = ((in[inOff + 1] & 0xff) << 8) + (in[inOff + 0] & 0xff);
+
+        for (int i = 0; i <= 16; i += 4)
+        {
+                x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i  ], 1);
+                x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+                x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+                x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+        }
+
+        x10 += workingKey[x76 & 63];
+        x32 += workingKey[x10 & 63];
+        x54 += workingKey[x32 & 63];
+        x76 += workingKey[x54 & 63];
+
+        for (int i = 20; i <= 40; i += 4)
+        {
+                x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i  ], 1);
+                x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+                x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+                x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+        }
+
+        x10 += workingKey[x76 & 63];
+        x32 += workingKey[x10 & 63];
+        x54 += workingKey[x32 & 63];
+        x76 += workingKey[x54 & 63];
+
+        for (int i = 44; i < 64; i += 4)
+        {
+                x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i  ], 1);
+                x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+                x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+                x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+        }
+
+        out[outOff + 0] = (byte)x10;
+        out[outOff + 1] = (byte)(x10 >> 8);
+        out[outOff + 2] = (byte)x32;
+        out[outOff + 3] = (byte)(x32 >> 8);
+        out[outOff + 4] = (byte)x54;
+        out[outOff + 5] = (byte)(x54 >> 8);
+        out[outOff + 6] = (byte)x76;
+        out[outOff + 7] = (byte)(x76 >> 8);
+    }
+
+    private void decryptBlock(
+        byte[]  in,
+        int     inOff,
+        byte[]  out,
+        int     outOff)
+    {
+        int x76, x54, x32, x10;
+
+        x76 = ((in[inOff + 7] & 0xff) << 8) + (in[inOff + 6] & 0xff);
+        x54 = ((in[inOff + 5] & 0xff) << 8) + (in[inOff + 4] & 0xff);
+        x32 = ((in[inOff + 3] & 0xff) << 8) + (in[inOff + 2] & 0xff);
+        x10 = ((in[inOff + 1] & 0xff) << 8) + (in[inOff + 0] & 0xff);
+
+        for (int i = 60; i >= 44; i -= 4)
+        {
+            x76 = rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+            x54 = rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+            x32 = rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+            x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i  ]);
+        }
+
+        x76 -= workingKey[x54 & 63];
+        x54 -= workingKey[x32 & 63];
+        x32 -= workingKey[x10 & 63];
+        x10 -= workingKey[x76 & 63];
+
+        for (int i = 40; i >= 20; i -= 4)
+        {
+            x76 = rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+            x54 = rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+            x32 = rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+            x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i  ]);
+        }
+
+        x76 -= workingKey[x54 & 63];
+        x54 -= workingKey[x32 & 63];
+        x32 -= workingKey[x10 & 63];
+        x10 -= workingKey[x76 & 63];
+
+        for (int i = 16; i >= 0; i -= 4)
+        {
+            x76 = rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+            x54 = rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+            x32 = rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+            x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i  ]);
+        }
+
+        out[outOff + 0] = (byte)x10;
+        out[outOff + 1] = (byte)(x10 >> 8);
+        out[outOff + 2] = (byte)x32;
+        out[outOff + 3] = (byte)(x32 >> 8);
+        out[outOff + 4] = (byte)x54;
+        out[outOff + 5] = (byte)(x54 >> 8);
+        out[outOff + 6] = (byte)x76;
+        out[outOff + 7] = (byte)(x76 >> 8);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RC4Engine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RC4Engine.java
new file mode 100644
index 0000000..02c138c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RC4Engine.java
@@ -0,0 +1,150 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.StreamCipher;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RC4Engine implements StreamCipher
+{
+    private final static int STATE_LENGTH = 256;
+
+    /*
+     * variables to hold the state of the RC4 engine
+     * during encryption and decryption
+     */
+
+    private byte[]      engineState = null;
+    private int         x = 0;
+    private int         y = 0;
+    private byte[]      workingKey = null;
+
+    /**
+     * initialise a RC4 cipher.
+     *
+     * @param forEncryption whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             forEncryption, 
+        CipherParameters     params
+   )
+    {
+        if (params instanceof KeyParameter)
+        {
+            /* 
+             * RC4 encryption and decryption is completely
+             * symmetrical, so the 'forEncryption' is 
+             * irrelevant.
+             */
+            workingKey = ((KeyParameter)params).getKey();
+            setKey(workingKey);
+
+            return;
+        }
+
+        throw new IllegalArgumentException("invalid parameter passed to RC4 init - " + params.getClass().getName());
+    }
+
+    public String getAlgorithmName()
+    {
+        return "RC4";
+    }
+
+    public byte returnByte(byte in)
+    {
+        x = (x + 1) & 0xff;
+        y = (engineState[x] + y) & 0xff;
+
+        // swap
+        byte tmp = engineState[x];
+        engineState[x] = engineState[y];
+        engineState[y] = tmp;
+
+        // xor
+        return (byte)(in ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+    }
+
+    public int processBytes(
+        byte[]     in, 
+        int     inOff, 
+        int     len, 
+        byte[]     out, 
+        int     outOff)
+    {
+        if ((inOff + len) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + len) > out.length)
+        {
+            throw new OutputLengthException("output buffer too short");
+        }
+
+        for (int i = 0; i < len ; i++)
+        {
+            x = (x + 1) & 0xff;
+            y = (engineState[x] + y) & 0xff;
+
+            // swap
+            byte tmp = engineState[x];
+            engineState[x] = engineState[y];
+            engineState[y] = tmp;
+
+            // xor
+            out[i+outOff] = (byte)(in[i + inOff]
+                    ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+        }
+
+        return len;
+    }
+
+    public void reset()
+    {
+        setKey(workingKey);
+    }
+
+    // Private implementation
+
+    private void setKey(byte[] keyBytes)
+    {
+        workingKey = keyBytes;
+
+        // System.out.println("the key length is ; "+ workingKey.length);
+
+        x = 0;
+        y = 0;
+
+        if (engineState == null)
+        {
+            engineState = new byte[STATE_LENGTH];
+        }
+
+        // reset the state of the engine
+        for (int i=0; i < STATE_LENGTH; i++)
+        {
+            engineState[i] = (byte)i;
+        }
+        
+        int i1 = 0;
+        int i2 = 0;
+
+        for (int i=0; i < STATE_LENGTH; i++)
+        {
+            i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff;
+            // do the byte-swap inline
+            byte tmp = engineState[i];
+            engineState[i] = engineState[i2];
+            engineState[i2] = tmp;
+            i1 = (i1+1) % keyBytes.length; 
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java
new file mode 100644
index 0000000..f29cc07
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java
@@ -0,0 +1,197 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.Wrapper;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * an implementation of the AES Key Wrapper from the NIST Key Wrap
+ * Specification as described in RFC 3394.
+ * <p>
+ * For further details see: <a href="http://www.ietf.org/rfc/rfc3394.txt">http://www.ietf.org/rfc/rfc3394.txt</a>
+ * and  <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RFC3394WrapEngine
+    implements Wrapper
+{
+    private BlockCipher     engine;
+    private boolean         wrapCipherMode;
+    private KeyParameter    param;
+    private boolean         forWrapping;
+
+    private byte[]          iv = {
+                              (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6,
+                              (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6 };
+
+    /**
+     * Create a RFC 3394 WrapEngine specifying the encrypt for wrapping, decrypt for unwrapping.
+     *
+     * @param engine the block cipher to be used for wrapping.
+     */
+    public RFC3394WrapEngine(BlockCipher engine)
+    {
+        this(engine, false);
+    }
+
+    /**
+     * Create a RFC 3394 WrapEngine specifying the direction for wrapping and unwrapping..
+     *
+     * @param engine the block cipher to be used for wrapping.
+     * @param useReverseDirection true if engine should be used in decryption mode for wrapping, false otherwise.
+     */
+    public RFC3394WrapEngine(BlockCipher engine, boolean useReverseDirection)
+    {
+        this.engine = engine;
+        this.wrapCipherMode = (useReverseDirection) ? false : true;
+    }
+
+    public void init(
+        boolean             forWrapping,
+        CipherParameters    param)
+    {
+        this.forWrapping = forWrapping;
+
+        if (param instanceof ParametersWithRandom)
+        {
+            param = ((ParametersWithRandom) param).getParameters();
+        }
+
+        if (param instanceof KeyParameter)
+        {
+            this.param = (KeyParameter)param;
+        }
+        else if (param instanceof ParametersWithIV)
+        {
+            this.iv = ((ParametersWithIV)param).getIV();
+            this.param = (KeyParameter)((ParametersWithIV) param).getParameters();
+            if (this.iv.length != 8)
+            {
+               throw new IllegalArgumentException("IV not equal to 8");
+            }
+        }
+    }
+
+    public String getAlgorithmName()
+    {
+        return engine.getAlgorithmName();
+    }
+
+    public byte[] wrap(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+    {
+        if (!forWrapping)
+        {
+            throw new IllegalStateException("not set for wrapping");
+        }
+
+        int     n = inLen / 8;
+
+        if ((n * 8) != inLen)
+        {
+            throw new DataLengthException("wrap data must be a multiple of 8 bytes");
+        }
+
+        byte[]  block = new byte[inLen + iv.length];
+        byte[]  buf = new byte[8 + iv.length];
+
+        System.arraycopy(iv, 0, block, 0, iv.length);
+        System.arraycopy(in, inOff, block, iv.length, inLen);
+
+        engine.init(wrapCipherMode, param);
+
+        for (int j = 0; j != 6; j++)
+        {
+            for (int i = 1; i <= n; i++)
+            {
+                System.arraycopy(block, 0, buf, 0, iv.length);
+                System.arraycopy(block, 8 * i, buf, iv.length, 8);
+                engine.processBlock(buf, 0, buf, 0);
+
+                int t = n * j + i;
+                for (int k = 1; t != 0; k++)
+                {
+                    byte    v = (byte)t;
+
+                    buf[iv.length - k] ^= v;
+
+                    t >>>= 8;
+                }
+
+                System.arraycopy(buf, 0, block, 0, 8);
+                System.arraycopy(buf, 8, block, 8 * i, 8);
+            }
+        }
+
+        return block;
+    }
+
+    public byte[] unwrap(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        if (forWrapping)
+        {
+            throw new IllegalStateException("not set for unwrapping");
+        }
+
+        int     n = inLen / 8;
+
+        if ((n * 8) != inLen)
+        {
+            throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
+        }
+
+        byte[]  block = new byte[inLen - iv.length];
+        byte[]  a = new byte[iv.length];
+        byte[]  buf = new byte[8 + iv.length];
+
+        System.arraycopy(in, inOff, a, 0, iv.length);
+        System.arraycopy(in, inOff + iv.length, block, 0, inLen - iv.length);
+
+        engine.init(!wrapCipherMode, param);
+
+        n = n - 1;
+
+        for (int j = 5; j >= 0; j--)
+        {
+            for (int i = n; i >= 1; i--)
+            {
+                System.arraycopy(a, 0, buf, 0, iv.length);
+                System.arraycopy(block, 8 * (i - 1), buf, iv.length, 8);
+
+                int t = n * j + i;
+                for (int k = 1; t != 0; k++)
+                {
+                    byte    v = (byte)t;
+
+                    buf[iv.length - k] ^= v;
+
+                    t >>>= 8;
+                }
+
+                engine.processBlock(buf, 0, buf, 0);
+                System.arraycopy(buf, 0, a, 0, 8);
+                System.arraycopy(buf, 8, block, 8 * (i - 1), 8);
+            }
+        }
+
+        if (!Arrays.constantTimeAreEqual(a, iv))
+        {
+            throw new InvalidCipherTextException("checksum failed");
+        }
+
+        return block;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RSABlindedEngine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RSABlindedEngine.java
new file mode 100644
index 0000000..367f0d9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RSABlindedEngine.java
@@ -0,0 +1,134 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.AsymmetricBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.android.internal.org.bouncycastle.crypto.params.RSAKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * this does your basic RSA algorithm with blinding
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSABlindedEngine
+    implements AsymmetricBlockCipher
+{
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+
+    private RSACoreEngine    core = new RSACoreEngine();
+    private RSAKeyParameters key;
+    private SecureRandom     random;
+
+    /**
+     * initialise the RSA engine.
+     *
+     * @param forEncryption true if we are encrypting, false otherwise.
+     * @param param the necessary RSA key parameters.
+     */
+    public void init(
+        boolean             forEncryption,
+        CipherParameters    param)
+    {
+        core.init(forEncryption, param);
+
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom    rParam = (ParametersWithRandom)param;
+
+            key = (RSAKeyParameters)rParam.getParameters();
+            random = rParam.getRandom();
+        }
+        else
+        {
+            key = (RSAKeyParameters)param;
+            random = CryptoServicesRegistrar.getSecureRandom();
+        }
+    }
+
+    /**
+     * Return the maximum size for an input block to this engine.
+     * For RSA this is always one byte less than the key size on
+     * encryption, and the same length as the key size on decryption.
+     *
+     * @return maximum size for an input block.
+     */
+    public int getInputBlockSize()
+    {
+        return core.getInputBlockSize();
+    }
+
+    /**
+     * Return the maximum size for an output block to this engine.
+     * For RSA this is always one byte less than the key size on
+     * decryption, and the same length as the key size on encryption.
+     *
+     * @return maximum size for an output block.
+     */
+    public int getOutputBlockSize()
+    {
+        return core.getOutputBlockSize();
+    }
+
+    /**
+     * Process a single block using the basic RSA algorithm.
+     *
+     * @param in the input array.
+     * @param inOff the offset into the input buffer where the data starts.
+     * @param inLen the length of the data to be processed.
+     * @return the result of the RSA process.
+     * @exception DataLengthException the input block is too large.
+     */
+    public byte[] processBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+    {
+        if (key == null)
+        {
+            throw new IllegalStateException("RSA engine not initialised");
+        }
+
+        BigInteger input = core.convertInput(in, inOff, inLen);
+
+        BigInteger result;
+        if (key instanceof RSAPrivateCrtKeyParameters)
+        {
+            RSAPrivateCrtKeyParameters k = (RSAPrivateCrtKeyParameters)key;
+
+            BigInteger e = k.getPublicExponent();
+            if (e != null)   // can't do blinding without a public exponent
+            {
+                BigInteger m = k.getModulus();
+                BigInteger r = BigIntegers.createRandomInRange(ONE, m.subtract(ONE), random);
+
+                BigInteger blindedInput = r.modPow(e, m).multiply(input).mod(m);
+                BigInteger blindedResult = core.processBlock(blindedInput);
+
+                BigInteger rInv = r.modInverse(m);
+                result = blindedResult.multiply(rInv).mod(m);
+                // defence against Arjen Lenstra’s CRT attack
+                if (!input.equals(result.modPow(e, m)))
+                {
+                    throw new IllegalStateException("RSA engine faulty decryption/signing detected");
+                }
+            }
+            else
+            {
+                result = core.processBlock(input);
+            }
+        }
+        else
+        {
+            result = core.processBlock(input);
+        }
+
+        return core.convertOutput(result);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RSACoreEngine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RSACoreEngine.java
new file mode 100644
index 0000000..7ab640d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/RSACoreEngine.java
@@ -0,0 +1,214 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.android.internal.org.bouncycastle.crypto.params.RSAKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * this does your basic RSA algorithm.
+ */
+class RSACoreEngine
+{
+    private RSAKeyParameters key;
+    private boolean          forEncryption;
+
+    /**
+     * initialise the RSA engine.
+     *
+     * @param forEncryption true if we are encrypting, false otherwise.
+     * @param param the necessary RSA key parameters.
+     */
+    public void init(
+        boolean          forEncryption,
+        CipherParameters param)
+    {
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom    rParam = (ParametersWithRandom)param;
+
+            key = (RSAKeyParameters)rParam.getParameters();
+        }
+        else
+        {
+            key = (RSAKeyParameters)param;
+        }
+
+        this.forEncryption = forEncryption;
+    }
+
+    /**
+     * Return the maximum size for an input block to this engine.
+     * For RSA this is always one byte less than the key size on
+     * encryption, and the same length as the key size on decryption.
+     *
+     * @return maximum size for an input block.
+     */
+    public int getInputBlockSize()
+    {
+        int     bitSize = key.getModulus().bitLength();
+
+        if (forEncryption)
+        {
+            return (bitSize + 7) / 8 - 1;
+        }
+        else
+        {
+            return (bitSize + 7) / 8;
+        }
+    }
+
+    /**
+     * Return the maximum size for an output block to this engine.
+     * For RSA this is always one byte less than the key size on
+     * decryption, and the same length as the key size on encryption.
+     *
+     * @return maximum size for an output block.
+     */
+    public int getOutputBlockSize()
+    {
+        int     bitSize = key.getModulus().bitLength();
+
+        if (forEncryption)
+        {
+            return (bitSize + 7) / 8;
+        }
+        else
+        {
+            return (bitSize + 7) / 8 - 1;
+        }
+    }
+
+    public BigInteger convertInput(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+    {
+        if (inLen > (getInputBlockSize() + 1))
+        {
+            throw new DataLengthException("input too large for RSA cipher.");
+        }
+        else if (inLen == (getInputBlockSize() + 1) && !forEncryption)
+        {
+            throw new DataLengthException("input too large for RSA cipher.");
+        }
+
+        byte[]  block;
+
+        if (inOff != 0 || inLen != in.length)
+        {
+            block = new byte[inLen];
+
+            System.arraycopy(in, inOff, block, 0, inLen);
+        }
+        else
+        {
+            block = in;
+        }
+
+        BigInteger res = new BigInteger(1, block);
+        if (res.compareTo(key.getModulus()) >= 0)
+        {
+            throw new DataLengthException("input too large for RSA cipher.");
+        }
+
+        return res;
+    }
+
+    public byte[] convertOutput(
+        BigInteger result)
+    {
+        byte[]      output = result.toByteArray();
+
+        if (forEncryption)
+        {
+            if (output[0] == 0 && output.length > getOutputBlockSize())        // have ended up with an extra zero byte, copy down.
+            {
+                byte[]  tmp = new byte[output.length - 1];
+
+                System.arraycopy(output, 1, tmp, 0, tmp.length);
+
+                return tmp;
+            }
+
+            if (output.length < getOutputBlockSize())     // have ended up with less bytes than normal, lengthen
+            {
+                byte[]  tmp = new byte[getOutputBlockSize()];
+
+                System.arraycopy(output, 0, tmp, tmp.length - output.length, output.length);
+
+                return tmp;
+            }
+
+            return output;
+        }
+        else
+        {
+            byte[]  rv;
+            if (output[0] == 0)        // have ended up with an extra zero byte, copy down.
+            {
+                rv = new byte[output.length - 1];
+
+                System.arraycopy(output, 1, rv, 0, rv.length);
+            }
+            else        // maintain decryption time
+            {
+                rv = new byte[output.length];
+
+                System.arraycopy(output, 0, rv, 0, rv.length);
+            }
+
+            Arrays.fill(output, (byte)0);
+
+            return rv;
+        }
+    }
+
+    public BigInteger processBlock(BigInteger input)
+    {
+        if (key instanceof RSAPrivateCrtKeyParameters)
+        {
+            //
+            // we have the extra factors, use the Chinese Remainder Theorem - the author
+            // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
+            // advice regarding the expression of this.
+            //
+            RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)key;
+
+            BigInteger p = crtKey.getP();
+            BigInteger q = crtKey.getQ();
+            BigInteger dP = crtKey.getDP();
+            BigInteger dQ = crtKey.getDQ();
+            BigInteger qInv = crtKey.getQInv();
+
+            BigInteger mP, mQ, h, m;
+
+            // mP = ((input mod p) ^ dP)) mod p
+            mP = (input.remainder(p)).modPow(dP, p);
+
+            // mQ = ((input mod q) ^ dQ)) mod q
+            mQ = (input.remainder(q)).modPow(dQ, q);
+
+            // h = qInv * (mP - mQ) mod p
+            h = mP.subtract(mQ);
+            h = h.multiply(qInv);
+            h = h.mod(p);               // mod (in Java) returns the positive residual
+
+            // m = h * q + mQ
+            m = h.multiply(q);
+            m = m.add(mQ);
+
+            return m;
+        }
+        else
+        {
+            return input.modPow(
+                        key.getExponent(), key.getModulus());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/TwofishEngine.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/TwofishEngine.java
new file mode 100644
index 0000000..e7ba6de
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/engines/TwofishEngine.java
@@ -0,0 +1,682 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.engines;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * A class that provides Twofish encryption operations.
+ *
+ * This Java implementation is based on the Java reference
+ * implementation provided by Bruce Schneier and developed
+ * by Raif S. Naffah.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class TwofishEngine
+    implements BlockCipher
+{
+    private static final byte[][] P =  {
+    {  // p0
+        (byte) 0xA9, (byte) 0x67, (byte) 0xB3, (byte) 0xE8,
+        (byte) 0x04, (byte) 0xFD, (byte) 0xA3, (byte) 0x76,
+        (byte) 0x9A, (byte) 0x92, (byte) 0x80, (byte) 0x78,
+        (byte) 0xE4, (byte) 0xDD, (byte) 0xD1, (byte) 0x38,
+        (byte) 0x0D, (byte) 0xC6, (byte) 0x35, (byte) 0x98,
+        (byte) 0x18, (byte) 0xF7, (byte) 0xEC, (byte) 0x6C,
+        (byte) 0x43, (byte) 0x75, (byte) 0x37, (byte) 0x26,
+        (byte) 0xFA, (byte) 0x13, (byte) 0x94, (byte) 0x48,
+        (byte) 0xF2, (byte) 0xD0, (byte) 0x8B, (byte) 0x30,
+        (byte) 0x84, (byte) 0x54, (byte) 0xDF, (byte) 0x23,
+        (byte) 0x19, (byte) 0x5B, (byte) 0x3D, (byte) 0x59,
+        (byte) 0xF3, (byte) 0xAE, (byte) 0xA2, (byte) 0x82,
+        (byte) 0x63, (byte) 0x01, (byte) 0x83, (byte) 0x2E,
+        (byte) 0xD9, (byte) 0x51, (byte) 0x9B, (byte) 0x7C,
+        (byte) 0xA6, (byte) 0xEB, (byte) 0xA5, (byte) 0xBE,
+        (byte) 0x16, (byte) 0x0C, (byte) 0xE3, (byte) 0x61,
+        (byte) 0xC0, (byte) 0x8C, (byte) 0x3A, (byte) 0xF5,
+        (byte) 0x73, (byte) 0x2C, (byte) 0x25, (byte) 0x0B,
+        (byte) 0xBB, (byte) 0x4E, (byte) 0x89, (byte) 0x6B,
+        (byte) 0x53, (byte) 0x6A, (byte) 0xB4, (byte) 0xF1,
+        (byte) 0xE1, (byte) 0xE6, (byte) 0xBD, (byte) 0x45,
+        (byte) 0xE2, (byte) 0xF4, (byte) 0xB6, (byte) 0x66,
+        (byte) 0xCC, (byte) 0x95, (byte) 0x03, (byte) 0x56,
+        (byte) 0xD4, (byte) 0x1C, (byte) 0x1E, (byte) 0xD7,
+        (byte) 0xFB, (byte) 0xC3, (byte) 0x8E, (byte) 0xB5,
+        (byte) 0xE9, (byte) 0xCF, (byte) 0xBF, (byte) 0xBA,
+        (byte) 0xEA, (byte) 0x77, (byte) 0x39, (byte) 0xAF,
+        (byte) 0x33, (byte) 0xC9, (byte) 0x62, (byte) 0x71,
+        (byte) 0x81, (byte) 0x79, (byte) 0x09, (byte) 0xAD,
+        (byte) 0x24, (byte) 0xCD, (byte) 0xF9, (byte) 0xD8,
+        (byte) 0xE5, (byte) 0xC5, (byte) 0xB9, (byte) 0x4D,
+        (byte) 0x44, (byte) 0x08, (byte) 0x86, (byte) 0xE7,
+        (byte) 0xA1, (byte) 0x1D, (byte) 0xAA, (byte) 0xED,
+        (byte) 0x06, (byte) 0x70, (byte) 0xB2, (byte) 0xD2,
+        (byte) 0x41, (byte) 0x7B, (byte) 0xA0, (byte) 0x11,
+        (byte) 0x31, (byte) 0xC2, (byte) 0x27, (byte) 0x90,
+        (byte) 0x20, (byte) 0xF6, (byte) 0x60, (byte) 0xFF,
+        (byte) 0x96, (byte) 0x5C, (byte) 0xB1, (byte) 0xAB,
+        (byte) 0x9E, (byte) 0x9C, (byte) 0x52, (byte) 0x1B,
+        (byte) 0x5F, (byte) 0x93, (byte) 0x0A, (byte) 0xEF,
+        (byte) 0x91, (byte) 0x85, (byte) 0x49, (byte) 0xEE,
+        (byte) 0x2D, (byte) 0x4F, (byte) 0x8F, (byte) 0x3B,
+        (byte) 0x47, (byte) 0x87, (byte) 0x6D, (byte) 0x46,
+        (byte) 0xD6, (byte) 0x3E, (byte) 0x69, (byte) 0x64,
+        (byte) 0x2A, (byte) 0xCE, (byte) 0xCB, (byte) 0x2F,
+        (byte) 0xFC, (byte) 0x97, (byte) 0x05, (byte) 0x7A,
+        (byte) 0xAC, (byte) 0x7F, (byte) 0xD5, (byte) 0x1A,
+        (byte) 0x4B, (byte) 0x0E, (byte) 0xA7, (byte) 0x5A,
+        (byte) 0x28, (byte) 0x14, (byte) 0x3F, (byte) 0x29,
+        (byte) 0x88, (byte) 0x3C, (byte) 0x4C, (byte) 0x02,
+        (byte) 0xB8, (byte) 0xDA, (byte) 0xB0, (byte) 0x17,
+        (byte) 0x55, (byte) 0x1F, (byte) 0x8A, (byte) 0x7D,
+        (byte) 0x57, (byte) 0xC7, (byte) 0x8D, (byte) 0x74,
+        (byte) 0xB7, (byte) 0xC4, (byte) 0x9F, (byte) 0x72,
+        (byte) 0x7E, (byte) 0x15, (byte) 0x22, (byte) 0x12,
+        (byte) 0x58, (byte) 0x07, (byte) 0x99, (byte) 0x34,
+        (byte) 0x6E, (byte) 0x50, (byte) 0xDE, (byte) 0x68,
+        (byte) 0x65, (byte) 0xBC, (byte) 0xDB, (byte) 0xF8,
+        (byte) 0xC8, (byte) 0xA8, (byte) 0x2B, (byte) 0x40,
+        (byte) 0xDC, (byte) 0xFE, (byte) 0x32, (byte) 0xA4,
+        (byte) 0xCA, (byte) 0x10, (byte) 0x21, (byte) 0xF0,
+        (byte) 0xD3, (byte) 0x5D, (byte) 0x0F, (byte) 0x00,
+        (byte) 0x6F, (byte) 0x9D, (byte) 0x36, (byte) 0x42,
+        (byte) 0x4A, (byte) 0x5E, (byte) 0xC1, (byte) 0xE0 },
+    {  // p1
+        (byte) 0x75, (byte) 0xF3, (byte) 0xC6, (byte) 0xF4,
+        (byte) 0xDB, (byte) 0x7B, (byte) 0xFB, (byte) 0xC8,
+        (byte) 0x4A, (byte) 0xD3, (byte) 0xE6, (byte) 0x6B,
+        (byte) 0x45, (byte) 0x7D, (byte) 0xE8, (byte) 0x4B,
+        (byte) 0xD6, (byte) 0x32, (byte) 0xD8, (byte) 0xFD,
+        (byte) 0x37, (byte) 0x71, (byte) 0xF1, (byte) 0xE1,
+        (byte) 0x30, (byte) 0x0F, (byte) 0xF8, (byte) 0x1B,
+        (byte) 0x87, (byte) 0xFA, (byte) 0x06, (byte) 0x3F,
+        (byte) 0x5E, (byte) 0xBA, (byte) 0xAE, (byte) 0x5B,
+        (byte) 0x8A, (byte) 0x00, (byte) 0xBC, (byte) 0x9D,
+        (byte) 0x6D, (byte) 0xC1, (byte) 0xB1, (byte) 0x0E,
+        (byte) 0x80, (byte) 0x5D, (byte) 0xD2, (byte) 0xD5,
+        (byte) 0xA0, (byte) 0x84, (byte) 0x07, (byte) 0x14,
+        (byte) 0xB5, (byte) 0x90, (byte) 0x2C, (byte) 0xA3,
+        (byte) 0xB2, (byte) 0x73, (byte) 0x4C, (byte) 0x54,
+        (byte) 0x92, (byte) 0x74, (byte) 0x36, (byte) 0x51,
+        (byte) 0x38, (byte) 0xB0, (byte) 0xBD, (byte) 0x5A,
+        (byte) 0xFC, (byte) 0x60, (byte) 0x62, (byte) 0x96,
+        (byte) 0x6C, (byte) 0x42, (byte) 0xF7, (byte) 0x10,
+        (byte) 0x7C, (byte) 0x28, (byte) 0x27, (byte) 0x8C,
+        (byte) 0x13, (byte) 0x95, (byte) 0x9C, (byte) 0xC7,
+        (byte) 0x24, (byte) 0x46, (byte) 0x3B, (byte) 0x70,
+        (byte) 0xCA, (byte) 0xE3, (byte) 0x85, (byte) 0xCB,
+        (byte) 0x11, (byte) 0xD0, (byte) 0x93, (byte) 0xB8,
+        (byte) 0xA6, (byte) 0x83, (byte) 0x20, (byte) 0xFF,
+        (byte) 0x9F, (byte) 0x77, (byte) 0xC3, (byte) 0xCC,
+        (byte) 0x03, (byte) 0x6F, (byte) 0x08, (byte) 0xBF,
+        (byte) 0x40, (byte) 0xE7, (byte) 0x2B, (byte) 0xE2,
+        (byte) 0x79, (byte) 0x0C, (byte) 0xAA, (byte) 0x82,
+        (byte) 0x41, (byte) 0x3A, (byte) 0xEA, (byte) 0xB9,
+        (byte) 0xE4, (byte) 0x9A, (byte) 0xA4, (byte) 0x97,
+        (byte) 0x7E, (byte) 0xDA, (byte) 0x7A, (byte) 0x17,
+        (byte) 0x66, (byte) 0x94, (byte) 0xA1, (byte) 0x1D,
+        (byte) 0x3D, (byte) 0xF0, (byte) 0xDE, (byte) 0xB3,
+        (byte) 0x0B, (byte) 0x72, (byte) 0xA7, (byte) 0x1C,
+        (byte) 0xEF, (byte) 0xD1, (byte) 0x53, (byte) 0x3E,
+        (byte) 0x8F, (byte) 0x33, (byte) 0x26, (byte) 0x5F,
+        (byte) 0xEC, (byte) 0x76, (byte) 0x2A, (byte) 0x49,
+        (byte) 0x81, (byte) 0x88, (byte) 0xEE, (byte) 0x21,
+        (byte) 0xC4, (byte) 0x1A, (byte) 0xEB, (byte) 0xD9,
+        (byte) 0xC5, (byte) 0x39, (byte) 0x99, (byte) 0xCD,
+        (byte) 0xAD, (byte) 0x31, (byte) 0x8B, (byte) 0x01,
+        (byte) 0x18, (byte) 0x23, (byte) 0xDD, (byte) 0x1F,
+        (byte) 0x4E, (byte) 0x2D, (byte) 0xF9, (byte) 0x48,
+        (byte) 0x4F, (byte) 0xF2, (byte) 0x65, (byte) 0x8E,
+        (byte) 0x78, (byte) 0x5C, (byte) 0x58, (byte) 0x19,
+        (byte) 0x8D, (byte) 0xE5, (byte) 0x98, (byte) 0x57,
+        (byte) 0x67, (byte) 0x7F, (byte) 0x05, (byte) 0x64,
+        (byte) 0xAF, (byte) 0x63, (byte) 0xB6, (byte) 0xFE,
+        (byte) 0xF5, (byte) 0xB7, (byte) 0x3C, (byte) 0xA5,
+        (byte) 0xCE, (byte) 0xE9, (byte) 0x68, (byte) 0x44,
+        (byte) 0xE0, (byte) 0x4D, (byte) 0x43, (byte) 0x69,
+        (byte) 0x29, (byte) 0x2E, (byte) 0xAC, (byte) 0x15,
+        (byte) 0x59, (byte) 0xA8, (byte) 0x0A, (byte) 0x9E,
+        (byte) 0x6E, (byte) 0x47, (byte) 0xDF, (byte) 0x34,
+        (byte) 0x35, (byte) 0x6A, (byte) 0xCF, (byte) 0xDC,
+        (byte) 0x22, (byte) 0xC9, (byte) 0xC0, (byte) 0x9B,
+        (byte) 0x89, (byte) 0xD4, (byte) 0xED, (byte) 0xAB,
+        (byte) 0x12, (byte) 0xA2, (byte) 0x0D, (byte) 0x52,
+        (byte) 0xBB, (byte) 0x02, (byte) 0x2F, (byte) 0xA9,
+        (byte) 0xD7, (byte) 0x61, (byte) 0x1E, (byte) 0xB4,
+        (byte) 0x50, (byte) 0x04, (byte) 0xF6, (byte) 0xC2,
+        (byte) 0x16, (byte) 0x25, (byte) 0x86, (byte) 0x56,
+        (byte) 0x55, (byte) 0x09, (byte) 0xBE, (byte) 0x91  }
+    };
+
+    /**
+    * Define the fixed p0/p1 permutations used in keyed S-box lookup.
+    * By changing the following constant definitions, the S-boxes will
+    * automatically get changed in the Twofish engine.
+    */
+    private static final int P_00 = 1;
+    private static final int P_01 = 0;
+    private static final int P_02 = 0;
+    private static final int P_03 = P_01 ^ 1;
+    private static final int P_04 = 1;
+
+    private static final int P_10 = 0;
+    private static final int P_11 = 0;
+    private static final int P_12 = 1;
+    private static final int P_13 = P_11 ^ 1;
+    private static final int P_14 = 0;
+
+    private static final int P_20 = 1;
+    private static final int P_21 = 1;
+    private static final int P_22 = 0;
+    private static final int P_23 = P_21 ^ 1;
+    private static final int P_24 = 0;
+
+    private static final int P_30 = 0;
+    private static final int P_31 = 1;
+    private static final int P_32 = 1;
+    private static final int P_33 = P_31 ^ 1;
+    private static final int P_34 = 1;
+
+    /* Primitive polynomial for GF(256) */
+    private static final int GF256_FDBK =   0x169;
+    private static final int GF256_FDBK_2 = GF256_FDBK / 2;
+    private static final int GF256_FDBK_4 = GF256_FDBK / 4;
+
+    private static final int RS_GF_FDBK = 0x14D; // field generator
+
+    //====================================
+    // Useful constants
+    //====================================
+
+    private static final int    ROUNDS = 16;
+    private static final int    MAX_ROUNDS = 16;  // bytes = 128 bits
+    private static final int    BLOCK_SIZE = 16;  // bytes = 128 bits
+    private static final int    MAX_KEY_BITS = 256;
+
+    private static final int    INPUT_WHITEN=0;
+    private static final int    OUTPUT_WHITEN=INPUT_WHITEN+BLOCK_SIZE/4; // 4
+    private static final int    ROUND_SUBKEYS=OUTPUT_WHITEN+BLOCK_SIZE/4;// 8
+
+    private static final int    TOTAL_SUBKEYS=ROUND_SUBKEYS+2*MAX_ROUNDS;// 40
+
+    private static final int    SK_STEP = 0x02020202;
+    private static final int    SK_BUMP = 0x01010101;
+    private static final int    SK_ROTL = 9;
+
+    private boolean encrypting = false;
+
+    private int[] gMDS0 = new int[MAX_KEY_BITS];
+    private int[] gMDS1 = new int[MAX_KEY_BITS];
+    private int[] gMDS2 = new int[MAX_KEY_BITS];
+    private int[] gMDS3 = new int[MAX_KEY_BITS];
+
+    /**
+     * gSubKeys[] and gSBox[] are eventually used in the 
+     * encryption and decryption methods.
+     */
+    private int[] gSubKeys;
+    private int[] gSBox;
+
+    private int k64Cnt = 0;
+
+    private byte[] workingKey = null;
+
+    public TwofishEngine()
+    {
+        // calculate the MDS matrix
+        int[] m1 = new int[2];
+        int[] mX = new int[2];
+        int[] mY = new int[2];
+        int j;
+
+        for (int i=0; i< MAX_KEY_BITS ; i++)
+        {
+            j = P[0][i] & 0xff;
+            m1[0] = j;
+            mX[0] = Mx_X(j) & 0xff;
+            mY[0] = Mx_Y(j) & 0xff;
+
+            j = P[1][i] & 0xff;
+            m1[1] = j;
+            mX[1] = Mx_X(j) & 0xff;
+            mY[1] = Mx_Y(j) & 0xff;
+
+            gMDS0[i] = m1[P_00]       | mX[P_00] <<  8 |
+                         mY[P_00] << 16 | mY[P_00] << 24;
+
+            gMDS1[i] = mY[P_10]       | mY[P_10] <<  8 |
+                         mX[P_10] << 16 | m1[P_10] << 24;
+
+            gMDS2[i] = mX[P_20]       | mY[P_20] <<  8 |
+                         m1[P_20] << 16 | mY[P_20] << 24;
+
+            gMDS3[i] = mX[P_30]       | m1[P_30] <<  8 |
+                         mY[P_30] << 16 | mX[P_30] << 24;
+        }
+    }
+
+    /**
+     * initialise a Twofish cipher.
+     *
+     * @param encrypting whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             encrypting,
+        CipherParameters    params)
+    {
+        if (params instanceof KeyParameter)
+        {
+            this.encrypting = encrypting;
+            this.workingKey = ((KeyParameter)params).getKey();
+            this.k64Cnt = (this.workingKey.length / 8); // pre-padded ?
+            setKey(this.workingKey);
+
+            return;
+        }
+
+        throw new IllegalArgumentException("invalid parameter passed to Twofish init - " + params.getClass().getName());
+    }
+
+    public String getAlgorithmName()
+    {
+        return "Twofish";
+    }
+
+    public int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (workingKey == null)
+        {
+            throw new IllegalStateException("Twofish not initialised");
+        }
+
+        if ((inOff + BLOCK_SIZE) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + BLOCK_SIZE) > out.length)
+        {
+            throw new OutputLengthException("output buffer too short");
+        }
+
+        if (encrypting)
+        {
+            encryptBlock(in, inOff, out, outOff);
+        }
+        else
+        {    
+            decryptBlock(in, inOff, out, outOff);
+        }
+
+        return BLOCK_SIZE;
+    }
+
+    public void reset()
+    {
+        if (this.workingKey != null)
+        {
+            setKey(this.workingKey);
+        }
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    //==================================
+    // Private Implementation
+    //==================================
+
+    private void setKey(byte[] key)
+    {
+        int[] k32e = new int[MAX_KEY_BITS/64]; // 4
+        int[] k32o = new int[MAX_KEY_BITS/64]; // 4 
+
+        int[] sBoxKeys = new int[MAX_KEY_BITS/64]; // 4 
+        gSubKeys = new int[TOTAL_SUBKEYS];
+
+        if (k64Cnt < 1) 
+        {
+            throw new IllegalArgumentException("Key size less than 64 bits");
+        }
+        
+        if (k64Cnt > 4)
+        {
+            throw new IllegalArgumentException("Key size larger than 256 bits");
+        }
+
+        /*
+         * k64Cnt is the number of 8 byte blocks (64 chunks)
+         * that are in the input key.  The input key is a
+         * maximum of 32 bytes (256 bits), so the range
+         * for k64Cnt is 1..4
+         */
+        for (int i=0; i<k64Cnt ; i++)
+        {
+            int p = i* 8;
+
+            k32e[i] = BytesTo32Bits(key, p);
+            k32o[i] = BytesTo32Bits(key, p+4);
+
+            sBoxKeys[k64Cnt-1-i] = RS_MDS_Encode(k32e[i], k32o[i]);
+        }
+
+        int q,A,B;
+        for (int i=0; i < TOTAL_SUBKEYS / 2 ; i++) 
+        {
+            q = i*SK_STEP;
+            A = F32(q,         k32e);
+            B = F32(q+SK_BUMP, k32o);
+            B = B << 8 | B >>> 24;
+            A += B;
+            gSubKeys[i*2] = A;
+            A += B;
+            gSubKeys[i*2 + 1] = A << SK_ROTL | A >>> (32-SK_ROTL);
+        }
+
+        /*
+         * fully expand the table for speed
+         */
+        int k0 = sBoxKeys[0];
+        int k1 = sBoxKeys[1];
+        int k2 = sBoxKeys[2];
+        int k3 = sBoxKeys[3];
+        int b0, b1, b2, b3;
+        gSBox = new int[4*MAX_KEY_BITS];
+        for (int i=0; i<MAX_KEY_BITS; i++)
+        {
+            b0 = b1 = b2 = b3 = i;
+            switch (k64Cnt & 3)
+            {
+                case 1:
+                    gSBox[i*2]       = gMDS0[(P[P_01][b0] & 0xff) ^ b0(k0)];
+                    gSBox[i*2+1]     = gMDS1[(P[P_11][b1] & 0xff) ^ b1(k0)];
+                    gSBox[i*2+0x200] = gMDS2[(P[P_21][b2] & 0xff) ^ b2(k0)];
+                    gSBox[i*2+0x201] = gMDS3[(P[P_31][b3] & 0xff) ^ b3(k0)];
+                break;
+                case 0: // 256 bits of key
+                    b0 = (P[P_04][b0] & 0xff) ^ b0(k3);
+                    b1 = (P[P_14][b1] & 0xff) ^ b1(k3);
+                    b2 = (P[P_24][b2] & 0xff) ^ b2(k3);
+                    b3 = (P[P_34][b3] & 0xff) ^ b3(k3);
+                    // fall through, having pre-processed b[0]..b[3] with k32[3]
+                case 3: // 192 bits of key
+                    b0 = (P[P_03][b0] & 0xff) ^ b0(k2);
+                    b1 = (P[P_13][b1] & 0xff) ^ b1(k2);
+                    b2 = (P[P_23][b2] & 0xff) ^ b2(k2);
+                    b3 = (P[P_33][b3] & 0xff) ^ b3(k2);
+                    // fall through, having pre-processed b[0]..b[3] with k32[2]
+                case 2: // 128 bits of key
+                    gSBox[i*2]   = gMDS0[(P[P_01]
+                        [(P[P_02][b0] & 0xff) ^ b0(k1)] & 0xff) ^ b0(k0)];
+                    gSBox[i*2+1] = gMDS1[(P[P_11]
+                        [(P[P_12][b1] & 0xff) ^ b1(k1)] & 0xff) ^ b1(k0)];
+                    gSBox[i*2+0x200] = gMDS2[(P[P_21]
+                        [(P[P_22][b2] & 0xff) ^ b2(k1)] & 0xff) ^ b2(k0)];
+                    gSBox[i*2+0x201] = gMDS3[(P[P_31]
+                        [(P[P_32][b3] & 0xff) ^ b3(k1)] & 0xff) ^ b3(k0)];
+                break;
+            }
+        }
+
+        /* 
+         * the function exits having setup the gSBox with the 
+         * input key material.
+         */
+    }
+
+    /**
+     * Encrypt the given input starting at the given offset and place
+     * the result in the provided buffer starting at the given offset.
+     * The input will be an exact multiple of our blocksize.
+     *
+     * encryptBlock uses the pre-calculated gSBox[] and subKey[]
+     * arrays.
+     */
+    private void encryptBlock(
+        byte[] src, 
+        int srcIndex,
+        byte[] dst,
+        int dstIndex)
+    {
+        int x0 = BytesTo32Bits(src, srcIndex) ^ gSubKeys[INPUT_WHITEN];
+        int x1 = BytesTo32Bits(src, srcIndex + 4) ^ gSubKeys[INPUT_WHITEN + 1];
+        int x2 = BytesTo32Bits(src, srcIndex + 8) ^ gSubKeys[INPUT_WHITEN + 2];
+        int x3 = BytesTo32Bits(src, srcIndex + 12) ^ gSubKeys[INPUT_WHITEN + 3];
+
+        int k = ROUND_SUBKEYS;
+        int t0, t1;
+        for (int r = 0; r < ROUNDS; r +=2)
+        {
+            t0 = Fe32_0(x0);
+            t1 = Fe32_3(x1);
+            x2 ^= t0 + t1 + gSubKeys[k++];
+            x2 = x2 >>>1 | x2 << 31;
+            x3 = (x3 << 1 | x3 >>> 31) ^ (t0 + 2*t1 + gSubKeys[k++]);
+
+            t0 = Fe32_0(x2);
+            t1 = Fe32_3(x3);
+            x0 ^= t0 + t1 + gSubKeys[k++];
+            x0 = x0 >>>1 | x0 << 31;
+            x1 = (x1 << 1 | x1 >>> 31) ^ (t0 + 2*t1 + gSubKeys[k++]);
+        }
+
+        Bits32ToBytes(x2 ^ gSubKeys[OUTPUT_WHITEN], dst, dstIndex);
+        Bits32ToBytes(x3 ^ gSubKeys[OUTPUT_WHITEN + 1], dst, dstIndex + 4);
+        Bits32ToBytes(x0 ^ gSubKeys[OUTPUT_WHITEN + 2], dst, dstIndex + 8);
+        Bits32ToBytes(x1 ^ gSubKeys[OUTPUT_WHITEN + 3], dst, dstIndex + 12);
+    }
+
+    /**
+     * Decrypt the given input starting at the given offset and place
+     * the result in the provided buffer starting at the given offset.
+     * The input will be an exact multiple of our blocksize.
+     */
+    private void decryptBlock(
+        byte[] src, 
+        int srcIndex,
+        byte[] dst,
+        int dstIndex)
+    {
+        int x2 = BytesTo32Bits(src, srcIndex) ^ gSubKeys[OUTPUT_WHITEN];
+        int x3 = BytesTo32Bits(src, srcIndex+4) ^ gSubKeys[OUTPUT_WHITEN + 1];
+        int x0 = BytesTo32Bits(src, srcIndex+8) ^ gSubKeys[OUTPUT_WHITEN + 2];
+        int x1 = BytesTo32Bits(src, srcIndex+12) ^ gSubKeys[OUTPUT_WHITEN + 3];
+
+        int k = ROUND_SUBKEYS + 2 * ROUNDS -1 ;
+        int t0, t1;
+        for (int r = 0; r< ROUNDS ; r +=2)
+        {
+            t0 = Fe32_0(x2);
+            t1 = Fe32_3(x3);
+            x1 ^= t0 + 2*t1 + gSubKeys[k--];
+            x0 = (x0 << 1 | x0 >>> 31) ^ (t0 + t1 + gSubKeys[k--]);
+            x1 = x1 >>>1 | x1 << 31;
+
+            t0 = Fe32_0(x0);
+            t1 = Fe32_3(x1);
+            x3 ^= t0 + 2*t1 + gSubKeys[k--];
+            x2 = (x2 << 1 | x2 >>> 31) ^ (t0 + t1 + gSubKeys[k--]);
+            x3 = x3 >>>1 | x3 << 31;
+        }
+
+        Bits32ToBytes(x0 ^ gSubKeys[INPUT_WHITEN], dst, dstIndex);
+        Bits32ToBytes(x1 ^ gSubKeys[INPUT_WHITEN + 1], dst, dstIndex + 4);
+        Bits32ToBytes(x2 ^ gSubKeys[INPUT_WHITEN + 2], dst, dstIndex + 8);
+        Bits32ToBytes(x3 ^ gSubKeys[INPUT_WHITEN + 3], dst, dstIndex + 12);
+    }
+
+    /* 
+     * TODO:  This can be optimised and made cleaner by combining
+     * the functionality in this function and applying it appropriately
+     * to the creation of the subkeys during key setup.
+     */
+    private int F32(int x, int[] k32)
+    {
+        int b0 = b0(x);
+        int b1 = b1(x);
+        int b2 = b2(x);
+        int b3 = b3(x);
+        int k0 = k32[0];
+        int k1 = k32[1];
+        int k2 = k32[2];
+        int k3 = k32[3];
+
+        int result = 0;
+        switch (k64Cnt & 3)
+        {
+            case 1:
+                result = gMDS0[(P[P_01][b0] & 0xff) ^ b0(k0)] ^
+                         gMDS1[(P[P_11][b1] & 0xff) ^ b1(k0)] ^
+                         gMDS2[(P[P_21][b2] & 0xff) ^ b2(k0)] ^
+                         gMDS3[(P[P_31][b3] & 0xff) ^ b3(k0)];
+                break;
+            case 0: /* 256 bits of key */
+                b0 = (P[P_04][b0] & 0xff) ^ b0(k3);
+                b1 = (P[P_14][b1] & 0xff) ^ b1(k3);
+                b2 = (P[P_24][b2] & 0xff) ^ b2(k3);
+                b3 = (P[P_34][b3] & 0xff) ^ b3(k3);
+            case 3: 
+                b0 = (P[P_03][b0] & 0xff) ^ b0(k2);
+                b1 = (P[P_13][b1] & 0xff) ^ b1(k2);
+                b2 = (P[P_23][b2] & 0xff) ^ b2(k2);
+                b3 = (P[P_33][b3] & 0xff) ^ b3(k2);
+            case 2:
+                result = 
+                gMDS0[(P[P_01][(P[P_02][b0]&0xff)^b0(k1)]&0xff)^b0(k0)] ^ 
+                gMDS1[(P[P_11][(P[P_12][b1]&0xff)^b1(k1)]&0xff)^b1(k0)] ^
+                gMDS2[(P[P_21][(P[P_22][b2]&0xff)^b2(k1)]&0xff)^b2(k0)] ^
+                gMDS3[(P[P_31][(P[P_32][b3]&0xff)^b3(k1)]&0xff)^b3(k0)];
+            break;
+        }
+        return result;
+    }
+
+    /**
+     * Use (12, 8) Reed-Solomon code over GF(256) to produce
+     * a key S-box 32-bit entity from 2 key material 32-bit
+     * entities.
+     *
+     * @param    k0 first 32-bit entity
+     * @param    k1 second 32-bit entity
+     * @return     Remainder polynomial generated using RS code
+     */
+    private int RS_MDS_Encode(int k0, int k1)
+    {
+        int r = k1;
+        for (int i = 0 ; i < 4 ; i++) // shift 1 byte at a time
+        {
+            r = RS_rem(r);
+        }
+        r ^= k0;
+        for (int i=0 ; i < 4 ; i++)
+        {
+            r = RS_rem(r);
+        }
+
+        return r;
+    }
+
+    /**
+     * Reed-Solomon code parameters: (12,8) reversible code:<p>
+     * <pre>
+     * g(x) = x^4 + (a+1/a)x^3 + ax^2 + (a+1/a)x + 1
+     * </pre>
+     * where a = primitive root of field generator 0x14D
+     */
+    private int RS_rem(int x)
+    {
+        int b = (x >>> 24) & 0xff;
+        int g2 = ((b << 1) ^ 
+                 ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff;
+        int g3 = ((b >>> 1) ^ 
+                 ((b & 0x01) != 0 ? (RS_GF_FDBK >>> 1) : 0)) ^ g2 ;
+        return ((x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b);
+    }
+        
+    private int LFSR1(int x)
+    {
+        return (x >> 1) ^ 
+                (((x & 0x01) != 0) ? GF256_FDBK_2 : 0);
+    }
+
+    private int LFSR2(int x)
+    {
+        return (x >> 2) ^
+                (((x & 0x02) != 0) ? GF256_FDBK_2 : 0) ^
+                (((x & 0x01) != 0) ? GF256_FDBK_4 : 0);
+    }
+
+    private int Mx_X(int x)
+    {
+        return x ^ LFSR2(x);
+    } // 5B
+
+    private int Mx_Y(int x)
+    {
+        return x ^ LFSR1(x) ^ LFSR2(x);
+    } // EF
+
+    private int b0(int x)
+    {
+        return x & 0xff;
+    }
+
+    private int b1(int x)
+    {
+        return (x >>> 8) & 0xff;
+    }
+
+    private int b2(int x)
+    {
+        return (x >>> 16) & 0xff;
+    }
+
+    private int b3(int x)
+    {
+        return (x >>> 24) & 0xff;
+    }
+
+    private int Fe32_0(int x)
+    {
+        return gSBox[ 0x000 + 2*(x & 0xff) ] ^
+               gSBox[ 0x001 + 2*((x >>> 8) & 0xff) ] ^
+               gSBox[ 0x200 + 2*((x >>> 16) & 0xff) ] ^
+               gSBox[ 0x201 + 2*((x >>> 24) & 0xff) ];
+    }
+    
+    private int Fe32_3(int x)
+    {
+        return gSBox[ 0x000 + 2*((x >>> 24) & 0xff) ] ^
+               gSBox[ 0x001 + 2*(x & 0xff) ] ^
+               gSBox[ 0x200 + 2*((x >>> 8) & 0xff) ] ^
+               gSBox[ 0x201 + 2*((x >>> 16) & 0xff) ];
+    }
+    
+    private int BytesTo32Bits(byte[] b, int p)
+    {
+        return ((b[p] & 0xff)) | 
+             ((b[p+1] & 0xff) << 8) |
+             ((b[p+2] & 0xff) << 16) |
+             ((b[p+3] & 0xff) << 24);
+    }
+
+    private void Bits32ToBytes(int in,  byte[] b, int offset)
+    {
+        b[offset] = (byte)in;
+        b[offset + 1] = (byte)(in >> 8);
+        b[offset + 2] = (byte)(in >> 16);
+        b[offset + 3] = (byte)(in >> 24);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DESKeyGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DESKeyGenerator.java
new file mode 100644
index 0000000..3a5090a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DESKeyGenerator.java
@@ -0,0 +1,52 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import com.android.internal.org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DESParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DESKeyGenerator
+    extends CipherKeyGenerator
+{
+    /**
+     * initialise the key generator - if strength is set to zero
+     * the key generated will be 64 bits in size, otherwise
+     * strength can be 64 or 56 bits (if you don't count the parity bits).
+     *
+     * @param param the parameters to be used for key generation
+     */
+    public void init(
+        KeyGenerationParameters param)
+    {
+        super.init(param);
+
+        if (strength == 0 || strength == (56 / 8))
+        {
+            strength = DESParameters.DES_KEY_LENGTH;
+        }
+        else if (strength != DESParameters.DES_KEY_LENGTH)
+        {
+            throw new IllegalArgumentException("DES key must be "
+                    + (DESParameters.DES_KEY_LENGTH * 8)
+                    + " bits long.");
+        }
+    }
+
+    public byte[] generateKey()
+    {
+        byte[]  newKey = new byte[DESParameters.DES_KEY_LENGTH];
+
+        do
+        {
+            random.nextBytes(newKey);
+
+            DESParameters.setOddParity(newKey);
+        }
+        while (DESParameters.isWeakKey(newKey, 0));
+
+        return newKey;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java
new file mode 100644
index 0000000..c718a7d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java
@@ -0,0 +1,68 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DESedeParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DESedeKeyGenerator
+    extends DESKeyGenerator
+{
+    private static final int MAX_IT = 20;
+
+    /**
+     * initialise the key generator - if strength is set to zero
+     * the key generated will be 192 bits in size, otherwise
+     * strength can be 128 or 192 (or 112 or 168 if you don't count
+     * parity bits), depending on whether you wish to do 2-key or 3-key
+     * triple DES.
+     *
+     * @param param the parameters to be used for key generation
+     */
+    public void init(
+        KeyGenerationParameters param)
+    {
+        this.random = param.getRandom();
+        this.strength = (param.getStrength() + 7) / 8;
+
+        if (strength == 0 || strength == (168 / 8))
+        {
+            strength = DESedeParameters.DES_EDE_KEY_LENGTH;
+        }
+        else if (strength == (112 / 8))
+        {
+            strength = 2 * DESedeParameters.DES_KEY_LENGTH;
+        }
+        else if (strength != DESedeParameters.DES_EDE_KEY_LENGTH
+                && strength != (2 * DESedeParameters.DES_KEY_LENGTH))
+        {
+            throw new IllegalArgumentException("DESede key must be "
+                + (DESedeParameters.DES_EDE_KEY_LENGTH * 8) + " or "
+                + (2 * 8 * DESedeParameters.DES_KEY_LENGTH)
+                + " bits long.");
+        }
+    }
+
+    public byte[] generateKey()
+    {
+        byte[]  newKey = new byte[strength];
+        int     count = 0;
+
+        do
+        {
+            random.nextBytes(newKey);
+
+            DESedeParameters.setOddParity(newKey);
+        }
+        while (++count < MAX_IT && (DESedeParameters.isWeakKey(newKey, 0, newKey.length) || !DESedeParameters.isRealEDEKey(newKey, 0)));
+
+        if (DESedeParameters.isWeakKey(newKey, 0, newKey.length) || !DESedeParameters.isRealEDEKey(newKey, 0))
+        {
+            throw new IllegalStateException("Unable to generate DES-EDE key");
+        }
+
+        return newKey;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHBasicKeyPairGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHBasicKeyPairGenerator.java
new file mode 100644
index 0000000..75d1e3c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHBasicKeyPairGenerator.java
@@ -0,0 +1,44 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHKeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPublicKeyParameters;
+
+import java.math.BigInteger;
+
+/**
+ * a basic Diffie-Hellman key pair generator.
+ *
+ * This generates keys consistent for use with the basic algorithm for
+ * Diffie-Hellman.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHBasicKeyPairGenerator
+    implements AsymmetricCipherKeyPairGenerator
+{
+    private DHKeyGenerationParameters param;
+
+    public void init(
+        KeyGenerationParameters param)
+    {
+        this.param = (DHKeyGenerationParameters)param;
+    }
+
+    public AsymmetricCipherKeyPair generateKeyPair()
+    {
+        DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.INSTANCE;
+        DHParameters dhp = param.getParameters();
+
+        BigInteger x = helper.calculatePrivate(dhp, param.getRandom()); 
+        BigInteger y = helper.calculatePublic(dhp, x);
+
+        return new AsymmetricCipherKeyPair(
+            new DHPublicKeyParameters(y, dhp),
+            new DHPrivateKeyParameters(x, dhp));
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
new file mode 100644
index 0000000..0ef8365
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
@@ -0,0 +1,68 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.math.ec.WNafUtil;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+class DHKeyGeneratorHelper
+{
+    static final DHKeyGeneratorHelper INSTANCE = new DHKeyGeneratorHelper();
+
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+    private static final BigInteger TWO = BigInteger.valueOf(2);
+
+    private DHKeyGeneratorHelper()
+    {
+    }
+
+    BigInteger calculatePrivate(DHParameters dhParams, SecureRandom random)
+    {
+        int limit = dhParams.getL();
+
+        if (limit != 0)
+        {
+            int minWeight = limit >>> 2;
+            for (;;)
+            {
+                BigInteger x = BigIntegers.createRandomBigInteger(limit, random).setBit(limit - 1);
+                if (WNafUtil.getNafWeight(x) >= minWeight)
+                {
+                    return x;
+                }
+            }
+        }
+
+        BigInteger min = TWO;
+        int m = dhParams.getM();
+        if (m != 0)
+        {
+            min = ONE.shiftLeft(m - 1);
+        }
+
+        BigInteger q = dhParams.getQ();
+        if (q == null)
+        {
+            q = dhParams.getP();
+        }
+        BigInteger max = q.subtract(TWO);
+
+        int minWeight = max.bitLength() >>> 2;
+        for (;;)
+        {
+            BigInteger x = BigIntegers.createRandomInRange(min, max, random);
+            if (WNafUtil.getNafWeight(x) >= minWeight)
+            {
+                return x;
+            }
+        }
+    }
+
+    BigInteger calculatePublic(DHParameters dhParams, BigInteger x)
+    {
+        return dhParams.getG().modPow(x, dhParams.getP());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHParametersGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHParametersGenerator.java
new file mode 100644
index 0000000..2b83ea9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHParametersGenerator.java
@@ -0,0 +1,57 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHParametersGenerator
+{
+    private int             size;
+    private int             certainty;
+    private SecureRandom    random;
+
+    private static final BigInteger TWO = BigInteger.valueOf(2);
+
+    /**
+     * Initialise the parameters generator.
+     * 
+     * @param size bit length for the prime p
+     * @param certainty level of certainty for the prime number tests
+     * @param random  a source of randomness
+     */
+    public void init(
+        int             size,
+        int             certainty,
+        SecureRandom    random)
+    {
+        this.size = size;
+        this.certainty = certainty;
+        this.random = random;
+    }
+
+    /**
+     * which generates the p and g values from the given parameters,
+     * returning the DHParameters object.
+     * <p>
+     * Note: can take a while...
+     * @return a generated Diffie-Hellman parameters object.
+     */
+    public DHParameters generateParameters()
+    {
+        //
+        // find a safe prime p where p = 2*q + 1, where p and q are prime.
+        //
+        BigInteger[] safePrimes = DHParametersHelper.generateSafePrimes(size, certainty, random);
+
+        BigInteger p = safePrimes[0];
+        BigInteger q = safePrimes[1];
+        BigInteger g = DHParametersHelper.selectGenerator(p, q, random);
+
+        return new DHParameters(p, g, q, TWO, null);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHParametersHelper.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHParametersHelper.java
new file mode 100644
index 0000000..f999286
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DHParametersHelper.java
@@ -0,0 +1,111 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+// Android-added: Log long-running operation
+import java.util.logging.Logger;
+import com.android.internal.org.bouncycastle.math.ec.WNafUtil;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+class DHParametersHelper
+{
+    // Android-added: Log long-running operation
+    private static final Logger logger = Logger.getLogger(DHParametersHelper.class.getName());
+
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+    private static final BigInteger TWO = BigInteger.valueOf(2);
+
+    /*
+     * Finds a pair of prime BigInteger's {p, q: p = 2q + 1}
+     * 
+     * (see: Handbook of Applied Cryptography 4.86)
+     */
+    static BigInteger[] generateSafePrimes(int size, int certainty, SecureRandom random)
+    {
+        // BEGIN Android-added: Log long-running operation
+        logger.info("Generating safe primes. This may take a long time.");
+        long start = System.currentTimeMillis();
+        int tries = 0;
+        // END Android-added: Log long-running operation
+        BigInteger p, q;
+        int qLength = size - 1;
+        int minWeight = size >>> 2;
+
+        for (;;)
+        {
+            // Android-added: Log long-running operation
+            tries++;
+            q = BigIntegers.createRandomPrime(qLength, 2, random);
+
+            // p <- 2q + 1
+            p = q.shiftLeft(1).add(ONE);
+
+            if (!p.isProbablePrime(certainty))
+            {
+                continue;
+            }
+
+            if (certainty > 2 && !q.isProbablePrime(certainty - 2))
+            {
+                continue;
+            }
+
+            /*
+             * Require a minimum weight of the NAF representation, since low-weight primes may be
+             * weak against a version of the number-field-sieve for the discrete-logarithm-problem.
+             * 
+             * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+             */
+            if (WNafUtil.getNafWeight(p) < minWeight)
+            {
+                continue;
+            }
+
+            break;
+        }
+        // BEGIN Android-added: Log long-running operation
+        long end = System.currentTimeMillis();
+        long duration = end - start;
+        logger.info("Generated safe primes: " + tries + " tries took " + duration + "ms");
+        // END Android-added: Log long-running operation
+
+        return new BigInteger[] { p, q };
+    }
+
+    /*
+     * Select a high order element of the multiplicative group Zp*
+     * 
+     * p and q must be s.t. p = 2*q + 1, where p and q are prime (see generateSafePrimes)
+     */
+    static BigInteger selectGenerator(BigInteger p, BigInteger q, SecureRandom random)
+    {
+        BigInteger pMinusTwo = p.subtract(TWO);
+        BigInteger g;
+
+        /*
+         * (see: Handbook of Applied Cryptography 4.80)
+         */
+//        do
+//        {
+//            g = BigIntegers.createRandomInRange(TWO, pMinusTwo, random);
+//        }
+//        while (g.modPow(TWO, p).equals(ONE) || g.modPow(q, p).equals(ONE));
+
+
+        /*
+         * RFC 2631 2.2.1.2 (and see: Handbook of Applied Cryptography 4.81)
+         */
+        do
+        {
+            BigInteger h = BigIntegers.createRandomInRange(TWO, pMinusTwo, random);
+
+            g = h.modPow(TWO, p);
+        }
+        while (g.equals(ONE));
+
+
+        return g;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java
new file mode 100644
index 0000000..570d45a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java
@@ -0,0 +1,71 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import com.android.internal.org.bouncycastle.math.ec.WNafUtil;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * a DSA key pair generator.
+ *
+ * This generates DSA keys in line with the method described 
+ * in <i>FIPS 186-3 B.1 FFC Key Pair Generation</i>.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSAKeyPairGenerator
+    implements AsymmetricCipherKeyPairGenerator
+{
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+
+    private DSAKeyGenerationParameters param;
+
+    public void init(
+        KeyGenerationParameters param)
+    {
+        this.param = (DSAKeyGenerationParameters)param;
+    }
+
+    public AsymmetricCipherKeyPair generateKeyPair()
+    {
+        DSAParameters dsaParams = param.getParameters();
+
+        BigInteger x = generatePrivateKey(dsaParams.getQ(), param.getRandom());
+        BigInteger y = calculatePublicKey(dsaParams.getP(), dsaParams.getG(), x);
+
+        return new AsymmetricCipherKeyPair(
+            new DSAPublicKeyParameters(y, dsaParams),
+            new DSAPrivateKeyParameters(x, dsaParams));
+    }
+
+    private static BigInteger generatePrivateKey(BigInteger q, SecureRandom random)
+    {
+        // B.1.2 Key Pair Generation by Testing Candidates
+        int minWeight = q.bitLength() >>> 2;
+        for (;;)
+        {
+            // TODO Prefer this method? (change test cases that used fixed random)
+            // B.1.1 Key Pair Generation Using Extra Random Bits
+//            BigInteger x = new BigInteger(q.bitLength() + 64, random).mod(q.subtract(ONE)).add(ONE);
+
+            BigInteger x = BigIntegers.createRandomInRange(ONE, q.subtract(ONE), random);
+            if (WNafUtil.getNafWeight(x) >= minWeight)
+            {
+                return x;
+            }
+        }
+    }
+
+    private static BigInteger calculatePublicKey(BigInteger p, BigInteger g, BigInteger x)
+    {
+        return g.modPow(x, p);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
new file mode 100644
index 0000000..3ea79d1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
@@ -0,0 +1,416 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameterGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAValidationParameters;
+// Android-changed: Use Android digests
+// import org.bouncycastle.crypto.util.DigestFactory;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * Generate suitable parameters for DSA, in line with FIPS 186-2, or FIPS 186-3.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSAParametersGenerator
+{
+    private static final BigInteger ZERO = BigInteger.valueOf(0);
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+    private static final BigInteger TWO = BigInteger.valueOf(2);
+
+    private Digest          digest;
+    private int             L, N;
+    private int             certainty;
+    private int             iterations;
+    private SecureRandom    random;
+    private boolean         use186_3;
+    private int             usageIndex;
+
+    public DSAParametersGenerator()
+    {
+        // Android-changed: Use Android digests
+        // this(DigestFactory.createSHA1());
+        this(AndroidDigestFactory.getSHA1());
+    }
+
+    public DSAParametersGenerator(Digest digest)
+    {
+        this.digest = digest;
+    }
+
+    /**
+     * initialise the key generator.
+     *
+     * @param size size of the key (range 2^512 -&gt; 2^1024 - 64 bit increments)
+     * @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
+     * @param random random byte source.
+     */
+    public void init(
+        int             size,
+        int             certainty,
+        SecureRandom    random)
+    {
+        this.L = size;
+        this.N = getDefaultN(size);
+        this.certainty = certainty;
+        this.iterations = Math.max(getMinimumIterations(L), (certainty + 1) / 2);
+        this.random = random;
+        this.use186_3 = false;
+        this.usageIndex = -1;
+    }
+
+    /**
+     * Initialise the key generator for DSA 2.
+     * <p>
+     *     Use this init method if you need to generate parameters for DSA 2 keys.
+     * </p>
+     *
+     * @param params  DSA 2 key generation parameters.
+     */
+    public void init(
+        DSAParameterGenerationParameters params)
+    {
+        int L = params.getL(), N = params.getN();
+
+        if ((L < 1024 || L > 3072) || L % 1024 != 0)
+        {
+            throw new IllegalArgumentException("L values must be between 1024 and 3072 and a multiple of 1024");
+        }
+        else if (L == 1024 && N != 160)
+        {
+            throw new IllegalArgumentException("N must be 160 for L = 1024");
+        }
+        else if (L == 2048 && (N != 224 && N != 256))
+        {
+            throw new IllegalArgumentException("N must be 224 or 256 for L = 2048");
+        }
+        else if (L == 3072 && N != 256)
+        {
+            throw new IllegalArgumentException("N must be 256 for L = 3072");
+        }
+
+        if (digest.getDigestSize() * 8 < N)
+        {
+            throw new IllegalStateException("Digest output size too small for value of N");
+        }
+
+        this.L = L;
+        this.N = N;
+        this.certainty = params.getCertainty();
+        this.iterations = Math.max(getMinimumIterations(L), (certainty + 1) / 2);
+        this.random = params.getRandom();
+        this.use186_3 = true;
+        this.usageIndex = params.getUsageIndex();
+    }
+
+    /**
+     * which generates the p and g values from the given parameters,
+     * returning the DSAParameters object.
+     * <p>
+     * Note: can take a while...
+     * @return a generated DSA parameters object.
+     */
+    public DSAParameters generateParameters()
+    {
+        return (use186_3)
+            ? generateParameters_FIPS186_3()
+            : generateParameters_FIPS186_2();
+    }
+
+    private DSAParameters generateParameters_FIPS186_2()
+    {
+        byte[]          seed = new byte[20];
+        byte[]          part1 = new byte[20];
+        byte[]          part2 = new byte[20];
+        byte[]          u = new byte[20];
+        int             n = (L - 1) / 160;
+        byte[]          w = new byte[L / 8];
+
+        // Android-changed: Use Android digests
+        // if (!(digest instanceof SHA1Digest))
+        if (!(digest.getAlgorithmName().equals("SHA-1")))
+        {
+            throw new IllegalStateException("can only use SHA-1 for generating FIPS 186-2 parameters");
+        }
+
+        for (;;)
+        {
+            random.nextBytes(seed);
+
+            hash(digest, seed, part1, 0);
+            System.arraycopy(seed, 0, part2, 0, seed.length);
+            inc(part2);
+            hash(digest, part2, part2, 0);
+
+            for (int i = 0; i != u.length; i++)
+            {
+                u[i] = (byte)(part1[i] ^ part2[i]);
+            }
+
+            u[0] |= (byte)0x80;
+            u[19] |= (byte)0x01;
+
+            BigInteger q = new BigInteger(1, u);
+
+            if (!isProbablePrime(q))
+            {
+                continue;
+            }
+
+            byte[] offset = Arrays.clone(seed);
+            inc(offset);
+
+            for (int counter = 0; counter < 4096; ++counter)
+            {
+                {
+                    for (int k = 1; k <= n; k++)
+                    {
+                        inc(offset);
+                        hash(digest, offset, w, w.length - k * part1.length);
+                    }
+
+                    int remaining = w.length - (n * part1.length);
+                    inc(offset);
+                    hash(digest, offset, part1, 0);
+                    System.arraycopy(part1, part1.length - remaining, w, 0, remaining);
+
+                    w[0] |= (byte)0x80;
+                }
+
+                BigInteger x = new BigInteger(1, w);
+
+                BigInteger c = x.mod(q.shiftLeft(1));
+
+                BigInteger p = x.subtract(c.subtract(ONE));
+
+                if (p.bitLength() != L)
+                {
+                    continue;
+                }
+
+                if (isProbablePrime(p))
+                {
+                    BigInteger g = calculateGenerator_FIPS186_2(p, q, random);
+
+                    return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter));
+                }
+            }
+        }
+    }
+
+    private static BigInteger calculateGenerator_FIPS186_2(BigInteger p, BigInteger q, SecureRandom r)
+    {
+        BigInteger e = p.subtract(ONE).divide(q);
+        BigInteger pSub2 = p.subtract(TWO);
+
+        for (;;)
+        {
+            BigInteger h = BigIntegers.createRandomInRange(TWO, pSub2, r);
+            BigInteger g = h.modPow(e, p);
+            if (g.bitLength() > 1)
+            {
+                return g;
+            }
+        }
+    }
+
+    /**
+     * generate suitable parameters for DSA, in line with
+     * <i>FIPS 186-3 A.1 Generation of the FFC Primes p and q</i>.
+     */
+    private DSAParameters generateParameters_FIPS186_3()
+    {
+// A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
+        // FIXME This should be configurable (digest size in bits must be >= N)
+        Digest d = digest;
+        int outlen = d.getDigestSize() * 8;
+
+// 1. Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2). If
+//    the pair is not in the list, then return INVALID.
+        // Note: checked at initialisation
+
+// 2. If (seedlen < N), then return INVALID.
+        // FIXME This should be configurable (must be >= N)
+        int seedlen = N;
+        byte[] seed = new byte[seedlen / 8];
+
+// 3. n = ceiling(L / outlen) - 1.
+        int n = (L - 1) / outlen;
+
+// 4. b = L - 1 - (n * outlen).
+        int b = (L - 1) % outlen;
+
+        byte[] w = new byte[L / 8];
+        byte[] output = new byte[d.getDigestSize()];
+        for (;;)
+        {
+// 5. Get an arbitrary sequence of seedlen bits as the domain_parameter_seed.
+            random.nextBytes(seed);
+
+// 6. U = Hash (domain_parameter_seed) mod 2^(N–1).
+            hash(d, seed, output, 0);
+
+            BigInteger U = new BigInteger(1, output).mod(ONE.shiftLeft(N - 1));
+
+// 7. q = 2^(N–1) + U + 1 – ( U mod 2).
+            BigInteger q = U.setBit(0).setBit(N - 1);
+
+// 8. Test whether or not q is prime as specified in Appendix C.3.
+            if (!isProbablePrime(q))
+            {
+// 9. If q is not a prime, then go to step 5.
+                continue;
+            }
+
+// 10. offset = 1.
+            // Note: 'offset' value managed incrementally
+            byte[] offset = Arrays.clone(seed);
+
+// 11. For counter = 0 to (4L – 1) do
+            int counterLimit = 4 * L;
+            for (int counter = 0; counter < counterLimit; ++counter)
+            {
+// 11.1 For j = 0 to n do
+//      Vj = Hash ((domain_parameter_seed + offset + j) mod 2^seedlen).
+// 11.2 W = V0 + (V1 ∗ 2^outlen) + ... + (V^(n–1) ∗ 2^((n–1) ∗ outlen)) + ((Vn mod 2^b) ∗ 2^(n ∗ outlen)).
+                {
+                    for (int j = 1; j <= n; ++j)
+                    {
+                        inc(offset);
+                        hash(d, offset, w, w.length - j * output.length);
+                    }
+
+                    int remaining = w.length - (n * output.length);
+                    inc(offset);
+                    hash(d, offset, output, 0);
+                    System.arraycopy(output, output.length - remaining, w, 0, remaining);
+
+// 11.3 X = W + 2^(L–1). Comment: 0 ≤ W < 2^(L–1); hence, 2^(L–1) ≤ X < 2^L.
+                    w[0] |= (byte)0x80;
+                }
+
+                BigInteger X = new BigInteger(1, w);
+ 
+// 11.4 c = X mod 2q.
+                BigInteger c = X.mod(q.shiftLeft(1));
+
+// 11.5 p = X - (c - 1). Comment: p ≡ 1 (mod 2q).
+                BigInteger p = X.subtract(c.subtract(ONE));
+
+// 11.6 If (p < 2^(L-1)), then go to step 11.9
+                if (p.bitLength() != L)
+                {
+                    continue;
+                }
+
+// 11.7 Test whether or not p is prime as specified in Appendix C.3.
+                if (isProbablePrime(p))
+                {
+// 11.8 If p is determined to be prime, then return VALID and the values of p, q and
+//      (optionally) the values of domain_parameter_seed and counter.
+                    if (usageIndex >= 0)
+                    {
+                        BigInteger g = calculateGenerator_FIPS186_3_Verifiable(d, p, q, seed, usageIndex);
+                        if (g != null)
+                        {
+                           return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter, usageIndex));
+                        }
+                    }
+
+                    BigInteger g = calculateGenerator_FIPS186_3_Unverifiable(p, q, random);
+
+                    return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter));
+                }
+
+// 11.9 offset = offset + n + 1.      Comment: Increment offset; then, as part of
+//                                    the loop in step 11, increment counter; if
+//                                    counter < 4L, repeat steps 11.1 through 11.8.
+                // Note: 'offset' value already incremented in inner loop
+            }
+// 12. Go to step 5.
+        }
+    }
+
+    private boolean isProbablePrime(BigInteger x)
+    {
+        /*
+         * TODO Use Primes class for FIPS 186-4 C.3 primality checking - but it breaks existing
+         * tests using FixedSecureRandom
+         */
+//        return !Primes.hasAnySmallFactors(x) && Primes.isMRProbablePrime(x, random, iterations);
+        return x.isProbablePrime(certainty);
+    }
+
+    private static BigInteger calculateGenerator_FIPS186_3_Unverifiable(BigInteger p, BigInteger q,
+        SecureRandom r)
+    {
+        return calculateGenerator_FIPS186_2(p, q, r);
+    }
+
+    private static BigInteger calculateGenerator_FIPS186_3_Verifiable(Digest d, BigInteger p, BigInteger q,
+        byte[] seed, int index)
+    {
+// A.2.3 Verifiable Canonical Generation of the Generator g
+        BigInteger e = p.subtract(ONE).divide(q);
+        byte[] ggen = Hex.decode("6767656E");
+
+        // 7. U = domain_parameter_seed || "ggen" || index || count.
+        byte[] U = new byte[seed.length + ggen.length + 1 + 2];
+        System.arraycopy(seed, 0, U, 0, seed.length);
+        System.arraycopy(ggen, 0, U, seed.length, ggen.length);
+        U[U.length - 3] = (byte)index;
+
+        byte[] w = new byte[d.getDigestSize()];
+        for (int count = 1; count < (1 << 16); ++count)
+        {
+            inc(U);
+            hash(d, U, w, 0);
+            BigInteger W = new BigInteger(1, w);
+            BigInteger g = W.modPow(e, p);
+            if (g.compareTo(TWO) >= 0)
+            {
+                return g;
+            }
+        }
+
+        return null;
+    }
+
+    private static void hash(Digest d, byte[] input, byte[] output, int outputPos)
+    {
+        d.update(input, 0, input.length);
+        d.doFinal(output, outputPos);
+    }
+
+    private static int getDefaultN(int L)
+    {
+        return L > 1024 ? 256 : 160;
+    }
+
+    private static int getMinimumIterations(int L)
+    {
+        // Values based on FIPS 186-4 C.3 Table C.1
+        return L <= 1024 ? 40 : (48 + 8 * ((L - 1) / 1024)); 
+    }
+
+    private static void inc(byte[] buf)
+    {
+        for (int i = buf.length - 1; i >= 0; --i)
+        {
+            byte b = (byte)((buf[i] + 1) & 0xff);
+            buf[i] = b;
+
+            if (b != 0)
+            {
+                break;
+            }
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
new file mode 100644
index 0000000..f5e3449
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
@@ -0,0 +1,84 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import com.android.internal.org.bouncycastle.math.ec.ECConstants;
+import com.android.internal.org.bouncycastle.math.ec.ECMultiplier;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.ec.FixedPointCombMultiplier;
+import com.android.internal.org.bouncycastle.math.ec.WNafUtil;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECKeyPairGenerator
+    implements AsymmetricCipherKeyPairGenerator, ECConstants
+{
+    ECDomainParameters  params;
+    SecureRandom        random;
+
+    public void init(
+        KeyGenerationParameters param)
+    {
+        ECKeyGenerationParameters  ecP = (ECKeyGenerationParameters)param;
+
+        this.random = ecP.getRandom();
+        this.params = ecP.getDomainParameters();
+
+        if (this.random == null)
+        {
+            this.random = CryptoServicesRegistrar.getSecureRandom();
+        }
+    }
+
+    /**
+     * Given the domain parameters this routine generates an EC key
+     * pair in accordance with X9.62 section 5.2.1 pages 26, 27.
+     */
+    public AsymmetricCipherKeyPair generateKeyPair()
+    {
+        BigInteger n = params.getN();
+        int nBitLength = n.bitLength();
+        int minWeight = nBitLength >>> 2;
+
+        BigInteger d;
+        for (;;)
+        {
+            d = BigIntegers.createRandomBigInteger(nBitLength, random);
+
+            if (d.compareTo(TWO) < 0  || (d.compareTo(n) >= 0))
+            {
+                continue;
+            }
+
+            if (WNafUtil.getNafWeight(d) < minWeight)
+            {
+                continue;
+            }
+
+            break;
+        }
+
+        ECPoint Q = createBasePointMultiplier().multiply(params.getG(), d);
+
+        return new AsymmetricCipherKeyPair(
+            new ECPublicKeyParameters(Q, params),
+            new ECPrivateKeyParameters(d, params));
+    }
+
+    protected ECMultiplier createBasePointMultiplier()
+    {
+        return new FixedPointCombMultiplier();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
new file mode 100644
index 0000000..43b5b5c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
@@ -0,0 +1,137 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.PBEParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+// Android-changed: Use Android digests
+// import org.bouncycastle.crypto.util.DigestFactory;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+
+/**
+ * Generator for PBE derived keys and ivs as usd by OpenSSL.
+ * <p>
+ * The scheme is a simple extension of PKCS 5 V2.0 Scheme 1 using MD5 with an
+ * iteration count of 1.
+ * <p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OpenSSLPBEParametersGenerator
+    extends PBEParametersGenerator
+{
+    // Android-changed: Use Android digests
+    // private Digest  digest = DigestFactory.createMD5();
+    private Digest  digest = AndroidDigestFactory.getMD5();
+
+    /**
+     * Construct a OpenSSL Parameters generator. 
+     */
+    public OpenSSLPBEParametersGenerator()
+    {
+    }
+
+    /**
+     * Initialise - note the iteration count for this algorithm is fixed at 1.
+     * 
+     * @param password password to use.
+     * @param salt salt to use.
+     */
+    public void init(
+       byte[] password,
+       byte[] salt)
+    {
+        super.init(password, salt, 1);
+    }
+    
+    /**
+     * the derived key function, the ith hash of the password and the salt.
+     */
+    private byte[] generateDerivedKey(
+        int bytesNeeded)
+    {
+        byte[]  buf = new byte[digest.getDigestSize()];
+        byte[]  key = new byte[bytesNeeded];
+        int     offset = 0;
+        
+        for (;;)
+        {
+            digest.update(password, 0, password.length);
+            digest.update(salt, 0, salt.length);
+
+            digest.doFinal(buf, 0);
+            
+            int len = (bytesNeeded > buf.length) ? buf.length : bytesNeeded;
+            System.arraycopy(buf, 0, key, offset, len);
+            offset += len;
+
+            // check if we need any more
+            bytesNeeded -= len;
+            if (bytesNeeded == 0)
+            {
+                break;
+            }
+
+            // do another round
+            digest.reset();
+            digest.update(buf, 0, buf.length);
+        }
+        
+        return key;
+    }
+
+    /**
+     * Generate a key parameter derived from the password, salt, and iteration
+     * count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     * @exception IllegalArgumentException if the key length larger than the base hash size.
+     */
+    public CipherParameters generateDerivedParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        byte[]  dKey = generateDerivedKey(keySize);
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+
+    /**
+     * Generate a key with initialisation vector parameter derived from
+     * the password, salt, and iteration count we are currently initialised
+     * with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @param ivSize the size of the iv we want (in bits)
+     * @return a ParametersWithIV object.
+     * @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
+     */
+    public CipherParameters generateDerivedParameters(
+        int     keySize,
+        int     ivSize)
+    {
+        keySize = keySize / 8;
+        ivSize = ivSize / 8;
+
+        byte[]  dKey = generateDerivedKey(keySize + ivSize);
+
+        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+    }
+
+    /**
+     * Generate a key parameter for use with a MAC derived from the password,
+     * salt, and iteration count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     * @exception IllegalArgumentException if the key length larger than the base hash size.
+     */
+    public CipherParameters generateDerivedMacParameters(
+        int keySize)
+    {
+        return generateDerivedParameters(keySize);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java
new file mode 100644
index 0000000..f9d4ec9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java
@@ -0,0 +1,222 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.ExtendedDigest;
+import com.android.internal.org.bouncycastle.crypto.PBEParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html>
+ * RSA's PKCS12 Page</a>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS12ParametersGenerator
+    extends PBEParametersGenerator
+{
+    public static final int KEY_MATERIAL = 1;
+    public static final int IV_MATERIAL  = 2;
+    public static final int MAC_MATERIAL = 3;
+
+    private Digest digest;
+
+    private int     u;
+    private int     v;
+
+    /**
+     * Construct a PKCS 12 Parameters generator. This constructor will
+     * accept any digest which also implements ExtendedDigest.
+     *
+     * @param digest the digest to be used as the source of derived keys.
+     * @exception IllegalArgumentException if an unknown digest is passed in.
+     */
+    public PKCS12ParametersGenerator(
+        Digest  digest)
+    {
+        this.digest = digest;
+        if (digest instanceof ExtendedDigest)
+        {
+            u = digest.getDigestSize();
+            v = ((ExtendedDigest)digest).getByteLength();
+        }
+        else
+        {
+            throw new IllegalArgumentException("Digest " + digest.getAlgorithmName() + " unsupported");
+        }
+    }
+
+    /**
+     * add a + b + 1, returning the result in a. The a value is treated
+     * as a BigInteger of length (b.length * 8) bits. The result is 
+     * modulo 2^b.length in case of overflow.
+     */
+    private void adjust(
+        byte[]  a,
+        int     aOff,
+        byte[]  b)
+    {
+        int  x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1;
+
+        a[aOff + b.length - 1] = (byte)x;
+        x >>>= 8;
+
+        for (int i = b.length - 2; i >= 0; i--)
+        {
+            x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
+            a[aOff + i] = (byte)x;
+            x >>>= 8;
+        }
+    }
+
+    /**
+     * generation of a derived key ala PKCS12 V1.0.
+     */
+    private byte[] generateDerivedKey(
+        int idByte,
+        int n)
+    {
+        byte[]  D = new byte[v];
+        byte[]  dKey = new byte[n];
+
+        for (int i = 0; i != D.length; i++)
+        {
+            D[i] = (byte)idByte;
+        }
+
+        byte[]  S;
+
+        if ((salt != null) && (salt.length != 0))
+        {
+            S = new byte[v * ((salt.length + v - 1) / v)];
+
+            for (int i = 0; i != S.length; i++)
+            {
+                S[i] = salt[i % salt.length];
+            }
+        }
+        else
+        {
+            S = new byte[0];
+        }
+
+        byte[]  P;
+
+        if ((password != null) && (password.length != 0))
+        {
+            P = new byte[v * ((password.length + v - 1) / v)];
+
+            for (int i = 0; i != P.length; i++)
+            {
+                P[i] = password[i % password.length];
+            }
+        }
+        else
+        {
+            P = new byte[0];
+        }
+
+        byte[]  I = new byte[S.length + P.length];
+
+        System.arraycopy(S, 0, I, 0, S.length);
+        System.arraycopy(P, 0, I, S.length, P.length);
+
+        byte[]  B = new byte[v];
+        int     c = (n + u - 1) / u;
+        byte[]  A = new byte[u];
+
+        for (int i = 1; i <= c; i++)
+        {
+            digest.update(D, 0, D.length);
+            digest.update(I, 0, I.length);
+            digest.doFinal(A, 0);
+            for (int j = 1; j < iterationCount; j++)
+            {
+                digest.update(A, 0, A.length);
+                digest.doFinal(A, 0);
+            }
+
+            for (int j = 0; j != B.length; j++)
+            {
+                B[j] = A[j % A.length];
+            }
+
+            for (int j = 0; j != I.length / v; j++)
+            {
+                adjust(I, j * v, B);
+            }
+
+            if (i == c)
+            {
+                System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u));
+            }
+            else
+            {
+                System.arraycopy(A, 0, dKey, (i - 1) * u, A.length);
+            }
+        }
+
+        return dKey;
+    }
+
+    /**
+     * Generate a key parameter derived from the password, salt, and iteration
+     * count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     */
+    public CipherParameters generateDerivedParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+
+    /**
+     * Generate a key with initialisation vector parameter derived from
+     * the password, salt, and iteration count we are currently initialised
+     * with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @param ivSize the size of the iv we want (in bits)
+     * @return a ParametersWithIV object.
+     */
+    public CipherParameters generateDerivedParameters(
+        int     keySize,
+        int     ivSize)
+    {
+        keySize = keySize / 8;
+        ivSize = ivSize / 8;
+
+        byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+        byte[]  iv = generateDerivedKey(IV_MATERIAL, ivSize);
+
+        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
+    }
+
+    /**
+     * Generate a key parameter for use with a MAC derived from the password,
+     * salt, and iteration count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     */
+    public CipherParameters generateDerivedMacParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        byte[]  dKey = generateDerivedKey(MAC_MATERIAL, keySize);
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/PKCS5S1ParametersGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/PKCS5S1ParametersGenerator.java
new file mode 100644
index 0000000..cd9d5e8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/PKCS5S1ParametersGenerator.java
@@ -0,0 +1,121 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.PBEParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 1.
+ * Note this generator is limited to the size of the hash produced by the
+ * digest used to drive it.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
+ * RSA's PKCS5 Page</a>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS5S1ParametersGenerator
+    extends PBEParametersGenerator
+{
+    private Digest  digest;
+
+    /**
+     * Construct a PKCS 5 Scheme 1 Parameters generator. 
+     *
+     * @param digest the digest to be used as the source of derived keys.
+     */
+    public PKCS5S1ParametersGenerator(
+        Digest  digest)
+    {
+        this.digest = digest;
+    }
+
+    /**
+     * the derived key function, the ith hash of the password and the salt.
+     */
+    private byte[] generateDerivedKey()
+    {
+        byte[] digestBytes = new byte[digest.getDigestSize()];
+
+        digest.update(password, 0, password.length);
+        digest.update(salt, 0, salt.length);
+
+        digest.doFinal(digestBytes, 0);
+        for (int i = 1; i < iterationCount; i++)
+        {
+            digest.update(digestBytes, 0, digestBytes.length);
+            digest.doFinal(digestBytes, 0);
+        }
+
+        return digestBytes;
+    }
+
+    /**
+     * Generate a key parameter derived from the password, salt, and iteration
+     * count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     * @exception IllegalArgumentException if the key length larger than the base hash size.
+     */
+    public CipherParameters generateDerivedParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        if (keySize > digest.getDigestSize())
+        {
+            throw new IllegalArgumentException(
+                   "Can't generate a derived key " + keySize + " bytes long.");
+        }
+
+        byte[]  dKey = generateDerivedKey();
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+
+    /**
+     * Generate a key with initialisation vector parameter derived from
+     * the password, salt, and iteration count we are currently initialised
+     * with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @param ivSize the size of the iv we want (in bits)
+     * @return a ParametersWithIV object.
+     * @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
+     */
+    public CipherParameters generateDerivedParameters(
+        int     keySize,
+        int     ivSize)
+    {
+        keySize = keySize / 8;
+        ivSize = ivSize / 8;
+
+        if ((keySize + ivSize) > digest.getDigestSize())
+        {
+            throw new IllegalArgumentException(
+                   "Can't generate a derived key " + (keySize + ivSize) + " bytes long.");
+        }
+
+        byte[]  dKey = generateDerivedKey();
+
+        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+    }
+
+    /**
+     * Generate a key parameter for use with a MAC derived from the password,
+     * salt, and iteration count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     * @exception IllegalArgumentException if the key length larger than the base hash size.
+     */
+    public CipherParameters generateDerivedMacParameters(
+        int keySize)
+    {
+        return generateDerivedParameters(keySize);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
new file mode 100644
index 0000000..2223874
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
@@ -0,0 +1,160 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.Mac;
+import com.android.internal.org.bouncycastle.crypto.PBEParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.macs.HMac;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+// Android-changed: Use Android digests
+// import org.bouncycastle.crypto.util.DigestFactory;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2.
+ * This generator uses a SHA-1 HMac as the calculation function.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
+ * RSA's PKCS5 Page</a>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS5S2ParametersGenerator
+    extends PBEParametersGenerator
+{
+    private Mac hMac;
+    private byte[] state;
+
+    /**
+     * construct a PKCS5 Scheme 2 Parameters generator.
+     */
+    public PKCS5S2ParametersGenerator()
+    {
+        // Android-changed: Use Android digests
+        // this(DigestFactory.createSHA1());
+        this(AndroidDigestFactory.getSHA1());
+    }
+
+    public PKCS5S2ParametersGenerator(Digest digest)
+    {
+        hMac = new HMac(digest);
+        state = new byte[hMac.getMacSize()];
+    }
+
+    private void F(
+        byte[]  S,
+        int     c,
+        byte[]  iBuf,
+        byte[]  out,
+        int     outOff)
+    {
+        if (c == 0)
+        {
+            throw new IllegalArgumentException("iteration count must be at least 1.");
+        }
+
+        if (S != null)
+        {
+            hMac.update(S, 0, S.length);
+        }
+
+        hMac.update(iBuf, 0, iBuf.length);
+        hMac.doFinal(state, 0);
+
+        System.arraycopy(state, 0, out, outOff, state.length);
+
+        for (int count = 1; count < c; count++)
+        {
+            hMac.update(state, 0, state.length);
+            hMac.doFinal(state, 0);
+
+            for (int j = 0; j != state.length; j++)
+            {
+                out[outOff + j] ^= state[j];
+            }
+        }
+    }
+
+    private byte[] generateDerivedKey(
+        int dkLen)
+    {
+        int     hLen = hMac.getMacSize();
+        int     l = (dkLen + hLen - 1) / hLen;
+        byte[]  iBuf = new byte[4];
+        byte[]  outBytes = new byte[l * hLen];
+        int     outPos = 0;
+
+        CipherParameters param = new KeyParameter(password);
+
+        hMac.init(param);
+
+        for (int i = 1; i <= l; i++)
+        {
+            // Increment the value in 'iBuf'
+            int pos = 3;
+            while (++iBuf[pos] == 0)
+            {
+                --pos;
+            }
+
+            F(salt, iterationCount, iBuf, outBytes, outPos);
+            outPos += hLen;
+        }
+
+        return outBytes;
+    }
+
+    /**
+     * Generate a key parameter derived from the password, salt, and iteration
+     * count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     */
+    public CipherParameters generateDerivedParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        byte[]  dKey = Arrays.copyOfRange(generateDerivedKey(keySize), 0, keySize);
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+
+    /**
+     * Generate a key with initialisation vector parameter derived from
+     * the password, salt, and iteration count we are currently initialised
+     * with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @param ivSize the size of the iv we want (in bits)
+     * @return a ParametersWithIV object.
+     */
+    public CipherParameters generateDerivedParameters(
+        int     keySize,
+        int     ivSize)
+    {
+        keySize = keySize / 8;
+        ivSize = ivSize / 8;
+
+        byte[]  dKey = generateDerivedKey(keySize + ivSize);
+
+        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+    }
+
+    /**
+     * Generate a key parameter for use with a MAC derived from the password,
+     * salt, and iteration count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     */
+    public CipherParameters generateDerivedMacParameters(
+        int keySize)
+    {
+        return generateDerivedParameters(keySize);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
new file mode 100644
index 0000000..ae4eb33
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
@@ -0,0 +1,234 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import com.android.internal.org.bouncycastle.math.Primes;
+import com.android.internal.org.bouncycastle.math.ec.WNafUtil;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * an RSA key pair generator.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSAKeyPairGenerator
+    implements AsymmetricCipherKeyPairGenerator
+{
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+
+    private RSAKeyGenerationParameters param;
+
+    public void init(KeyGenerationParameters param)
+    {
+        this.param = (RSAKeyGenerationParameters)param;
+    }
+
+    public AsymmetricCipherKeyPair generateKeyPair()
+    {
+        AsymmetricCipherKeyPair result = null;
+        boolean done = false;
+
+        //
+        // p and q values should have a length of half the strength in bits
+        //
+        int strength = param.getStrength();
+        int pbitlength = (strength + 1) / 2;
+        int qbitlength = strength - pbitlength;
+        int mindiffbits = (strength / 2) - 100;
+
+        if (mindiffbits < strength / 3)
+        {
+            mindiffbits = strength / 3;
+        }
+
+        int minWeight = strength >> 2;
+
+        // d lower bound is 2^(strength / 2)
+        BigInteger dLowerBound = BigInteger.valueOf(2).pow(strength / 2);
+        // squared bound (sqrt(2)*2^(nlen/2-1))^2
+        BigInteger squaredBound = ONE.shiftLeft(strength - 1);
+        // 2^(nlen/2 - 100)
+        BigInteger minDiff = ONE.shiftLeft(mindiffbits);
+
+        while (!done)
+        {
+            BigInteger p, q, n, d, e, pSub1, qSub1, gcd, lcm;
+
+            e = param.getPublicExponent();
+
+            p = chooseRandomPrime(pbitlength, e, squaredBound);
+
+            //
+            // generate a modulus of the required length
+            //
+            for (; ; )
+            {
+                q = chooseRandomPrime(qbitlength, e, squaredBound);
+
+                // p and q should not be too close together (or equal!)
+                BigInteger diff = q.subtract(p).abs();
+                if (diff.bitLength() < mindiffbits || diff.compareTo(minDiff) <= 0)
+                {
+                    continue;
+                }
+
+                //
+                // calculate the modulus
+                //
+                n = p.multiply(q);
+
+                if (n.bitLength() != strength)
+                {
+                    //
+                    // if we get here our primes aren't big enough, make the largest
+                    // of the two p and try again
+                    //
+                    p = p.max(q);
+                    continue;
+                }
+
+	            /*
+                 * Require a minimum weight of the NAF representation, since low-weight composites may
+	             * be weak against a version of the number-field-sieve for factoring.
+	             *
+	             * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+	             */
+                if (WNafUtil.getNafWeight(n) < minWeight)
+                {
+                    p = chooseRandomPrime(pbitlength, e, squaredBound);
+                    continue;
+                }
+
+                break;
+            }
+
+            if (p.compareTo(q) < 0)
+            {
+                gcd = p;
+                p = q;
+                q = gcd;
+            }
+
+            pSub1 = p.subtract(ONE);
+            qSub1 = q.subtract(ONE);
+            gcd = pSub1.gcd(qSub1);
+            lcm = pSub1.divide(gcd).multiply(qSub1);
+
+            //
+            // calculate the private exponent
+            //
+            d = e.modInverse(lcm);
+
+            if (d.compareTo(dLowerBound) <= 0)
+            {
+                continue;
+            }
+            else
+            {
+                done = true;
+            }
+
+            //
+            // calculate the CRT factors
+            //
+            BigInteger dP, dQ, qInv;
+
+            dP = d.remainder(pSub1);
+            dQ = d.remainder(qSub1);
+            qInv = q.modInverse(p);
+
+            result = new AsymmetricCipherKeyPair(
+                new RSAKeyParameters(false, n, e),
+                new RSAPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+        }
+
+        return result;
+    }
+
+    /**
+     * Choose a random prime value for use with RSA
+     *
+     * @param bitlength the bit-length of the returned prime
+     * @param e         the RSA public exponent
+     * @return A prime p, with (p-1) relatively prime to e
+     */
+    protected BigInteger chooseRandomPrime(int bitlength, BigInteger e, BigInteger sqrdBound)
+    {
+        for (int i = 0; i != 5 * bitlength; i++)
+        {
+            BigInteger p = BigIntegers.createRandomPrime(bitlength, 1, param.getRandom());
+
+            if (p.mod(e).equals(ONE))
+            {
+                continue;
+            }
+
+            if (p.multiply(p).compareTo(sqrdBound) < 0)
+            {
+                continue;
+            }
+
+            if (!isProbablePrime(p))
+            {
+                continue;
+            }
+
+            if (!e.gcd(p.subtract(ONE)).equals(ONE))
+            {
+                continue;
+            }
+
+            return p;
+        }
+
+        throw new IllegalStateException("unable to generate prime number for RSA key");
+    }
+
+    protected boolean isProbablePrime(BigInteger x)
+    {
+        int iterations = getNumberOfIterations(x.bitLength(), param.getCertainty());
+
+        /*
+         * Primes class for FIPS 186-4 C.3 primality checking
+         */
+        return !Primes.hasAnySmallFactors(x) && Primes.isMRProbablePrime(x, param.getRandom(), iterations);
+    }
+
+    private static int getNumberOfIterations(int bits, int certainty)
+    {
+        /*
+         * NOTE: We enforce a minimum 'certainty' of 100 for bits >= 1024 (else 80). Where the
+         * certainty is higher than the FIPS 186-4 tables (C.2/C.3) cater to, extra iterations
+         * are added at the "worst case rate" for the excess.
+         */
+        if (bits >= 1536)
+        {
+            return  certainty <= 100 ? 3
+                :   certainty <= 128 ? 4
+                :   4 + (certainty - 128 + 1) / 2;
+        }
+        else if (bits >= 1024)
+        {
+            return  certainty <= 100 ? 4
+                :   certainty <= 112 ? 5
+                :   5 + (certainty - 112 + 1) / 2;
+        }
+        else if (bits >= 512)
+        {
+            return  certainty <= 80  ? 5
+                :   certainty <= 100 ? 7
+                :   7 + (certainty - 100 + 1) / 2;
+        }
+        else
+        {
+            return  certainty <= 80  ? 40
+                :   40 + (certainty - 80 + 1) / 2;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/DigestInputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/DigestInputStream.java
new file mode 100644
index 0000000..a746acc
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/DigestInputStream.java
@@ -0,0 +1,56 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.android.internal.org.bouncycastle.crypto.Digest;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DigestInputStream
+    extends FilterInputStream
+{
+    protected Digest digest;
+
+    public DigestInputStream(
+        InputStream stream,
+        Digest      digest)
+    {
+        super(stream);
+        this.digest = digest;
+    }
+
+    public int read()
+        throws IOException
+    {
+        int b = in.read();
+
+        if (b >= 0)
+        {
+            digest.update((byte)b);
+        }
+        return b;
+    }
+
+    public int read(
+        byte[] b,
+        int off,
+        int len)
+        throws IOException
+    {
+        int n = in.read(b, off, len);
+        if (n > 0)
+        {
+            digest.update(b, off, n);
+        }
+        return n;
+    }
+
+    public Digest getDigest()
+    {
+        return digest;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/DigestOutputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/DigestOutputStream.java
new file mode 100644
index 0000000..4996e70
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/DigestOutputStream.java
@@ -0,0 +1,46 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import com.android.internal.org.bouncycastle.crypto.Digest;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DigestOutputStream
+    extends OutputStream
+{
+    protected Digest digest;
+
+    public DigestOutputStream(
+        Digest          Digest)
+    {
+        this.digest = Digest;
+    }
+
+    public void write(int b)
+        throws IOException
+    {
+        digest.update((byte)b);
+    }
+
+    public void write(
+        byte[] b,
+        int off,
+        int len)
+        throws IOException
+    {
+        digest.update(b, off, len);
+    }
+
+    public byte[] getDigest()
+    {
+        byte[] res = new byte[digest.getDigestSize()];
+        
+        digest.doFinal(res, 0);
+        
+        return res;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/MacInputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/MacInputStream.java
new file mode 100644
index 0000000..d4059bb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/MacInputStream.java
@@ -0,0 +1,56 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.android.internal.org.bouncycastle.crypto.Mac;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class MacInputStream
+    extends FilterInputStream
+{
+    protected Mac mac;
+
+    public MacInputStream(
+        InputStream stream,
+        Mac         mac)
+    {
+        super(stream);
+        this.mac = mac;
+    }
+
+    public int read()
+        throws IOException
+    {
+        int b = in.read();
+
+        if (b >= 0)
+        {
+            mac.update((byte)b);
+        }
+        return b;
+    }
+
+    public int read(
+        byte[] b,
+        int off,
+        int len)
+        throws IOException
+    {
+        int n = in.read(b, off, len);
+        if (n >= 0)
+        {
+            mac.update(b, off, n);
+        }
+        return n;
+    }
+
+    public Mac getMac()
+    {
+        return mac;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/MacOutputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/MacOutputStream.java
new file mode 100644
index 0000000..c57bcd1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/io/MacOutputStream.java
@@ -0,0 +1,46 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import com.android.internal.org.bouncycastle.crypto.Mac;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class MacOutputStream
+    extends OutputStream
+{
+    protected Mac mac;
+
+    public MacOutputStream(
+        Mac          mac)
+    {
+        this.mac = mac;
+    }
+
+    public void write(int b)
+        throws IOException
+    {
+        mac.update((byte)b);
+    }
+
+    public void write(
+        byte[] b,
+        int off,
+        int len)
+        throws IOException
+    {
+        mac.update(b, off, len);
+    }
+
+    public byte[] getMac()
+    {
+        byte[] res = new byte[mac.getMacSize()];
+
+        mac.doFinal(res, 0);
+
+        return res;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/macs/CBCBlockCipherMac.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/macs/CBCBlockCipherMac.java
new file mode 100644
index 0000000..38efe5c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/macs/CBCBlockCipherMac.java
@@ -0,0 +1,231 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.macs;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.Mac;
+import com.android.internal.org.bouncycastle.crypto.modes.CBCBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.paddings.BlockCipherPadding;
+
+/**
+ * standard CBC Block Cipher MAC - if no padding is specified the default of
+ * pad of zeroes is used.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CBCBlockCipherMac
+    implements Mac
+{
+    private byte[]              mac;
+
+    private byte[]              buf;
+    private int                 bufOff;
+    private BlockCipher         cipher;
+    private BlockCipherPadding  padding;
+
+    private int                 macSize;
+
+    /**
+     * create a standard MAC based on a CBC block cipher. This will produce an
+     * authentication code half the length of the block size of the cipher.
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     */
+    public CBCBlockCipherMac(
+        BlockCipher     cipher)
+    {
+        this(cipher, (cipher.getBlockSize() * 8) / 2, null);
+    }
+
+    /**
+     * create a standard MAC based on a CBC block cipher. This will produce an
+     * authentication code half the length of the block size of the cipher.
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param padding the padding to be used to complete the last block.
+     */
+    public CBCBlockCipherMac(
+        BlockCipher         cipher,
+        BlockCipherPadding  padding)
+    {
+        this(cipher, (cipher.getBlockSize() * 8) / 2, padding);
+    }
+
+    /**
+     * create a standard MAC based on a block cipher with the size of the
+     * MAC been given in bits. This class uses CBC mode as the basis for the
+     * MAC generation.
+     * <p>
+     * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+     * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+     * and in general should be less than the size of the block cipher as it reduces
+     * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+     */
+    public CBCBlockCipherMac(
+        BlockCipher     cipher,
+        int             macSizeInBits)
+    {
+        this(cipher, macSizeInBits, null);
+    }
+
+    /**
+     * create a standard MAC based on a block cipher with the size of the
+     * MAC been given in bits. This class uses CBC mode as the basis for the
+     * MAC generation.
+     * <p>
+     * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+     * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+     * and in general should be less than the size of the block cipher as it reduces
+     * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+     * @param padding the padding to be used to complete the last block.
+     */
+    public CBCBlockCipherMac(
+        BlockCipher         cipher,
+        int                 macSizeInBits,
+        BlockCipherPadding  padding)
+    {
+        if ((macSizeInBits % 8) != 0)
+        {
+            throw new IllegalArgumentException("MAC size must be multiple of 8");
+        }
+
+        this.cipher = new CBCBlockCipher(cipher);
+        this.padding = padding;
+        this.macSize = macSizeInBits / 8;
+
+        mac = new byte[cipher.getBlockSize()];
+
+        buf = new byte[cipher.getBlockSize()];
+        bufOff = 0;
+    }
+
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName();
+    }
+
+    public void init(
+        CipherParameters    params)
+    {
+        reset();
+
+        cipher.init(true, params);
+    }
+
+    public int getMacSize()
+    {
+        return macSize;
+    }
+
+    public void update(
+        byte        in)
+    {
+        if (bufOff == buf.length)
+        {
+            cipher.processBlock(buf, 0, mac, 0);
+            bufOff = 0;
+        }
+
+        buf[bufOff++] = in;
+    }
+
+    public void update(
+        byte[]      in,
+        int         inOff,
+        int         len)
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int blockSize = cipher.getBlockSize();
+        int gapLen = blockSize - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            cipher.processBlock(buf, 0, mac, 0);
+
+            bufOff = 0;
+            len -= gapLen;
+            inOff += gapLen;
+
+            while (len > blockSize)
+            {
+                cipher.processBlock(in, inOff, mac, 0);
+
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+
+        bufOff += len;
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        int blockSize = cipher.getBlockSize();
+
+        if (padding == null)
+        {
+            //
+            // pad with zeroes
+            //
+            while (bufOff < blockSize)
+            {
+                buf[bufOff] = 0;
+                bufOff++;
+            }
+        }
+        else
+        {
+            if (bufOff == blockSize)
+            {
+                cipher.processBlock(buf, 0, mac, 0);
+                bufOff = 0;
+            }
+
+            padding.addPadding(buf, bufOff);
+        }
+
+        cipher.processBlock(buf, 0, mac, 0);
+
+        System.arraycopy(mac, 0, out, outOff, macSize);
+
+        reset();
+
+        return macSize;
+    }
+
+    /**
+     * Reset the mac generator.
+     */
+    public void reset()
+    {
+        /*
+         * clean the buffer.
+         */
+        for (int i = 0; i < buf.length; i++)
+        {
+            buf[i] = 0;
+        }
+
+        bufOff = 0;
+
+        /*
+         * reset the underlying cipher.
+         */
+        cipher.reset();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/macs/HMac.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/macs/HMac.java
new file mode 100644
index 0000000..c88919b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/macs/HMac.java
@@ -0,0 +1,239 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.macs;
+
+import java.util.Hashtable;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.ExtendedDigest;
+import com.android.internal.org.bouncycastle.crypto.Mac;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.util.Integers;
+import com.android.internal.org.bouncycastle.util.Memoable;
+
+/**
+ * HMAC implementation based on RFC2104
+ *
+ * H(K XOR opad, H(K XOR ipad, text))
+ * @hide This class is not part of the Android public SDK API
+ */
+public class HMac
+    implements Mac
+{
+    private final static byte IPAD = (byte)0x36;
+    private final static byte OPAD = (byte)0x5C;
+
+    private Digest digest;
+    private int digestSize;
+    private int blockLength;
+    private Memoable ipadState;
+    private Memoable opadState;
+
+    private byte[] inputPad;
+    private byte[] outputBuf;
+
+    private static Hashtable blockLengths;
+    
+    static
+    {
+        blockLengths = new Hashtable();
+        
+        // BEGIN Android-removed: Unsupported algorithms
+        // blockLengths.put("GOST3411", Integers.valueOf(32));
+        //
+        // blockLengths.put("MD2", Integers.valueOf(16));
+        // blockLengths.put("MD4", Integers.valueOf(64));
+        // END Android-removed: Unsupported algorithms
+        blockLengths.put("MD5", Integers.valueOf(64));
+
+        // BEGIN Android-removed: Unsupported algorithms
+        // blockLengths.put("RIPEMD128", Integers.valueOf(64));
+        // blockLengths.put("RIPEMD160", Integers.valueOf(64));
+        // END Android-removed: Unsupported algorithms
+        
+        blockLengths.put("SHA-1", Integers.valueOf(64));
+        blockLengths.put("SHA-224", Integers.valueOf(64));
+        blockLengths.put("SHA-256", Integers.valueOf(64));
+        blockLengths.put("SHA-384", Integers.valueOf(128));
+        blockLengths.put("SHA-512", Integers.valueOf(128));
+
+        // BEGIN Android-removed: Unsupported algorithms
+        // blockLengths.put("Tiger", Integers.valueOf(64));
+        // blockLengths.put("Whirlpool", Integers.valueOf(64));
+        // END Android-removed: Unsupported algorithms
+    }
+    
+    private static int getByteLength(
+        Digest digest)
+    {
+        if (digest instanceof ExtendedDigest)
+        {
+            return ((ExtendedDigest)digest).getByteLength();
+        }
+        
+        Integer  b = (Integer)blockLengths.get(digest.getAlgorithmName());
+        
+        if (b == null)
+        {       
+            throw new IllegalArgumentException("unknown digest passed: " + digest.getAlgorithmName());
+        }
+        
+        return b.intValue();
+    }
+    
+    /**
+     * Base constructor for one of the standard digest algorithms that the 
+     * byteLength of the algorithm is know for.
+     * 
+     * @param digest the digest.
+     */
+    public HMac(
+        Digest digest)
+    {
+        this(digest, getByteLength(digest));
+    }
+
+    private HMac(
+        Digest digest,
+        int    byteLength)
+    {
+        this.digest = digest;
+        this.digestSize = digest.getDigestSize();
+        this.blockLength = byteLength;
+        this.inputPad = new byte[blockLength];
+        this.outputBuf = new byte[blockLength + digestSize];
+    }
+
+    public String getAlgorithmName()
+    {
+        return digest.getAlgorithmName() + "/HMAC";
+    }
+
+    public Digest getUnderlyingDigest()
+    {
+        return digest;
+    }
+
+    public void init(
+        CipherParameters params)
+    {
+        digest.reset();
+
+        byte[] key = ((KeyParameter)params).getKey();
+        int keyLength = key.length;
+
+        if (keyLength > blockLength)
+        {
+            digest.update(key, 0, keyLength);
+            digest.doFinal(inputPad, 0);
+            
+            keyLength = digestSize;
+        }
+        else
+        {
+            System.arraycopy(key, 0, inputPad, 0, keyLength);
+        }
+
+        for (int i = keyLength; i < inputPad.length; i++)
+        {
+            inputPad[i] = 0;
+        }
+
+        System.arraycopy(inputPad, 0, outputBuf, 0, blockLength);
+
+        xorPad(inputPad, blockLength, IPAD);
+        xorPad(outputBuf, blockLength, OPAD);
+
+        if (digest instanceof Memoable)
+        {
+            opadState = ((Memoable)digest).copy();
+
+            ((Digest)opadState).update(outputBuf, 0, blockLength);
+        }
+
+        digest.update(inputPad, 0, inputPad.length);
+
+        if (digest instanceof Memoable)
+        {
+            ipadState = ((Memoable)digest).copy();
+        }
+    }
+
+    public int getMacSize()
+    {
+        return digestSize;
+    }
+
+    public void update(
+        byte in)
+    {
+        digest.update(in);
+    }
+
+    public void update(
+        byte[] in,
+        int inOff,
+        int len)
+    {
+        digest.update(in, inOff, len);
+    }
+
+    public int doFinal(
+        byte[] out,
+        int outOff)
+    {
+        digest.doFinal(outputBuf, blockLength);
+
+        if (opadState != null)
+        {
+            ((Memoable)digest).reset(opadState);
+            digest.update(outputBuf, blockLength, digest.getDigestSize());
+        }
+        else
+        {
+            digest.update(outputBuf, 0, outputBuf.length);
+        }
+
+        int len = digest.doFinal(out, outOff);
+
+        for (int i = blockLength; i < outputBuf.length; i++)
+        {
+            outputBuf[i] = 0;
+        }
+
+        if (ipadState != null)
+        {
+            ((Memoable)digest).reset(ipadState);
+        }
+        else
+        {
+            digest.update(inputPad, 0, inputPad.length);
+        }
+
+        return len;
+    }
+
+    /**
+     * Reset the mac generator.
+     */
+    public void reset()
+    {
+        /*
+         * reset the underlying digest.
+         */
+        digest.reset();
+
+        /*
+         * reinitialize the digest.
+         */
+        digest.update(inputPad, 0, inputPad.length);
+    }
+
+    private static void xorPad(byte[] pad, int len, byte n)
+    {
+        for (int i = 0; i < len; ++i)
+        {
+            pad[i] ^= n;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/AEADBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/AEADBlockCipher.java
new file mode 100644
index 0000000..2673bff
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/AEADBlockCipher.java
@@ -0,0 +1,148 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A block cipher mode that includes authenticated encryption with a streaming mode and optional associated data.
+ * <p>
+ * Implementations of this interface may operate in a packet mode (where all input data is buffered and 
+ * processed dugin the call to {@link #doFinal(byte[], int)}), or in a streaming mode (where output data is
+ * incrementally produced with each call to {@link #processByte(byte, byte[], int)} or 
+ * {@link #processBytes(byte[], int, int, byte[], int)}.
+ * </p>
+ * This is important to consider during decryption: in a streaming mode, unauthenticated plaintext data
+ * may be output prior to the call to {@link #doFinal(byte[], int)} that results in an authentication
+ * failure. The higher level protocol utilising this cipher must ensure the plaintext data is handled 
+ * appropriately until the end of data is reached and the entire ciphertext is authenticated.
+ * @see com.android.internal.org.bouncycastle.crypto.params.AEADParameters
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface AEADBlockCipher
+{
+    /**
+     * initialise the underlying cipher. Parameter can either be an AEADParameters or a ParametersWithIV object.
+     *
+     * @param forEncryption true if we are setting up for encryption, false otherwise.
+     * @param params the necessary parameters for the underlying cipher to be initialised.
+     * @exception IllegalArgumentException if the params argument is inappropriate.
+     */
+    public void init(boolean forEncryption, CipherParameters params)
+        throws IllegalArgumentException;
+
+    /**
+     * Return the name of the algorithm.
+     * 
+     * @return the algorithm name.
+     */
+    public String getAlgorithmName();
+
+    /**
+     * return the cipher this object wraps.
+     *
+     * @return the cipher this object wraps.
+     */
+    public BlockCipher getUnderlyingCipher();
+
+    /**
+     * Add a single byte to the associated data check.
+     * <br>If the implementation supports it, this will be an online operation and will not retain the associated data.
+     *
+     * @param in the byte to be processed.
+     */
+    public void processAADByte(byte in);
+
+    /**
+     * Add a sequence of bytes to the associated data check.
+     * <br>If the implementation supports it, this will be an online operation and will not retain the associated data.
+     *
+     * @param in the input byte array.
+     * @param inOff the offset into the in array where the data to be processed starts.
+     * @param len the number of bytes to be processed.
+     */
+    public void processAADBytes(byte[] in, int inOff, int len);
+
+    /**
+     * encrypt/decrypt a single byte.
+     *
+     * @param in the byte to be processed.
+     * @param out the output buffer the processed byte goes into.
+     * @param outOff the offset into the output byte array the processed data starts at.
+     * @return the number of bytes written to out.
+     * @exception DataLengthException if the output buffer is too small.
+     */
+    public int processByte(byte in, byte[] out, int outOff)
+        throws DataLengthException;
+
+    /**
+     * process a block of bytes from in putting the result into out.
+     *
+     * @param in the input byte array.
+     * @param inOff the offset into the in array where the data to be processed starts.
+     * @param len the number of bytes to be processed.
+     * @param out the output buffer the processed bytes go into.
+     * @param outOff the offset into the output byte array the processed data starts at.
+     * @return the number of bytes written to out.
+     * @exception DataLengthException if the output buffer is too small.
+     */
+    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+        throws DataLengthException;
+
+    /**
+     * Finish the operation either appending or verifying the MAC at the end of the data.
+     *
+     * @param out space for any resulting output data.
+     * @param outOff offset into out to start copying the data at.
+     * @return number of bytes written into out.
+     * @throws IllegalStateException if the cipher is in an inappropriate state.
+     * @throws com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException if the MAC fails to match.
+     */
+    public int doFinal(byte[] out, int outOff)
+        throws IllegalStateException, InvalidCipherTextException;
+
+    /**
+     * Return the value of the MAC associated with the last stream processed.
+     *
+     * @return MAC for plaintext data.
+     */
+    public byte[] getMac();
+
+    /**
+     * return the size of the output buffer required for a processBytes
+     * an input of len bytes.
+     * <p>
+     * The returned size may be dependent on the initialisation of this cipher
+     * and may not be accurate once subsequent input data is processed - this method
+     * should be invoked immediately prior to input data being processed.
+     * </p>
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to processBytes
+     * with len bytes of input.
+     */
+    public int getUpdateOutputSize(int len);
+
+    /**
+     * return the size of the output buffer required for a processBytes plus a
+     * doFinal with an input of len bytes.
+     * <p>
+     * The returned size may be dependent on the initialisation of this cipher
+     * and may not be accurate once subsequent input data is processed - this method
+     * should be invoked immediately prior to a call to final processing of input data
+     * and a call to {@link #doFinal(byte[], int)}.
+     * </p>
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to processBytes and doFinal
+     * with len bytes of input.
+     */
+    public int getOutputSize(int len);
+
+    /**
+     * Reset the cipher. After resetting the cipher is in the same state
+     * as it was after the last init (if there was one).
+     */
+    public void reset();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CBCBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CBCBlockCipher.java
new file mode 100644
index 0000000..d767a6a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CBCBlockCipher.java
@@ -0,0 +1,255 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CBCBlockCipher
+    implements BlockCipher
+{
+    private byte[]          IV;
+    private byte[]          cbcV;
+    private byte[]          cbcNextV;
+
+    private int             blockSize;
+    private BlockCipher     cipher = null;
+    private boolean         encrypting;
+
+    /**
+     * Basic constructor.
+     *
+     * @param cipher the block cipher to be used as the basis of chaining.
+     */
+    public CBCBlockCipher(
+        BlockCipher cipher)
+    {
+        this.cipher = cipher;
+        this.blockSize = cipher.getBlockSize();
+
+        this.IV = new byte[blockSize];
+        this.cbcV = new byte[blockSize];
+        this.cbcNextV = new byte[blockSize];
+    }
+
+    /**
+     * return the underlying block cipher that we are wrapping.
+     *
+     * @return the underlying block cipher that we are wrapping.
+     */
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+    /**
+     * Initialise the cipher and, possibly, the initialisation vector (IV).
+     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+     *
+     * @param encrypting if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             encrypting,
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        boolean oldEncrypting = this.encrypting;
+
+        this.encrypting = encrypting;
+
+        if (params instanceof ParametersWithIV)
+        {
+            ParametersWithIV ivParam = (ParametersWithIV)params;
+            byte[] iv = ivParam.getIV();
+
+            if (iv.length != blockSize)
+            {
+                throw new IllegalArgumentException("initialisation vector must be the same length as block size");
+            }
+
+            System.arraycopy(iv, 0, IV, 0, iv.length);
+
+            reset();
+
+            // if null it's an IV changed only.
+            if (ivParam.getParameters() != null)
+            {
+                cipher.init(encrypting, ivParam.getParameters());
+            }
+            else if (oldEncrypting != encrypting)
+            {
+                throw new IllegalArgumentException("cannot change encrypting state without providing key.");
+            }
+        }
+        else
+        {
+            reset();
+
+            // if it's null, key is to be reused.
+            if (params != null)
+            {
+                cipher.init(encrypting, params);
+            }
+            else if (oldEncrypting != encrypting)
+            {
+                throw new IllegalArgumentException("cannot change encrypting state without providing key.");
+            }
+        }
+    }
+
+    /**
+     * return the algorithm name and mode.
+     *
+     * @return the name of the underlying algorithm followed by "/CBC".
+     */
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/CBC";
+    }
+
+    /**
+     * return the block size of the underlying cipher.
+     *
+     * @return the block size of the underlying cipher.
+     */
+    public int getBlockSize()
+    {
+        return cipher.getBlockSize();
+    }
+
+    /**
+     * Process one block of input from the array in and write it to
+     * the out array.
+     *
+     * @param in the array containing the input data.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the output data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int processBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
+    }
+
+    /**
+     * reset the chaining vector back to the IV and reset the underlying
+     * cipher.
+     */
+    public void reset()
+    {
+        System.arraycopy(IV, 0, cbcV, 0, IV.length);
+        Arrays.fill(cbcNextV, (byte)0);
+
+        cipher.reset();
+    }
+
+    /**
+     * Do the appropriate chaining step for CBC mode encryption.
+     *
+     * @param in the array containing the data to be encrypted.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the encrypted data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    private int encryptBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if ((inOff + blockSize) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        /*
+         * XOR the cbcV and the input,
+         * then encrypt the cbcV
+         */
+        for (int i = 0; i < blockSize; i++)
+        {
+            cbcV[i] ^= in[inOff + i];
+        }
+
+        int length = cipher.processBlock(cbcV, 0, out, outOff);
+
+        /*
+         * copy ciphertext to cbcV
+         */
+        System.arraycopy(out, outOff, cbcV, 0, cbcV.length);
+
+        return length;
+    }
+
+    /**
+     * Do the appropriate chaining step for CBC mode decryption.
+     *
+     * @param in the array containing the data to be decrypted.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the decrypted data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    private int decryptBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if ((inOff + blockSize) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        System.arraycopy(in, inOff, cbcNextV, 0, blockSize);
+
+        int length = cipher.processBlock(in, inOff, out, outOff);
+
+        /*
+         * XOR the cbcV and the output
+         */
+        for (int i = 0; i < blockSize; i++)
+        {
+            out[outOff + i] ^= cbcV[i];
+        }
+
+        /*
+         * swap the back up buffer into next position
+         */
+        byte[]  tmp;
+
+        tmp = cbcV;
+        cbcV = cbcNextV;
+        cbcNextV = tmp;
+
+        return length;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CCMBlockCipher.java
new file mode 100644
index 0000000..e0d2c5a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CCMBlockCipher.java
@@ -0,0 +1,461 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes;
+
+import java.io.ByteArrayOutputStream;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.Mac;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+import com.android.internal.org.bouncycastle.crypto.params.AEADParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
+ * NIST Special Publication 800-38C.
+ * <p>
+ * <b>Note</b>: this mode is a packet mode - it needs all the data up front.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CCMBlockCipher
+    implements AEADBlockCipher
+{
+    private BlockCipher           cipher;
+    private int                   blockSize;
+    private boolean               forEncryption;
+    private byte[]                nonce;
+    private byte[]                initialAssociatedText;
+    private int                   macSize;
+    private CipherParameters      keyParam;
+    private byte[]                macBlock;
+    private ExposedByteArrayOutputStream associatedText = new ExposedByteArrayOutputStream();
+    private ExposedByteArrayOutputStream data = new ExposedByteArrayOutputStream();
+
+    /**
+     * Basic constructor.
+     *
+     * @param c the block cipher to be used.
+     */
+    public CCMBlockCipher(BlockCipher c)
+    {
+        this.cipher = c;
+        this.blockSize = c.getBlockSize();
+        this.macBlock = new byte[blockSize];
+
+        if (blockSize != 16)
+        {
+            throw new IllegalArgumentException("cipher required with a block size of 16.");
+        }
+    }
+
+    /**
+     * return the underlying block cipher that we are wrapping.
+     *
+     * @return the underlying block cipher that we are wrapping.
+     */
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+
+    public void init(boolean forEncryption, CipherParameters params)
+          throws IllegalArgumentException
+    {
+        this.forEncryption = forEncryption;
+
+        CipherParameters cipherParameters;
+        if (params instanceof AEADParameters)
+        {
+            AEADParameters param = (AEADParameters)params;
+
+            nonce = param.getNonce();
+            initialAssociatedText = param.getAssociatedText();
+            macSize = param.getMacSize() / 8;
+            cipherParameters = param.getKey();
+        }
+        else if (params instanceof ParametersWithIV)
+        {
+            ParametersWithIV param = (ParametersWithIV)params;
+
+            nonce = param.getIV();
+            initialAssociatedText = null;
+            macSize = macBlock.length / 2;
+            cipherParameters = param.getParameters();
+        }
+        else
+        {
+            throw new IllegalArgumentException("invalid parameters passed to CCM: " + params.getClass().getName());
+        }
+
+        // NOTE: Very basic support for key re-use, but no performance gain from it
+        if (cipherParameters != null)
+        {
+            keyParam = cipherParameters;
+        }
+
+        if (nonce == null || nonce.length < 7 || nonce.length > 13)
+        {
+            throw new IllegalArgumentException("nonce must have length from 7 to 13 octets");
+        }
+
+        reset();
+    }
+
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/CCM";
+    }
+
+    public void processAADByte(byte in)
+    {
+        associatedText.write(in);
+    }
+
+    public void processAADBytes(byte[] in, int inOff, int len)
+    {
+        // TODO: Process AAD online
+        associatedText.write(in, inOff, len);
+    }
+
+    public int processByte(byte in, byte[] out, int outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        data.write(in);
+
+        return 0;
+    }
+
+    public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if (in.length < (inOff + inLen))
+        {
+            throw new DataLengthException("Input buffer too short");
+        }
+        data.write(in, inOff, inLen);
+
+        return 0;
+    }
+
+    public int doFinal(byte[] out, int outOff)
+        throws IllegalStateException, InvalidCipherTextException
+    {
+        int len = processPacket(data.getBuffer(), 0, data.size(), out, outOff);
+
+        reset();
+
+        return len;
+    }
+
+    public void reset()
+    {
+        cipher.reset();
+        associatedText.reset();
+        data.reset();
+    }
+
+    /**
+     * Returns a byte array containing the mac calculated as part of the
+     * last encrypt or decrypt operation.
+     *
+     * @return the last mac calculated.
+     */
+    public byte[] getMac()
+    {
+        byte[] mac = new byte[macSize];
+
+        System.arraycopy(macBlock, 0, mac, 0, mac.length);
+
+        return mac;
+    }
+
+    public int getUpdateOutputSize(int len)
+    {
+        return 0;
+    }
+
+    public int getOutputSize(int len)
+    {
+        int totalData = len + data.size();
+
+        if (forEncryption)
+        {
+             return totalData + macSize;
+        }
+
+        return totalData < macSize ? 0 : totalData - macSize;
+    }
+
+    /**
+     * Process a packet of data for either CCM decryption or encryption.
+     *
+     * @param in data for processing.
+     * @param inOff offset at which data starts in the input array.
+     * @param inLen length of the data in the input array.
+     * @return a byte array containing the processed input..
+     * @throws IllegalStateException if the cipher is not appropriately set up.
+     * @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
+     */
+    public byte[] processPacket(byte[] in, int inOff, int inLen)
+        throws IllegalStateException, InvalidCipherTextException
+    {
+        byte[] output;
+
+        if (forEncryption)
+        {
+            output = new byte[inLen + macSize];
+        }
+        else
+        {
+            if (inLen < macSize)
+            {
+                throw new InvalidCipherTextException("data too short");
+            }
+            output = new byte[inLen - macSize];
+        }
+
+        processPacket(in, inOff, inLen, output, 0);
+
+        return output;
+    }
+
+    /**
+     * Process a packet of data for either CCM decryption or encryption.
+     *
+     * @param in data for processing.
+     * @param inOff offset at which data starts in the input array.
+     * @param inLen length of the data in the input array.
+     * @param output output array.
+     * @param outOff offset into output array to start putting processed bytes.
+     * @return the number of bytes added to output.
+     * @throws IllegalStateException if the cipher is not appropriately set up.
+     * @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
+     * @throws DataLengthException if output buffer too short.
+     */
+    public int processPacket(byte[] in, int inOff, int inLen, byte[] output, int outOff)
+        throws IllegalStateException, InvalidCipherTextException, DataLengthException
+    {
+        // TODO: handle null keyParam (e.g. via RepeatedKeySpec)
+        // Need to keep the CTR and CBC Mac parts around and reset
+        if (keyParam == null)
+        {
+            throw new IllegalStateException("CCM cipher unitialized.");
+        }
+
+        int n = nonce.length;
+        int q = 15 - n;
+        if (q < 4)
+        {
+            int limitLen = 1 << (8 * q);
+            if (inLen >= limitLen)
+            {
+                throw new IllegalStateException("CCM packet too large for choice of q.");
+            }
+        }
+
+        byte[] iv = new byte[blockSize];
+        iv[0] = (byte)((q - 1) & 0x7);
+        System.arraycopy(nonce, 0, iv, 1, nonce.length);
+
+        BlockCipher ctrCipher = new SICBlockCipher(cipher);
+        ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv));
+
+        int outputLen;
+        int inIndex = inOff;
+        int outIndex = outOff;
+
+        if (forEncryption)
+        {
+            outputLen = inLen + macSize;
+            if (output.length < (outputLen + outOff))
+            {
+                throw new OutputLengthException("Output buffer too short.");
+            }
+
+            calculateMac(in, inOff, inLen, macBlock);
+
+            byte[] encMac = new byte[blockSize];
+
+            ctrCipher.processBlock(macBlock, 0, encMac, 0);   // S0
+
+            while (inIndex < (inOff + inLen - blockSize))                 // S1...
+            {
+                ctrCipher.processBlock(in, inIndex, output, outIndex);
+                outIndex += blockSize;
+                inIndex += blockSize;
+            }
+
+            byte[] block = new byte[blockSize];
+
+            System.arraycopy(in, inIndex, block, 0, inLen + inOff - inIndex);
+
+            ctrCipher.processBlock(block, 0, block, 0);
+
+            System.arraycopy(block, 0, output, outIndex, inLen + inOff - inIndex);
+
+            System.arraycopy(encMac, 0, output, outOff + inLen, macSize);
+        }
+        else
+        {
+            if (inLen < macSize)
+            {
+                throw new InvalidCipherTextException("data too short");
+            }
+            outputLen = inLen - macSize;
+            if (output.length < (outputLen + outOff))
+            {
+                throw new OutputLengthException("Output buffer too short.");
+            }
+
+            System.arraycopy(in, inOff + outputLen, macBlock, 0, macSize);
+
+            ctrCipher.processBlock(macBlock, 0, macBlock, 0);
+
+            for (int i = macSize; i != macBlock.length; i++)
+            {
+                macBlock[i] = 0;
+            }
+
+            while (inIndex < (inOff + outputLen - blockSize))
+            {
+                ctrCipher.processBlock(in, inIndex, output, outIndex);
+                outIndex += blockSize;
+                inIndex += blockSize;
+            }
+
+            byte[] block = new byte[blockSize];
+
+            System.arraycopy(in, inIndex, block, 0, outputLen - (inIndex - inOff));
+
+            ctrCipher.processBlock(block, 0, block, 0);
+
+            System.arraycopy(block, 0, output, outIndex, outputLen - (inIndex - inOff));
+
+            byte[] calculatedMacBlock = new byte[blockSize];
+
+            calculateMac(output, outOff, outputLen, calculatedMacBlock);
+
+            if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock))
+            {
+                throw new InvalidCipherTextException("mac check in CCM failed");
+            }
+        }
+
+        return outputLen;
+    }
+
+    private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
+    {
+        Mac cMac = new CBCBlockCipherMac(cipher, macSize * 8);
+
+        cMac.init(keyParam);
+
+        //
+        // build b0
+        //
+        byte[] b0 = new byte[16];
+
+        if (hasAssociatedText())
+        {
+            b0[0] |= 0x40;
+        }
+
+        b0[0] |= (((cMac.getMacSize() - 2) / 2) & 0x7) << 3;
+
+        b0[0] |= ((15 - nonce.length) - 1) & 0x7;
+
+        System.arraycopy(nonce, 0, b0, 1, nonce.length);
+
+        int q = dataLen;
+        int count = 1;
+        while (q > 0)
+        {
+            b0[b0.length - count] = (byte)(q & 0xff);
+            q >>>= 8;
+            count++;
+        }
+
+        cMac.update(b0, 0, b0.length);
+
+        //
+        // process associated text
+        //
+        if (hasAssociatedText())
+        {
+            int extra;
+
+            int textLength = getAssociatedTextLength();
+            if (textLength < ((1 << 16) - (1 << 8)))
+            {
+                cMac.update((byte)(textLength >> 8));
+                cMac.update((byte)textLength);
+
+                extra = 2;
+            }
+            else // can't go any higher than 2^32
+            {
+                cMac.update((byte)0xff);
+                cMac.update((byte)0xfe);
+                cMac.update((byte)(textLength >> 24));
+                cMac.update((byte)(textLength >> 16));
+                cMac.update((byte)(textLength >> 8));
+                cMac.update((byte)textLength);
+
+                extra = 6;
+            }
+
+            if (initialAssociatedText != null)
+            {
+                cMac.update(initialAssociatedText, 0, initialAssociatedText.length);
+            }
+            if (associatedText.size() > 0)
+            {
+                cMac.update(associatedText.getBuffer(), 0, associatedText.size());
+            }
+
+            extra = (extra + textLength) % 16;
+            if (extra != 0)
+            {
+                for (int i = extra; i != 16; i++)
+                {
+                    cMac.update((byte)0x00);
+                }
+            }
+        }
+
+        //
+        // add the text
+        //
+        cMac.update(data, dataOff, dataLen);
+
+        return cMac.doFinal(macBlock, 0);
+    }
+
+    private int getAssociatedTextLength()
+    {
+        return associatedText.size() + ((initialAssociatedText == null) ? 0 : initialAssociatedText.length);
+    }
+
+    private boolean hasAssociatedText()
+    {
+        return getAssociatedTextLength() > 0;
+    }
+
+    private class ExposedByteArrayOutputStream
+        extends ByteArrayOutputStream
+    {
+        public ExposedByteArrayOutputStream()
+        {
+        }
+
+        public byte[] getBuffer()
+        {
+            return this.buf;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CFBBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CFBBlockCipher.java
new file mode 100644
index 0000000..916cbd2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CFBBlockCipher.java
@@ -0,0 +1,271 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.StreamBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CFBBlockCipher
+    extends StreamBlockCipher
+{
+    private byte[]          IV;
+    private byte[]          cfbV;
+    private byte[]          cfbOutV;
+    private byte[]          inBuf;
+
+    private int             blockSize;
+    private BlockCipher     cipher = null;
+    private boolean         encrypting;
+    private int             byteCount;
+
+    /**
+     * Basic constructor.
+     *
+     * @param cipher the block cipher to be used as the basis of the
+     * feedback mode.
+     * @param bitBlockSize the block size in bits (note: a multiple of 8)
+     */
+    public CFBBlockCipher(
+        BlockCipher cipher,
+        int         bitBlockSize)
+    {
+        super(cipher);
+
+        this.cipher = cipher;
+        this.blockSize = bitBlockSize / 8;
+
+        this.IV = new byte[cipher.getBlockSize()];
+        this.cfbV = new byte[cipher.getBlockSize()];
+        this.cfbOutV = new byte[cipher.getBlockSize()];
+        this.inBuf = new byte[blockSize];
+    }
+
+    /**
+     * Initialise the cipher and, possibly, the initialisation vector (IV).
+     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+     * An IV which is too short is handled in FIPS compliant fashion.
+     *
+     * @param encrypting if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             encrypting,
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        this.encrypting = encrypting;
+        
+        if (params instanceof ParametersWithIV)
+        {
+            ParametersWithIV ivParam = (ParametersWithIV)params;
+            byte[]      iv = ivParam.getIV();
+
+            if (iv.length < IV.length)
+            {
+                // prepend the supplied IV with zeros (per FIPS PUB 81)
+                System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
+                for (int i = 0; i < IV.length - iv.length; i++)
+                {
+                    IV[i] = 0;
+                }
+            }
+            else
+            {
+                System.arraycopy(iv, 0, IV, 0, IV.length);
+            }
+
+            reset();
+
+            // if null it's an IV changed only.
+            if (ivParam.getParameters() != null)
+            {
+                cipher.init(true, ivParam.getParameters());
+            }
+        }
+        else
+        {
+            reset();
+
+            // if it's null, key is to be reused.
+            if (params != null)
+            {
+                cipher.init(true, params);
+            }
+        }
+    }
+
+    /**
+     * return the algorithm name and mode.
+     *
+     * @return the name of the underlying algorithm followed by "/CFB"
+     * and the block size in bits.
+     */
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/CFB" + (blockSize * 8);
+    }
+
+    protected byte calculateByte(byte in)
+          throws DataLengthException, IllegalStateException
+    {
+        return (encrypting) ? encryptByte(in) : decryptByte(in);
+    }
+
+    private byte encryptByte(byte in)
+    {
+        if (byteCount == 0)
+        {
+            cipher.processBlock(cfbV, 0, cfbOutV, 0);
+        }
+
+        byte rv = (byte)(cfbOutV[byteCount] ^ in);
+        inBuf[byteCount++] = rv;
+
+        if (byteCount == blockSize)
+        {
+            byteCount = 0;
+
+            System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
+            System.arraycopy(inBuf, 0, cfbV, cfbV.length - blockSize, blockSize);
+        }
+
+        return rv;
+    }
+
+    private byte decryptByte(byte in)
+    {
+        if (byteCount == 0)
+        {
+            cipher.processBlock(cfbV, 0, cfbOutV, 0);
+        }
+
+        inBuf[byteCount] = in;
+        byte rv = (byte)(cfbOutV[byteCount++] ^ in);
+
+        if (byteCount == blockSize)
+        {
+            byteCount = 0;
+
+            System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
+            System.arraycopy(inBuf, 0, cfbV, cfbV.length - blockSize, blockSize);
+        }
+
+        return rv;
+    }
+
+    /**
+     * return the block size we are operating at.
+     *
+     * @return the block size we are operating at (in bytes).
+     */
+    public int getBlockSize()
+    {
+        return blockSize;
+    }
+
+    /**
+     * Process one block of input from the array in and write it to
+     * the out array.
+     *
+     * @param in the array containing the input data.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the output data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int processBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        processBytes(in, inOff, blockSize, out, outOff);
+
+        return blockSize;
+    }
+
+    /**
+     * Do the appropriate processing for CFB mode encryption.
+     *
+     * @param in the array containing the data to be encrypted.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the encrypted data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int encryptBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        processBytes(in, inOff, blockSize, out, outOff);
+
+        return blockSize;
+    }
+
+    /**
+     * Do the appropriate processing for CFB mode decryption.
+     *
+     * @param in the array containing the data to be decrypted.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the encrypted data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int decryptBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        processBytes(in, inOff, blockSize, out, outOff);
+
+        return blockSize;
+    }
+
+    /**
+     * Return the current state of the initialisation vector.
+     *
+     * @return current IV
+     */
+    public byte[] getCurrentIV()
+    {
+        return Arrays.clone(cfbV);
+    }
+
+    /**
+     * reset the chaining vector back to the IV and reset the underlying
+     * cipher.
+     */
+    public void reset()
+    {
+        System.arraycopy(IV, 0, cfbV, 0, IV.length);
+        Arrays.fill(inBuf, (byte)0);
+        byteCount = 0;
+
+        cipher.reset();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CTSBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CTSBlockCipher.java
new file mode 100644
index 0000000..a277ae2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/CTSBlockCipher.java
@@ -0,0 +1,290 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.BufferedBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.StreamBlockCipher;
+
+/**
+ * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to
+ * be used to produce cipher text which is the same length as the plain text.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CTSBlockCipher
+    extends BufferedBlockCipher
+{
+    private int     blockSize;
+
+    /**
+     * Create a buffered block cipher that uses Cipher Text Stealing
+     *
+     * @param cipher the underlying block cipher this buffering object wraps.
+     */
+    public CTSBlockCipher(
+        BlockCipher     cipher)
+    {
+        if (cipher instanceof StreamBlockCipher)
+        {
+            throw new IllegalArgumentException("CTSBlockCipher can only accept ECB, or CBC ciphers");
+        }
+
+        this.cipher = cipher;
+
+        blockSize = cipher.getBlockSize();
+
+        buf = new byte[blockSize * 2];
+        bufOff = 0;
+    }
+
+    /**
+     * return the size of the output buffer required for an update 
+     * an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update
+     * with len bytes of input.
+     */
+    public int getUpdateOutputSize(
+        int len)
+    {
+        int total       = len + bufOff;
+        int leftOver    = total % buf.length;
+
+        if (leftOver == 0)
+        {
+            return total - buf.length;
+        }
+
+        return total - leftOver;
+    }
+
+    /**
+     * return the size of the output buffer required for an update plus a
+     * doFinal with an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update and doFinal
+     * with len bytes of input.
+     */
+    public int getOutputSize(
+        int len)
+    {
+        return len + bufOff;
+    }
+
+    /**
+     * process a single byte, producing an output block if necessary.
+     *
+     * @param in the input byte.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processByte(
+        byte        in,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        int         resultLen = 0;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = cipher.processBlock(buf, 0, out, outOff);
+            System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+            bufOff = blockSize;
+        }
+
+        buf[bufOff++] = in;
+
+        return resultLen;
+    }
+
+    /**
+     * process an array of bytes, producing output if necessary.
+     *
+     * @param in the input byte array.
+     * @param inOff the offset at which the input data starts.
+     * @param len the number of bytes to be copied out of the input array.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processBytes(
+        byte[]      in,
+        int         inOff,
+        int         len,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int blockSize   = getBlockSize();
+        int length      = getUpdateOutputSize(len);
+        
+        if (length > 0)
+        {
+            if ((outOff + length) > out.length)
+            {
+                throw new OutputLengthException("output buffer too short");
+            }
+        }
+
+        int resultLen = 0;
+        int gapLen = buf.length - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += cipher.processBlock(buf, 0, out, outOff);
+            System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+            bufOff = blockSize;
+
+            len -= gapLen;
+            inOff += gapLen;
+
+            while (len > blockSize)
+            {
+                System.arraycopy(in, inOff, buf, bufOff, blockSize);
+                resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+                System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+
+        bufOff += len;
+
+        return resultLen;
+    }
+
+    /**
+     * Process the last block in the buffer.
+     *
+     * @param out the array the block currently being held is copied into.
+     * @param outOff the offset at which the copying starts.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there is insufficient space in out for
+     * the output.
+     * @exception IllegalStateException if the underlying cipher is not
+     * initialised.
+     * @exception InvalidCipherTextException if cipher text decrypts wrongly (in
+     * case the exception will never get thrown).
+     */
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+        throws DataLengthException, IllegalStateException, InvalidCipherTextException
+    {
+        if (bufOff + outOff > out.length)
+        {
+            throw new OutputLengthException("output buffer to small in doFinal");
+        }
+
+        int     blockSize = cipher.getBlockSize();
+        int     len = bufOff - blockSize;
+        byte[]  block = new byte[blockSize];
+
+        if (forEncryption)
+        {
+            if (bufOff < blockSize)
+            {
+                throw new DataLengthException("need at least one block of input for CTS");
+            }
+
+            cipher.processBlock(buf, 0, block, 0);
+
+            if (bufOff > blockSize)
+            {
+                for (int i = bufOff; i != buf.length; i++)
+                {
+                    buf[i] = block[i - blockSize];
+                }
+
+                for (int i = blockSize; i != bufOff; i++)
+                {
+                    buf[i] ^= block[i - blockSize];
+                }
+
+                if (cipher instanceof CBCBlockCipher)
+                {
+                    BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
+
+                    c.processBlock(buf, blockSize, out, outOff);
+                }
+                else
+                {
+                    cipher.processBlock(buf, blockSize, out, outOff);
+                }
+
+                System.arraycopy(block, 0, out, outOff + blockSize, len);
+            }
+            else
+            {
+                System.arraycopy(block, 0, out, outOff, blockSize);
+            }
+        }
+        else
+        {
+            if (bufOff < blockSize)
+            {
+                throw new DataLengthException("need at least one block of input for CTS");
+            }
+
+            byte[]  lastBlock = new byte[blockSize];
+
+            if (bufOff > blockSize)
+            {
+                if (cipher instanceof CBCBlockCipher)
+                {
+                    BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
+
+                    c.processBlock(buf, 0, block, 0);
+                }
+                else
+                {
+                    cipher.processBlock(buf, 0, block, 0);
+                }
+
+                for (int i = blockSize; i != bufOff; i++)
+                {
+                    lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
+                }
+
+                System.arraycopy(buf, blockSize, block, 0, len);
+
+                cipher.processBlock(block, 0, out, outOff);
+                System.arraycopy(lastBlock, 0, out, outOff + blockSize, len);
+            }
+            else
+            {
+                cipher.processBlock(buf, 0, block, 0);
+
+                System.arraycopy(block, 0, out, outOff, blockSize);
+            }
+        }
+
+        int offset = bufOff;
+
+        reset();
+
+        return offset;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/GCMBlockCipher.java
new file mode 100644
index 0000000..e74dd6b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/GCMBlockCipher.java
@@ -0,0 +1,692 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.modes.gcm.BasicGCMExponentiator;
+import com.android.internal.org.bouncycastle.crypto.modes.gcm.GCMExponentiator;
+import com.android.internal.org.bouncycastle.crypto.modes.gcm.GCMMultiplier;
+import com.android.internal.org.bouncycastle.crypto.modes.gcm.GCMUtil;
+import com.android.internal.org.bouncycastle.crypto.modes.gcm.Tables4kGCMMultiplier;
+import com.android.internal.org.bouncycastle.crypto.params.AEADParameters;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * Implements the Galois/Counter mode (GCM) detailed in
+ * NIST Special Publication 800-38D.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class GCMBlockCipher
+    implements AEADBlockCipher
+{
+    private static final int BLOCK_SIZE = 16;
+    // BEGIN Android-added: Max input size limitation from NIST.
+    // 2^36-32 : limitation imposed by NIST GCM as otherwise the counter is wrapped and it can leak
+    // plaintext and authentication key
+    private static final long MAX_INPUT_SIZE = 68719476704L;
+    // END Android-added: Max input size limitation from NIST.
+
+    // not final due to a compiler bug
+    private BlockCipher   cipher;
+    private GCMMultiplier multiplier;
+    private GCMExponentiator exp;
+
+    // These fields are set by init and not modified by processing
+    private boolean             forEncryption;
+    private boolean             initialised;
+    private int                 macSize;
+    private byte[]              lastKey;
+    private byte[]              nonce;
+    private byte[]              initialAssociatedText;
+    private byte[]              H;
+    private byte[]              J0;
+
+    // These fields are modified during processing
+    private byte[]      bufBlock;
+    private byte[]      macBlock;
+    private byte[]      S, S_at, S_atPre;
+    private byte[]      counter;
+    private int         blocksRemaining;
+    private int         bufOff;
+    private long        totalLength;
+    private byte[]      atBlock;
+    private int         atBlockPos;
+    private long        atLength;
+    private long        atLengthPre;
+
+    public GCMBlockCipher(BlockCipher c)
+    {
+        this(c, null);
+    }
+
+    public GCMBlockCipher(BlockCipher c, GCMMultiplier m)
+    {
+        if (c.getBlockSize() != BLOCK_SIZE)
+        {
+            throw new IllegalArgumentException(
+                "cipher required with a block size of " + BLOCK_SIZE + ".");
+        }
+
+        if (m == null)
+        {
+            m = new Tables4kGCMMultiplier();
+        }
+
+        this.cipher = c;
+        this.multiplier = m;
+    }
+
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/GCM";
+    }
+
+    /**
+     * NOTE: MAC sizes from 32 bits to 128 bits (must be a multiple of 8) are supported. The default is 128 bits.
+     * Sizes less than 96 are not recommended, but are supported for specialized applications.
+     */
+    public void init(boolean forEncryption, CipherParameters params)
+        throws IllegalArgumentException
+    {
+        this.forEncryption = forEncryption;
+        this.macBlock = null;
+        this.initialised = true;
+
+        KeyParameter keyParam;
+        byte[] newNonce = null;
+
+        if (params instanceof AEADParameters)
+        {
+            AEADParameters param = (AEADParameters)params;
+
+            newNonce = param.getNonce();
+            initialAssociatedText = param.getAssociatedText();
+
+            int macSizeBits = param.getMacSize();
+            if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
+            {
+                throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits);
+            }
+
+            macSize = macSizeBits / 8;
+            keyParam = param.getKey();
+        }
+        else if (params instanceof ParametersWithIV)
+        {
+            ParametersWithIV param = (ParametersWithIV)params;
+
+            newNonce = param.getIV();
+            initialAssociatedText  = null;
+            macSize = 16;
+            keyParam = (KeyParameter)param.getParameters();
+        }
+        else
+        {
+            throw new IllegalArgumentException("invalid parameters passed to GCM");
+        }
+
+        int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
+        this.bufBlock = new byte[bufLength];
+
+        if (newNonce == null || newNonce.length < 1)
+        {
+            throw new IllegalArgumentException("IV must be at least 1 byte");
+        }
+
+        if (forEncryption)
+        {
+            if (nonce != null && Arrays.areEqual(nonce, newNonce))
+            {
+                if (keyParam == null)
+                {
+                    throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
+                }
+                if (lastKey != null && Arrays.areEqual(lastKey, keyParam.getKey()))
+                {
+                    throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
+                }
+            }
+        }
+
+        nonce = newNonce;
+        if (keyParam != null)
+        {
+            lastKey = keyParam.getKey();
+        }
+
+        // TODO Restrict macSize to 16 if nonce length not 12?
+
+        // Cipher always used in forward mode
+        // if keyParam is null we're reusing the last key.
+        if (keyParam != null)
+        {
+            cipher.init(true, keyParam);
+
+            this.H = new byte[BLOCK_SIZE];
+            cipher.processBlock(H, 0, H, 0);
+
+            // GCMMultiplier tables don't change unless the key changes (and are expensive to init)
+            multiplier.init(H);
+            exp = null;
+        }
+        else if (this.H == null)
+        {
+            throw new IllegalArgumentException("Key must be specified in initial init");
+        }
+
+        this.J0 = new byte[BLOCK_SIZE];
+
+        if (nonce.length == 12)
+        {
+            System.arraycopy(nonce, 0, J0, 0, nonce.length);
+            this.J0[BLOCK_SIZE - 1] = 0x01;
+        }
+        else
+        {
+            gHASH(J0, nonce, nonce.length);
+            byte[] X = new byte[BLOCK_SIZE];
+            Pack.longToBigEndian((long)nonce.length * 8, X, 8);
+            gHASHBlock(J0, X);
+        }
+
+        this.S = new byte[BLOCK_SIZE];
+        this.S_at = new byte[BLOCK_SIZE];
+        this.S_atPre = new byte[BLOCK_SIZE];
+        this.atBlock = new byte[BLOCK_SIZE];
+        this.atBlockPos = 0;
+        this.atLength = 0;
+        this.atLengthPre = 0;
+        this.counter = Arrays.clone(J0);
+        this.blocksRemaining = -2;      // page 8, len(P) <= 2^39 - 256, 1 block used by tag but done on J0
+        this.bufOff = 0;
+        this.totalLength = 0;
+
+        if (initialAssociatedText != null)
+        {
+            processAADBytes(initialAssociatedText, 0, initialAssociatedText.length);
+        }
+    }
+
+    public byte[] getMac()
+    {
+        if (macBlock == null)
+        {
+            return new byte[macSize];
+        }
+        return Arrays.clone(macBlock);
+    }
+
+    public int getOutputSize(int len)
+    {
+        int totalData = len + bufOff;
+
+        if (forEncryption)
+        {
+            return totalData + macSize;
+        }
+
+        return totalData < macSize ? 0 : totalData - macSize;
+    }
+
+    // BEGIN Android-added: Max input size limitation from NIST.
+    /** Helper used to ensure that {@link #MAX_INPUT_SIZE} is not exceeded. */
+    private long getTotalInputSizeAfterNewInput(int newInputLen)
+    {
+        return totalLength + newInputLen + bufOff;
+    }
+    // END Android-added: Max input size limitation from NIST.
+
+    public int getUpdateOutputSize(int len)
+    {
+        int totalData = len + bufOff;
+        if (!forEncryption)
+        {
+            if (totalData < macSize)
+            {
+                return 0;
+            }
+            totalData -= macSize;
+        }
+        return totalData - totalData % BLOCK_SIZE;
+    }
+
+    public void processAADByte(byte in)
+    {
+        checkStatus();
+        // BEGIN Android-added: Max input size limitation from NIST.
+        if (getTotalInputSizeAfterNewInput(1) > MAX_INPUT_SIZE) {
+            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
+        }
+        // END Android-added: Max input size limitation from NIST.
+
+        atBlock[atBlockPos] = in;
+        if (++atBlockPos == BLOCK_SIZE)
+        {
+            // Hash each block as it fills
+            gHASHBlock(S_at, atBlock);
+            atBlockPos = 0;
+            atLength += BLOCK_SIZE;
+        }
+    }
+
+    public void processAADBytes(byte[] in, int inOff, int len)
+    {
+        checkStatus();
+        // BEGIN Android-added: Max input size limitation from NIST.
+        if (getTotalInputSizeAfterNewInput(len) > MAX_INPUT_SIZE) {
+            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
+        }
+        // END Android-added: Max input size limitation from NIST.
+
+        for (int i = 0; i < len; ++i)
+        {
+            atBlock[atBlockPos] = in[inOff + i];
+            if (++atBlockPos == BLOCK_SIZE)
+            {
+                // Hash each block as it fills
+                gHASHBlock(S_at, atBlock);
+                atBlockPos = 0;
+                atLength += BLOCK_SIZE;
+            }
+        }
+    }
+
+    private void initCipher()
+    {
+        if (atLength > 0)
+        {
+            System.arraycopy(S_at, 0, S_atPre, 0, BLOCK_SIZE);
+            atLengthPre = atLength;
+        }
+
+        // Finish hash for partial AAD block
+        if (atBlockPos > 0)
+        {
+            gHASHPartial(S_atPre, atBlock, 0, atBlockPos);
+            atLengthPre += atBlockPos;
+        }
+
+        if (atLengthPre > 0)
+        {
+            System.arraycopy(S_atPre, 0, S, 0, BLOCK_SIZE);
+        }
+    }
+
+    public int processByte(byte in, byte[] out, int outOff)
+        throws DataLengthException
+    {
+        checkStatus();
+        // BEGIN Android-added: Max input size limitation from NIST.
+        if (getTotalInputSizeAfterNewInput(1) > MAX_INPUT_SIZE) {
+            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
+        }
+        // END Android-added: Max input size limitation from NIST.
+
+        bufBlock[bufOff] = in;
+        if (++bufOff == bufBlock.length)
+        {
+            processBlock(bufBlock, 0, out, outOff);
+            if (forEncryption)
+            {
+                bufOff = 0;
+            }
+            else
+            {
+                System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize);
+                bufOff = macSize;
+            }
+            return BLOCK_SIZE;
+        }
+        return 0;
+    }
+
+    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+        throws DataLengthException
+    {
+        checkStatus();
+        // BEGIN Android-added: Max input size limitation from NIST.
+        if (getTotalInputSizeAfterNewInput(len) > MAX_INPUT_SIZE) {
+            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
+        }
+        // END Android-added: Max input size limitation from NIST.
+
+        if ((in.length - inOff) < len)
+        {
+            throw new DataLengthException("Input buffer too short");
+        }
+
+        int resultLen = 0;
+
+        if (forEncryption)
+        {
+            if (bufOff != 0)
+            {
+                while (len > 0)
+                {
+                    --len;
+                    bufBlock[bufOff] = in[inOff++];
+                    if (++bufOff == BLOCK_SIZE)
+                    {
+                        processBlock(bufBlock, 0, out, outOff);
+                        bufOff = 0;
+                        resultLen += BLOCK_SIZE;
+                        break;
+                    }
+                }
+            }
+
+            while (len >= BLOCK_SIZE)
+            {
+                processBlock(in, inOff, out, outOff + resultLen);
+                inOff += BLOCK_SIZE;
+                len -= BLOCK_SIZE;
+                resultLen += BLOCK_SIZE;
+            }
+
+            if (len > 0)
+            {
+                System.arraycopy(in, inOff, bufBlock, 0, len);
+                bufOff = len;
+            }
+        }
+        else
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                bufBlock[bufOff] = in[inOff + i];
+                if (++bufOff == bufBlock.length)
+                {
+                    processBlock(bufBlock, 0, out, outOff + resultLen);
+                    System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize);
+                    bufOff = macSize;
+                    resultLen += BLOCK_SIZE;
+                }
+            }
+        }
+
+        return resultLen;
+    }
+
+    public int doFinal(byte[] out, int outOff)
+        throws IllegalStateException, InvalidCipherTextException
+    {
+        checkStatus();
+
+        if (totalLength == 0)
+        {
+            initCipher();
+        }
+
+        int extra = bufOff;
+
+        if (forEncryption)
+        {
+            if ((out.length - outOff) < (extra + macSize))
+            {
+                throw new OutputLengthException("Output buffer too short");
+            }
+        }
+        else
+        {
+            if (extra < macSize)
+            {
+                throw new InvalidCipherTextException("data too short");
+            }
+            extra -= macSize;
+
+            if ((out.length - outOff) < extra)
+            {
+                throw new OutputLengthException("Output buffer too short");
+            }
+        }
+
+        if (extra > 0)
+        {
+            processPartial(bufBlock, 0, extra, out, outOff);
+        }
+
+        atLength += atBlockPos;
+
+        if (atLength > atLengthPre)
+        {
+            /*
+             *  Some AAD was sent after the cipher started. We determine the difference b/w the hash value
+             *  we actually used when the cipher started (S_atPre) and the final hash value calculated (S_at).
+             *  Then we carry this difference forward by multiplying by H^c, where c is the number of (full or
+             *  partial) cipher-text blocks produced, and adjust the current hash.
+             */
+
+            // Finish hash for partial AAD block
+            if (atBlockPos > 0)
+            {
+                gHASHPartial(S_at, atBlock, 0, atBlockPos);
+            }
+
+            // Find the difference between the AAD hashes
+            if (atLengthPre > 0)
+            {
+                GCMUtil.xor(S_at, S_atPre);
+            }
+
+            // Number of cipher-text blocks produced
+            long c = ((totalLength * 8) + 127) >>> 7;
+
+            // Calculate the adjustment factor
+            byte[] H_c = new byte[16];
+            if (exp == null)
+            {
+                exp = new BasicGCMExponentiator();
+                exp.init(H);
+            }
+            exp.exponentiateX(c, H_c);
+
+            // Carry the difference forward
+            GCMUtil.multiply(S_at, H_c);
+
+            // Adjust the current hash
+            GCMUtil.xor(S, S_at);
+        }
+
+        // Final gHASH
+        byte[] X = new byte[BLOCK_SIZE];
+        Pack.longToBigEndian(atLength * 8, X, 0);
+        Pack.longToBigEndian(totalLength * 8, X, 8);
+
+        gHASHBlock(S, X);
+
+        // T = MSBt(GCTRk(J0,S))
+        byte[] tag = new byte[BLOCK_SIZE];
+        cipher.processBlock(J0, 0, tag, 0);
+        GCMUtil.xor(tag, S);
+
+        int resultLen = extra;
+
+        // We place into macBlock our calculated value for T
+        this.macBlock = new byte[macSize];
+        System.arraycopy(tag, 0, macBlock, 0, macSize);
+
+        if (forEncryption)
+        {
+            // Append T to the message
+            System.arraycopy(macBlock, 0, out, outOff + bufOff, macSize);
+            resultLen += macSize;
+        }
+        else
+        {
+            // Retrieve the T value from the message and compare to calculated one
+            byte[] msgMac = new byte[macSize];
+            System.arraycopy(bufBlock, extra, msgMac, 0, macSize);
+            if (!Arrays.constantTimeAreEqual(this.macBlock, msgMac))
+            {
+                throw new InvalidCipherTextException("mac check in GCM failed");
+            }
+        }
+
+        reset(false);
+
+        return resultLen;
+    }
+
+    public void reset()
+    {
+        reset(true);
+    }
+
+    private void reset(
+        boolean clearMac)
+    {
+        cipher.reset();
+
+        // note: we do not reset the nonce.
+
+        S = new byte[BLOCK_SIZE];
+        S_at = new byte[BLOCK_SIZE];
+        S_atPre = new byte[BLOCK_SIZE];
+        atBlock = new byte[BLOCK_SIZE];
+        atBlockPos = 0;
+        atLength = 0;
+        atLengthPre = 0;
+        counter = Arrays.clone(J0);
+        blocksRemaining = -2;
+        bufOff = 0;
+        totalLength = 0;
+
+        if (bufBlock != null)
+        {
+            Arrays.fill(bufBlock, (byte)0);
+        }
+
+        if (clearMac)
+        {
+            macBlock = null;
+        }
+
+        if (forEncryption)
+        {
+            initialised = false;
+        }
+        else
+        {
+            if (initialAssociatedText != null)
+            {
+                processAADBytes(initialAssociatedText, 0, initialAssociatedText.length);
+            }
+        }
+    }
+
+    private void processBlock(byte[] buf, int bufOff, byte[] out, int outOff)
+    {
+        if ((out.length - outOff) < BLOCK_SIZE)
+        {
+            throw new OutputLengthException("Output buffer too short");
+        }
+        if (totalLength == 0)
+        {
+            initCipher();
+        }
+
+        byte[] ctrBlock = new byte[BLOCK_SIZE];
+        getNextCTRBlock(ctrBlock);
+
+        if (forEncryption)
+        {
+            GCMUtil.xor(ctrBlock, buf, bufOff);
+            gHASHBlock(S, ctrBlock);
+            System.arraycopy(ctrBlock, 0, out, outOff, BLOCK_SIZE);
+        }
+        else
+        {
+            gHASHBlock(S, buf, bufOff);
+            GCMUtil.xor(ctrBlock, 0, buf, bufOff, out, outOff);
+        }
+
+        totalLength += BLOCK_SIZE;
+    }
+
+    private void processPartial(byte[] buf, int off, int len, byte[] out, int outOff)
+    {
+        byte[] ctrBlock = new byte[BLOCK_SIZE];
+        getNextCTRBlock(ctrBlock);
+
+        if (forEncryption)
+        {
+            GCMUtil.xor(buf, off, ctrBlock, 0, len);
+            gHASHPartial(S, buf, off, len);
+        }
+        else
+        {
+            gHASHPartial(S, buf, off, len);
+            GCMUtil.xor(buf, off, ctrBlock, 0, len);
+        }
+
+        System.arraycopy(buf, off, out, outOff, len);
+        totalLength += len;
+    }
+
+    private void gHASH(byte[] Y, byte[] b, int len)
+    {
+        for (int pos = 0; pos < len; pos += BLOCK_SIZE)
+        {
+            int num = Math.min(len - pos, BLOCK_SIZE);
+            gHASHPartial(Y, b, pos, num);
+        }
+    }
+
+    private void gHASHBlock(byte[] Y, byte[] b)
+    {
+        GCMUtil.xor(Y, b);
+        multiplier.multiplyH(Y);
+    }
+
+    private void gHASHBlock(byte[] Y, byte[] b, int off)
+    {
+        GCMUtil.xor(Y, b, off);
+        multiplier.multiplyH(Y);
+    }
+
+    private void gHASHPartial(byte[] Y, byte[] b, int off, int len)
+    {
+        GCMUtil.xor(Y, b, off, len);
+        multiplier.multiplyH(Y);
+    }
+
+    private void getNextCTRBlock(byte[] block)
+    {
+        if (blocksRemaining == 0)
+        {
+            throw new IllegalStateException("Attempt to process too many blocks");
+        }
+        blocksRemaining--;
+
+        int c = 1;
+        c += counter[15] & 0xFF; counter[15] = (byte)c; c >>>= 8;
+        c += counter[14] & 0xFF; counter[14] = (byte)c; c >>>= 8;
+        c += counter[13] & 0xFF; counter[13] = (byte)c; c >>>= 8;
+        c += counter[12] & 0xFF; counter[12] = (byte)c;
+
+        cipher.processBlock(counter, 0, block, 0);
+    }
+
+    private void checkStatus()
+    {
+        if (!initialised)
+        {
+            if (forEncryption)
+            {
+                throw new IllegalStateException("GCM cipher cannot be reused for encryption");
+            }
+            throw new IllegalStateException("GCM cipher needs to be initialised");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/OFBBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/OFBBlockCipher.java
new file mode 100644
index 0000000..f5d9743
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/OFBBlockCipher.java
@@ -0,0 +1,180 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.StreamBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * implements a Output-FeedBack (OFB) mode on top of a simple cipher.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OFBBlockCipher
+    extends StreamBlockCipher
+{
+    private int             byteCount;
+    private byte[]          IV;
+    private byte[]          ofbV;
+    private byte[]          ofbOutV;
+
+    private final int             blockSize;
+    private final BlockCipher     cipher;
+
+    /**
+     * Basic constructor.
+     *
+     * @param cipher the block cipher to be used as the basis of the
+     * feedback mode.
+     * @param blockSize the block size in bits (note: a multiple of 8)
+     */
+    public OFBBlockCipher(
+        BlockCipher cipher,
+        int         blockSize)
+    {
+        super(cipher);
+
+        this.cipher = cipher;
+        this.blockSize = blockSize / 8;
+
+        this.IV = new byte[cipher.getBlockSize()];
+        this.ofbV = new byte[cipher.getBlockSize()];
+        this.ofbOutV = new byte[cipher.getBlockSize()];
+    }
+
+    /**
+     * Initialise the cipher and, possibly, the initialisation vector (IV).
+     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+     * An IV which is too short is handled in FIPS compliant fashion.
+     *
+     * @param encrypting if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             encrypting, //ignored by this OFB mode
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        if (params instanceof ParametersWithIV)
+        {
+            ParametersWithIV ivParam = (ParametersWithIV)params;
+            byte[]      iv = ivParam.getIV();
+
+            if (iv.length < IV.length)
+            {
+                // prepend the supplied IV with zeros (per FIPS PUB 81)
+                System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length); 
+                for (int i = 0; i < IV.length - iv.length; i++)
+                {
+                    IV[i] = 0;
+                }
+            }
+            else
+            {
+                System.arraycopy(iv, 0, IV, 0, IV.length);
+            }
+
+            reset();
+
+            // if null it's an IV changed only.
+            if (ivParam.getParameters() != null)
+            {
+                cipher.init(true, ivParam.getParameters());
+            }
+        }
+        else
+        {
+            reset();
+
+            // if it's null, key is to be reused.
+            if (params != null)
+            {
+                cipher.init(true, params);
+            }
+        }
+    }
+
+    /**
+     * return the algorithm name and mode.
+     *
+     * @return the name of the underlying algorithm followed by "/OFB"
+     * and the block size in bits
+     */
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/OFB" + (blockSize * 8);
+    }
+
+
+    /**
+     * return the block size we are operating at (in bytes).
+     *
+     * @return the block size we are operating at (in bytes).
+     */
+    public int getBlockSize()
+    {
+        return blockSize;
+    }
+
+    /**
+     * Process one block of input from the array in and write it to
+     * the out array.
+     *
+     * @param in the array containing the input data.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the output data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int processBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        processBytes(in, inOff, blockSize, out, outOff);
+
+        return blockSize;
+    }
+
+    /**
+     * reset the feedback vector back to the IV and reset the underlying
+     * cipher.
+     */
+    public void reset()
+    {
+        System.arraycopy(IV, 0, ofbV, 0, IV.length);
+        byteCount = 0;
+
+        cipher.reset();
+    }
+
+    protected byte calculateByte(byte in)
+          throws DataLengthException, IllegalStateException
+    {
+        if (byteCount == 0)
+        {
+            cipher.processBlock(ofbV, 0, ofbOutV, 0);
+        }
+
+        byte rv = (byte)(ofbOutV[byteCount++] ^ in);
+
+        if (byteCount == blockSize)
+        {
+            byteCount = 0;
+
+            System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize);
+            System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize);
+        }
+
+        return rv;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/SICBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/SICBlockCipher.java
new file mode 100644
index 0000000..b4121be
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/SICBlockCipher.java
@@ -0,0 +1,292 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.SkippingStreamCipher;
+import com.android.internal.org.bouncycastle.crypto.StreamBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * Implements the Segmented Integer Counter (SIC) mode on top of a simple
+ * block cipher. This mode is also known as CTR mode.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SICBlockCipher
+    extends StreamBlockCipher
+    implements SkippingStreamCipher
+{
+    private final BlockCipher     cipher;
+    private final int             blockSize;
+
+    private byte[]          IV;
+    private byte[]          counter;
+    private byte[]          counterOut;
+    private int             byteCount;
+
+    /**
+     * Basic constructor.
+     *
+     * @param c the block cipher to be used.
+     */
+    public SICBlockCipher(BlockCipher c)
+    {
+        super(c);
+
+        this.cipher = c;
+        this.blockSize = cipher.getBlockSize();
+        this.IV = new byte[blockSize];
+        this.counter = new byte[blockSize];
+        this.counterOut = new byte[blockSize];
+        this.byteCount = 0;
+    }
+
+    public void init(
+        boolean             forEncryption, //ignored by this CTR mode
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        if (params instanceof ParametersWithIV)
+        {
+            ParametersWithIV ivParam = (ParametersWithIV)params;
+            this.IV = Arrays.clone(ivParam.getIV());
+
+            if (blockSize < IV.length)
+            {
+                throw new IllegalArgumentException("CTR/SIC mode requires IV no greater than: " + blockSize + " bytes.");
+            }
+
+            int maxCounterSize = (8 > blockSize / 2) ? blockSize / 2 : 8;
+
+            if (blockSize - IV.length > maxCounterSize)
+            {
+                throw new IllegalArgumentException("CTR/SIC mode requires IV of at least: " + (blockSize - maxCounterSize) + " bytes.");
+            }
+
+            // if null it's an IV changed only.
+            if (ivParam.getParameters() != null)
+            {
+                cipher.init(true, ivParam.getParameters());
+            }
+
+            reset();
+        }
+        else
+        {
+            throw new IllegalArgumentException("CTR/SIC mode requires ParametersWithIV");
+        }
+    }
+
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/SIC";
+    }
+
+    public int getBlockSize()
+    {
+        return cipher.getBlockSize();
+    }
+
+    public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+          throws DataLengthException, IllegalStateException
+    {
+        processBytes(in, inOff, blockSize, out, outOff);
+
+        return blockSize;
+    }
+
+    protected byte calculateByte(byte in)
+          throws DataLengthException, IllegalStateException
+    {
+        if (byteCount == 0)
+        {
+            cipher.processBlock(counter, 0, counterOut, 0);
+
+            return (byte)(counterOut[byteCount++] ^ in);
+        }
+
+        byte rv = (byte)(counterOut[byteCount++] ^ in);
+
+        if (byteCount == counter.length)
+        {
+            byteCount = 0;
+
+            incrementCounterAt(0);
+
+            checkCounter();
+        }
+
+        return rv;
+    }
+
+    private void checkCounter()
+    {
+        // if the IV is the same as the blocksize we assume the user knows what they are doing
+        if (IV.length < blockSize)
+        {
+            for (int i = 0; i != IV.length; i++)
+            {
+                if (counter[i] != IV[i])
+                {
+                    throw new IllegalStateException("Counter in CTR/SIC mode out of range.");
+                }
+            }
+        }
+    }
+
+    private void incrementCounterAt(int pos)
+    {
+        int i = counter.length - pos;
+        while (--i >= 0)
+        {
+            if (++counter[i] != 0)
+            {
+                break;
+            }
+        }
+    }
+
+    private void incrementCounter(int offSet)
+    {
+        byte old = counter[counter.length - 1];
+
+        counter[counter.length - 1] += offSet;
+
+        if (old != 0 && counter[counter.length - 1] < old)
+        {
+            incrementCounterAt(1);
+        }
+    }
+
+    private void decrementCounterAt(int pos)
+    {
+        int i = counter.length - pos;
+        while (--i >= 0)
+        {
+            if (--counter[i] != -1)
+            {
+                return;
+            }
+        }
+    }
+
+    private void adjustCounter(long n)
+    {
+        if (n >= 0)
+        {
+            long numBlocks = (n + byteCount) / blockSize;
+
+            long rem = numBlocks;
+            if (rem > 255)
+            {
+                for (int i = 5; i >= 1; i--)
+                {
+                    long diff = 1L << (8 * i);
+                    while (rem >= diff)
+                    {
+                        incrementCounterAt(i);
+                        rem -= diff;
+                    }
+                }
+            }
+
+            incrementCounter((int)rem);
+
+            byteCount = (int)((n + byteCount) - (blockSize * numBlocks));
+        }
+        else
+        {
+            long numBlocks = (-n - byteCount) / blockSize;
+
+            long rem = numBlocks;
+            if (rem > 255)
+            {
+                for (int i = 5; i >= 1; i--)
+                {
+                    long diff = 1L << (8 * i);
+                    while (rem > diff)
+                    {
+                        decrementCounterAt(i);
+                        rem -= diff;
+                    }
+                }
+            }
+
+            for (long i = 0; i != rem; i++)
+            {
+                decrementCounterAt(0);
+            }
+
+            int gap = (int)(byteCount + n + (blockSize * numBlocks));
+
+            if (gap >= 0)
+            {
+                byteCount = 0;
+            }
+            else
+            {
+                decrementCounterAt(0);
+                byteCount =  blockSize + gap;
+            }
+        }
+    }
+
+    public void reset()
+    {
+        Arrays.fill(counter, (byte)0);
+        System.arraycopy(IV, 0, counter, 0, IV.length);
+        cipher.reset();
+        this.byteCount = 0;
+    }
+
+    public long skip(long numberOfBytes)
+    {
+        adjustCounter(numberOfBytes);
+
+        checkCounter();
+
+        cipher.processBlock(counter, 0, counterOut, 0);
+
+        return numberOfBytes;
+    }
+
+    public long seekTo(long position)
+    {
+        reset();
+
+        return skip(position);
+    }
+
+    public long getPosition()
+    {
+        byte[] res = new byte[counter.length];
+
+        System.arraycopy(counter, 0, res, 0, res.length);
+
+        for (int i = res.length - 1; i >= 1; i--)
+        {
+            int v;
+            if (i < IV.length)
+            {
+                v = (res[i] & 0xff) - (IV[i] & 0xff);
+            }
+            else
+            {
+                v = (res[i] & 0xff);
+            }
+
+            if (v < 0)
+            {
+               res[i - 1]--;
+               v += 256;
+            }
+
+            res[i] = (byte)v;
+        }
+
+        return Pack.bigEndianToLong(res, res.length - 8) * blockSize + byteCount;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java
new file mode 100644
index 0000000..2d317ff
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java
@@ -0,0 +1,41 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes.gcm;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BasicGCMExponentiator
+    implements GCMExponentiator
+{
+    private long[] x;
+
+    public void init(byte[] x)
+    {
+        this.x = GCMUtil.asLongs(x);
+    }
+
+    public void exponentiateX(long pow, byte[] output)
+    {
+        // Initial value is little-endian 1
+        long[] y = GCMUtil.oneAsLongs();
+
+        if (pow > 0)
+        {
+            long[] powX = Arrays.clone(x);
+            do
+            {
+                if ((pow & 1L) != 0)
+                {
+                    GCMUtil.multiply(y, powX);
+                }
+                GCMUtil.square(powX, powX);
+                pow >>>= 1;
+            }
+            while (pow > 0);
+        }
+
+        GCMUtil.asBytes(y, output);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/GCMExponentiator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/GCMExponentiator.java
new file mode 100644
index 0000000..82f912f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/GCMExponentiator.java
@@ -0,0 +1,11 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes.gcm;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface GCMExponentiator
+{
+    void init(byte[] x);
+    void exponentiateX(long pow, byte[] output);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/GCMMultiplier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/GCMMultiplier.java
new file mode 100644
index 0000000..873b8e8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/GCMMultiplier.java
@@ -0,0 +1,11 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes.gcm;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface GCMMultiplier
+{
+    void init(byte[] H);
+    void multiplyH(byte[] x);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/GCMUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
new file mode 100644
index 0000000..a712b70
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
@@ -0,0 +1,389 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes.gcm;
+
+import com.android.internal.org.bouncycastle.math.raw.Interleave;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class GCMUtil
+{
+    private static final int E1 = 0xe1000000;
+    private static final long E1L = (E1 & 0xFFFFFFFFL) << 32;
+
+    public static byte[] oneAsBytes()
+    {
+        byte[] tmp = new byte[16];
+        tmp[0] = (byte)0x80;
+        return tmp;
+    }
+
+    public static int[] oneAsInts()
+    {
+        int[] tmp = new int[4];
+        tmp[0] = 1 << 31;
+        return tmp;
+    }
+
+    public static long[] oneAsLongs()
+    {
+        long[] tmp = new long[2];
+        tmp[0] = 1L << 63;
+        return tmp;
+    }
+
+    public static byte[] asBytes(int[] x)
+    {
+        byte[] z = new byte[16];
+        Pack.intToBigEndian(x, z, 0);
+        return z;
+    }
+
+    public static void asBytes(int[] x, byte[] z)
+    {
+        Pack.intToBigEndian(x, z, 0);
+    }
+
+    public static byte[] asBytes(long[] x)
+    {
+        byte[] z = new byte[16];
+        Pack.longToBigEndian(x, z, 0);
+        return z;
+    }
+
+    public static void asBytes(long[] x, byte[] z)
+    {
+        Pack.longToBigEndian(x, z, 0);
+    }
+
+    public static int[] asInts(byte[] x)
+    {
+        int[] z = new int[4];
+        Pack.bigEndianToInt(x, 0, z);
+        return z;
+    }
+
+    public static void asInts(byte[] x, int[] z)
+    {
+        Pack.bigEndianToInt(x, 0, z);
+    }
+
+    public static long[] asLongs(byte[] x)
+    {
+        long[] z = new long[2];
+        Pack.bigEndianToLong(x, 0, z);
+        return z;
+    }
+
+    public static void asLongs(byte[] x, long[] z)
+    {
+        Pack.bigEndianToLong(x, 0, z);
+    }
+
+    public static void copy(int[] x, int[] z)
+    {
+        z[0] = x[0];
+        z[1] = x[1];
+        z[2] = x[2];
+        z[3] = x[3];
+    }
+
+    public static void copy(long[] x, long[] z)
+    {
+        z[0] = x[0];
+        z[1] = x[1];
+    }
+
+    public static void divideP(long[] x, long[] z)
+    {
+        long x0 = x[0], x1 = x[1];
+        long m = x0 >> 63;
+        x0 ^= (m & E1L);
+        z[0] = (x0 << 1) | (x1 >>> 63);
+        z[1] = (x1 << 1) | -m;
+    }
+
+    public static void multiply(byte[] x, byte[] y)
+    {
+        long[] t1 = GCMUtil.asLongs(x);
+        long[] t2 = GCMUtil.asLongs(y);
+        GCMUtil.multiply(t1, t2);
+        GCMUtil.asBytes(t1, x);
+    }
+
+    public static void multiply(int[] x, int[] y)
+    {
+        int y0 = y[0], y1 = y[1], y2 = y[2], y3 = y[3];
+        int z0 = 0, z1 = 0, z2 = 0, z3 = 0;
+
+        for (int i = 0; i < 4; ++i)
+        {
+            int bits = x[i];
+            for (int j = 0; j < 32; ++j)
+            {
+                int m1 = bits >> 31; bits <<= 1;
+                z0 ^= (y0 & m1);
+                z1 ^= (y1 & m1);
+                z2 ^= (y2 & m1);
+                z3 ^= (y3 & m1);
+
+                int m2 = (y3 << 31) >> 8;
+                y3 = (y3 >>> 1) | (y2 << 31);
+                y2 = (y2 >>> 1) | (y1 << 31);
+                y1 = (y1 >>> 1) | (y0 << 31);
+                y0 = (y0 >>> 1) ^ (m2 & E1);
+            }
+        }
+
+        x[0] = z0;
+        x[1] = z1;
+        x[2] = z2;
+        x[3] = z3;
+    }
+
+    public static void multiply(long[] x, long[] y)
+    {
+        long x0 = x[0], x1 = x[1];
+        long y0 = y[0], y1 = y[1];
+        long z0 = 0, z1 = 0, z2 = 0;
+
+        for (int j = 0; j < 64; ++j)
+        {
+            long m0 = x0 >> 63; x0 <<= 1;
+            z0 ^= (y0 & m0);
+            z1 ^= (y1 & m0);
+
+            long m1 = x1 >> 63; x1 <<= 1;
+            z1 ^= (y0 & m1);
+            z2 ^= (y1 & m1);
+
+            long c = (y1 << 63) >> 8;
+            y1 = (y1 >>> 1) | (y0 << 63);
+            y0 = (y0 >>> 1) ^ (c & E1L);
+        }
+
+        z0 ^= z2 ^ (z2 >>>  1) ^ (z2 >>>  2) ^ (z2 >>>  7);
+        z1 ^=      (z2 <<  63) ^ (z2 <<  62) ^ (z2 <<  57);
+
+        x[0] = z0;
+        x[1] = z1;
+    }
+
+    public static void multiplyP(int[] x)
+    {
+        int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+        int m = (x3 << 31) >> 31;
+        x[0] = (x0 >>> 1) ^ (m & E1);
+        x[1] = (x1 >>> 1) | (x0 << 31);
+        x[2] = (x2 >>> 1) | (x1 << 31);
+        x[3] = (x3 >>> 1) | (x2 << 31);
+    }
+
+    public static void multiplyP(int[] x, int[] z)
+    {
+        int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+        int m = (x3 << 31) >> 31;
+        z[0] = (x0 >>> 1) ^ (m & E1);
+        z[1] = (x1 >>> 1) | (x0 << 31);
+        z[2] = (x2 >>> 1) | (x1 << 31);
+        z[3] = (x3 >>> 1) | (x2 << 31);
+    }
+
+    public static void multiplyP(long[] x)
+    {
+        long x0 = x[0], x1 = x[1];
+        long m = (x1 << 63) >> 63;
+        x[0] = (x0 >>> 1) ^ (m & E1L);
+        x[1] = (x1 >>> 1) | (x0 << 63);
+    }
+
+    public static void multiplyP(long[] x, long[] z)
+    {
+        long x0 = x[0], x1 = x[1];
+        long m = (x1 << 63) >> 63;
+        z[0] = (x0 >>> 1) ^ (m & E1L);
+        z[1] = (x1 >>> 1) | (x0 << 63);
+    }
+
+    public static void multiplyP3(long[] x, long[] z)
+    {
+        long x0 = x[0], x1 = x[1];
+        long c = x1 << 61;
+        z[0] = (x0 >>> 3) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7);
+        z[1] = (x1 >>> 3) | (x0 << 61);
+    }
+
+    public static void multiplyP4(long[] x, long[] z)
+    {
+        long x0 = x[0], x1 = x[1];
+        long c = x1 << 60;
+        z[0] = (x0 >>> 4) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7);
+        z[1] = (x1 >>> 4) | (x0 << 60);
+    }
+
+    public static void multiplyP7(long[] x, long[] z)
+    {
+        long x0 = x[0], x1 = x[1];
+        long c = x1 << 57;
+        z[0] = (x0 >>> 7) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7);
+        z[1] = (x1 >>> 7) | (x0 << 57);
+    }
+
+    public static void multiplyP8(int[] x)
+    {
+        int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+        int c = x3 << 24;
+        x[0] = (x0 >>> 8) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7);
+        x[1] = (x1 >>> 8) | (x0 << 24);
+        x[2] = (x2 >>> 8) | (x1 << 24);
+        x[3] = (x3 >>> 8) | (x2 << 24);
+    }
+
+    public static void multiplyP8(int[] x, int[] y)
+    {
+        int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+        int c = x3 << 24;
+        y[0] = (x0 >>> 8) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7);
+        y[1] = (x1 >>> 8) | (x0 << 24);
+        y[2] = (x2 >>> 8) | (x1 << 24);
+        y[3] = (x3 >>> 8) | (x2 << 24);
+    }
+
+    public static void multiplyP8(long[] x)
+    {
+        long x0 = x[0], x1 = x[1];
+        long c = x1 << 56;
+        x[0] = (x0 >>> 8) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7);
+        x[1] = (x1 >>> 8) | (x0 << 56);
+    }
+
+    public static void multiplyP8(long[] x, long[] y)
+    {
+        long x0 = x[0], x1 = x[1];
+        long c = x1 << 56;
+        y[0] = (x0 >>> 8) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7);
+        y[1] = (x1 >>> 8) | (x0 << 56);
+    }
+
+    public static long[] pAsLongs()
+    {
+        long[] tmp = new long[2];
+        tmp[0] = 1L << 62;
+        return tmp;
+    }
+
+    public static void square(long[] x, long[] z)
+    {
+        long[] t  = new long[4];
+        Interleave.expand64To128Rev(x[0], t, 0);
+        Interleave.expand64To128Rev(x[1], t, 2);
+
+        long z0 = t[0], z1 = t[1], z2 = t[2], z3 = t[3];
+
+        z1 ^= z3 ^ (z3 >>>  1) ^ (z3 >>>  2) ^ (z3 >>>  7);
+        z2 ^=      (z3 <<  63) ^ (z3 <<  62) ^ (z3 <<  57);
+
+        z0 ^= z2 ^ (z2 >>>  1) ^ (z2 >>>  2) ^ (z2 >>>  7);
+        z1 ^=      (z2 <<  63) ^ (z2 <<  62) ^ (z2 <<  57);
+
+        z[0] = z0;
+        z[1] = z1;
+    }
+
+    public static void xor(byte[] x, byte[] y)
+    {
+        int i = 0;
+        do
+        {
+            x[i] ^= y[i]; ++i;
+            x[i] ^= y[i]; ++i;
+            x[i] ^= y[i]; ++i;
+            x[i] ^= y[i]; ++i;
+        }
+        while (i < 16);
+    }
+
+    public static void xor(byte[] x, byte[] y, int yOff)
+    {
+        int i = 0;
+        do
+        {
+            x[i] ^= y[yOff + i]; ++i;
+            x[i] ^= y[yOff + i]; ++i;
+            x[i] ^= y[yOff + i]; ++i;
+            x[i] ^= y[yOff + i]; ++i;
+        }
+        while (i < 16);
+    }
+
+    public static void xor(byte[] x, int xOff, byte[] y, int yOff, byte[] z, int zOff)
+    {
+        int i = 0;
+        do
+        {
+            z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i;
+            z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i;
+            z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i;
+            z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i;
+        }
+        while (i < 16);
+    }
+
+    public static void xor(byte[] x, byte[] y, int yOff, int yLen)
+    {
+        while (--yLen >= 0)
+        {
+            x[yLen] ^= y[yOff + yLen];
+        }
+    }
+
+    public static void xor(byte[] x, int xOff, byte[] y, int yOff, int len)
+    {
+        while (--len >= 0)
+        {
+            x[xOff + len] ^= y[yOff + len];
+        }
+    }
+
+    public static void xor(byte[] x, byte[] y, byte[] z)
+    {
+        int i = 0;
+        do
+        {
+            z[i] = (byte)(x[i] ^ y[i]); ++i;
+            z[i] = (byte)(x[i] ^ y[i]); ++i;
+            z[i] = (byte)(x[i] ^ y[i]); ++i;
+            z[i] = (byte)(x[i] ^ y[i]); ++i;
+        }
+        while (i < 16);
+    }
+
+    public static void xor(int[] x, int[] y)
+    {
+        x[0] ^= y[0];
+        x[1] ^= y[1];
+        x[2] ^= y[2];
+        x[3] ^= y[3];
+    }
+
+    public static void xor(int[] x, int[] y, int[] z)
+    {
+        z[0] = x[0] ^ y[0];
+        z[1] = x[1] ^ y[1];
+        z[2] = x[2] ^ y[2];
+        z[3] = x[3] ^ y[3];
+    }
+
+    public static void xor(long[] x, long[] y)
+    {
+        x[0] ^= y[0];
+        x[1] ^= y[1];
+    }
+
+    public static void xor(long[] x, long[] y, long[] z)
+    {
+        z[0] = x[0] ^ y[0];
+        z[1] = x[1] ^ y[1];
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java
new file mode 100644
index 0000000..7689396
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java
@@ -0,0 +1,63 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes.gcm;
+
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Tables1kGCMExponentiator
+    implements GCMExponentiator
+{
+    // A lookup table of the power-of-two powers of 'x'
+    // - lookupPowX2[i] = x^(2^i)
+    private Vector lookupPowX2;
+
+    public void init(byte[] x)
+    {
+        long[] y = GCMUtil.asLongs(x);
+        if (lookupPowX2 != null && Arrays.areEqual(y, (long[])lookupPowX2.elementAt(0)))
+        {
+            return;
+        }
+
+        lookupPowX2 = new Vector(8);
+        lookupPowX2.addElement(y);
+    }
+
+    public void exponentiateX(long pow, byte[] output)
+    {
+        long[] y = GCMUtil.oneAsLongs();
+        int bit = 0;
+        while (pow > 0)
+        {
+            if ((pow & 1L) != 0)
+            {
+                ensureAvailable(bit);
+                GCMUtil.multiply(y, (long[])lookupPowX2.elementAt(bit));
+            }
+            ++bit;
+            pow >>>= 1;
+        }
+
+        GCMUtil.asBytes(y, output);
+    }
+
+    private void ensureAvailable(int bit)
+    {
+        int count = lookupPowX2.size();
+        if (count <= bit)
+        {
+            long[] tmp = (long[])lookupPowX2.elementAt(count - 1);
+            do
+            {
+                tmp = Arrays.clone(tmp);
+                GCMUtil.square(tmp, tmp);
+                lookupPowX2.addElement(tmp);
+            }
+            while (++count <= bit);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/Tables4kGCMMultiplier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/Tables4kGCMMultiplier.java
new file mode 100644
index 0000000..30f2af6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/Tables4kGCMMultiplier.java
@@ -0,0 +1,71 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes.gcm;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Tables4kGCMMultiplier
+    implements GCMMultiplier
+{
+    private byte[] H;
+    private long[][] T;
+
+    public void init(byte[] H)
+    {
+        if (T == null)
+        {
+            T = new long[256][2];
+        }
+        else if (Arrays.areEqual(this.H, H))
+        {
+            return;
+        }
+
+        this.H = Arrays.clone(H);
+
+        // T[0] = 0
+
+        // T[1] = H.p^7
+        GCMUtil.asLongs(this.H, T[1]);
+        GCMUtil.multiplyP7(T[1], T[1]);
+
+        for (int n = 2; n < 256; n += 2)
+        {
+            // T[2.n] = T[n].p^-1
+            GCMUtil.divideP(T[n >> 1], T[n]);
+
+            // T[2.n + 1] = T[2.n] + T[1]
+            GCMUtil.xor(T[n], T[1], T[n + 1]);
+        }
+    }
+
+    public void multiplyH(byte[] x)
+    {
+//        long[] z = new long[2];
+//        GCMUtil.copy(T[x[15] & 0xFF], z);
+//        for (int i = 14; i >= 0; --i)
+//        {
+//            GCMUtil.multiplyP8(z);
+//            GCMUtil.xor(z, T[x[i] & 0xFF]);
+//        }
+//        Pack.longToBigEndian(z, x, 0);
+
+        long[] t = T[x[15] & 0xFF];
+        long z0 = t[0], z1 = t[1];
+
+        for (int i = 14; i >= 0; --i)
+        {
+            t = T[x[i] & 0xFF];
+
+            long c = z1 << 56;
+            z1 = t[1] ^ ((z1 >>> 8) | (z0 << 56));
+            z0 = t[0] ^ (z0 >>> 8) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7);
+        }
+
+        Pack.longToBigEndian(z0, x, 0);
+        Pack.longToBigEndian(z1, x, 8);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java
new file mode 100644
index 0000000..3b92541
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java
@@ -0,0 +1,83 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.modes.gcm;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Tables8kGCMMultiplier
+    implements GCMMultiplier
+{
+    private byte[] H;
+    private long[][][] T;
+
+    public void init(byte[] H)
+    {
+        if (T == null)
+        {
+            T = new long[32][16][2];
+        }
+        else if (Arrays.areEqual(this.H, H))
+        {
+            return;
+        }
+
+        this.H = Arrays.clone(H);
+
+        for (int i = 0; i < 32; ++i)
+        {
+            long[][] t = T[i];
+
+            // t[0] = 0
+
+            if (i == 0)
+            {
+                // t[1] = H.p^3
+                GCMUtil.asLongs(this.H, t[1]);
+                GCMUtil.multiplyP3(t[1], t[1]);
+            }
+            else
+            {
+                // t[1] = T[i-1][1].p^4
+                GCMUtil.multiplyP4(T[i - 1][1], t[1]);
+            }
+
+            for (int n = 2; n < 16; n += 2)
+            {
+                // t[2.n] = t[n].p^-1
+                GCMUtil.divideP(t[n >> 1], t[n]);
+
+                // t[2.n + 1] = t[2.n] + t[1]
+                GCMUtil.xor(t[n], t[1], t[n + 1]);
+            }
+        }
+
+    }
+
+    public void multiplyH(byte[] x)
+    {
+//        long[] z = new long[2];
+//        for (int i = 15; i >= 0; --i)
+//        {
+//            GCMUtil.xor(z, T[i + i + 1][(x[i] & 0x0F)]);
+//            GCMUtil.xor(z, T[i + i    ][(x[i] & 0xF0) >>> 4]);
+//        }
+//        Pack.longToBigEndian(z, x, 0);
+
+        long z0 = 0, z1 = 0;
+
+        for (int i = 15; i >= 0; --i)
+        {
+            long[] u = T[i + i + 1][(x[i] & 0x0F)];
+            long[] v = T[i + i    ][(x[i] & 0xF0) >>> 4];
+
+            z0 ^= u[0] ^ v[0];
+            z1 ^= u[1] ^ v[1];
+        }
+
+        Pack.longToBigEndian(z0, x, 0);
+        Pack.longToBigEndian(z1, x, 8);
+   }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/BlockCipherPadding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/BlockCipherPadding.java
new file mode 100644
index 0000000..54d349b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/BlockCipherPadding.java
@@ -0,0 +1,50 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * Block cipher padders are expected to conform to this interface
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface BlockCipherPadding
+{
+    /**
+     * Initialise the padder.
+     *
+     * @param random the source of randomness for the padding, if required.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException;
+
+    /**
+     * Return the name of the algorithm the cipher implements.
+     *
+     * @return the name of the algorithm the cipher implements.
+     */
+    public String getPaddingName();
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     * <p>
+     * Note: this assumes that the last block of plain text is always 
+     * passed to it inside in. i.e. if inOff is zero, indicating the
+     * entire block is to be overwritten with padding the value of in
+     * should be the same as the last block of plain text. The reason
+     * for this is that some modes such as "trailing bit compliment"
+     * base the padding on the last byte of plain text.
+     * </p>
+     */
+    public int addPadding(byte[] in, int inOff);
+
+    /**
+     * return the number of pad bytes present in the block.
+     * @exception InvalidCipherTextException if the padding is badly formed
+     * or invalid.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java
new file mode 100644
index 0000000..456a5f1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java
@@ -0,0 +1,82 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds ISO10126-2 padding to a block.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ISO10126d2Padding
+    implements BlockCipherPadding
+{
+    SecureRandom    random;
+
+    /**
+     * Initialise the padder.
+     *
+     * @param random a SecureRandom if available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        if (random != null)
+        {
+            this.random = random;
+        }
+        else
+        {
+            this.random = CryptoServicesRegistrar.getSecureRandom();
+        }
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "ISO10126-2";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        byte code = (byte)(in.length - inOff);
+
+        while (inOff < (in.length - 1))
+        {
+            in[inOff] = (byte)random.nextInt();
+            inOff++;
+        }
+
+        in[inOff] = code;
+
+        return code;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        int count = in[in.length - 1] & 0xff;
+
+        if (count > in.length)
+        {
+            throw new InvalidCipherTextException("pad block corrupted");
+        }
+
+        return count;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/ISO7816d4Padding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/ISO7816d4Padding.java
new file mode 100644
index 0000000..9b20044
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/ISO7816d4Padding.java
@@ -0,0 +1,79 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds the padding according to the scheme referenced in
+ * ISO 7814-4 - scheme 2 from ISO 9797-1. The first byte is 0x80, rest is 0x00
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ISO7816d4Padding
+    implements BlockCipherPadding
+{
+    /**
+     * Initialise the padder.
+     *
+     * @param random - a SecureRandom if available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        // nothing to do.
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "ISO7816-4";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        int added = (in.length - inOff);
+
+        in [inOff]= (byte) 0x80;
+        inOff ++;
+        
+        while (inOff < in.length)
+        {
+            in[inOff] = (byte) 0;
+            inOff++;
+        }
+
+        return added;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        int count = in.length - 1;
+
+        while (count > 0 && in[count] == 0)
+        {
+            count--;
+        }
+
+        if (in[count] != (byte)0x80)
+        {
+            throw new InvalidCipherTextException("pad block corrupted");
+        }
+        
+        return in.length - count;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/PKCS7Padding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/PKCS7Padding.java
new file mode 100644
index 0000000..f96d4b8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/PKCS7Padding.java
@@ -0,0 +1,79 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds PKCS7/PKCS5 padding to a block.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS7Padding
+    implements BlockCipherPadding
+{
+    /**
+     * Initialise the padder.
+     *
+     * @param random - a SecureRandom if available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        // nothing to do.
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "PKCS7";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        byte code = (byte)(in.length - inOff);
+
+        while (inOff < in.length)
+        {
+            in[inOff] = code;
+            inOff++;
+        }
+
+        return code;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        int count = in[in.length - 1] & 0xff;
+        byte countAsbyte = (byte)count;
+
+        // constant time version
+        boolean failed = (count > in.length | count == 0);
+
+        for (int i = 0; i < in.length; i++)
+        {
+            failed |= (in.length - i <= count) & (in[i] != countAsbyte);
+        }
+
+        if (failed)
+        {
+            throw new InvalidCipherTextException("pad block corrupted");
+        }
+
+        return count;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
new file mode 100644
index 0000000..f75ef53
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
@@ -0,0 +1,301 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.paddings;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.BufferedBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+
+/**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion with padding. The PaddedBufferedBlockCipher
+ * outputs a block only when the buffer is full and more data is being added,
+ * or on a doFinal (unless the current block in the buffer is a pad block).
+ * The default padding mechanism used is the one outlined in PKCS5/PKCS7.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PaddedBufferedBlockCipher
+    extends BufferedBlockCipher
+{
+    BlockCipherPadding  padding;
+
+    /**
+     * Create a buffered block cipher with the desired padding.
+     *
+     * @param cipher the underlying block cipher this buffering object wraps.
+     * @param padding the padding type.
+     */
+    public PaddedBufferedBlockCipher(
+        BlockCipher         cipher,
+        BlockCipherPadding  padding)
+    {
+        this.cipher = cipher;
+        this.padding = padding;
+
+        buf = new byte[cipher.getBlockSize()];
+        bufOff = 0;
+    }
+
+    /**
+     * Create a buffered block cipher PKCS7 padding
+     *
+     * @param cipher the underlying block cipher this buffering object wraps.
+     */
+    public PaddedBufferedBlockCipher(
+        BlockCipher     cipher)
+    {
+        this(cipher, new PKCS7Padding());
+    }
+
+    /**
+     * initialise the cipher.
+     *
+     * @param forEncryption if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             forEncryption,
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        this.forEncryption = forEncryption;
+
+        reset();
+
+        if (params instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom    p = (ParametersWithRandom)params;
+
+            padding.init(p.getRandom());
+
+            cipher.init(forEncryption, p.getParameters());
+        }
+        else
+        {
+            padding.init(null);
+
+            cipher.init(forEncryption, params);
+        }
+    }
+
+    /**
+     * return the minimum size of the output buffer required for an update
+     * plus a doFinal with an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update and doFinal
+     * with len bytes of input.
+     */
+    public int getOutputSize(
+        int len)
+    {
+        int total       = len + bufOff;
+        int leftOver    = total % buf.length;
+
+        if (leftOver == 0)
+        {
+            if (forEncryption)
+            {
+                return total + buf.length;
+            }
+
+            return total;
+        }
+
+        return total - leftOver + buf.length;
+    }
+
+    /**
+     * return the size of the output buffer required for an update 
+     * an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update
+     * with len bytes of input.
+     */
+    public int getUpdateOutputSize(
+        int len)
+    {
+        int total       = len + bufOff;
+        int leftOver    = total % buf.length;
+
+        if (leftOver == 0)
+        {
+            return Math.max(0, total - buf.length);
+        }
+
+        return total - leftOver;
+    }
+
+    /**
+     * process a single byte, producing an output block if neccessary.
+     *
+     * @param in the input byte.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processByte(
+        byte        in,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        int         resultLen = 0;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = cipher.processBlock(buf, 0, out, outOff);
+            bufOff = 0;
+        }
+
+        buf[bufOff++] = in;
+
+        return resultLen;
+    }
+
+    /**
+     * process an array of bytes, producing output if necessary.
+     *
+     * @param in the input byte array.
+     * @param inOff the offset at which the input data starts.
+     * @param len the number of bytes to be copied out of the input array.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processBytes(
+        byte[]      in,
+        int         inOff,
+        int         len,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int blockSize   = getBlockSize();
+        int length      = getUpdateOutputSize(len);
+        
+        if (length > 0)
+        {
+            if ((outOff + length) > out.length)
+            {
+                throw new OutputLengthException("output buffer too short");
+            }
+        }
+
+        int resultLen = 0;
+        int gapLen = buf.length - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += cipher.processBlock(buf, 0, out, outOff);
+
+            bufOff = 0;
+            len -= gapLen;
+            inOff += gapLen;
+
+            while (len > buf.length)
+            {
+                resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
+
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+
+        bufOff += len;
+
+        return resultLen;
+    }
+
+    /**
+     * Process the last block in the buffer. If the buffer is currently
+     * full and padding needs to be added a call to doFinal will produce
+     * 2 * getBlockSize() bytes.
+     *
+     * @param out the array the block currently being held is copied into.
+     * @param outOff the offset at which the copying starts.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there is insufficient space in out for
+     * the output or we are decrypting and the input is not block size aligned.
+     * @exception IllegalStateException if the underlying cipher is not
+     * initialised.
+     * @exception InvalidCipherTextException if padding is expected and not found.
+     */
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+        throws DataLengthException, IllegalStateException, InvalidCipherTextException
+    {
+        int blockSize = cipher.getBlockSize();
+        int resultLen = 0;
+
+        if (forEncryption)
+        {
+            if (bufOff == blockSize)
+            {
+                if ((outOff + 2 * blockSize) > out.length)
+                {
+                    reset();
+
+                    throw new OutputLengthException("output buffer too short");
+                }
+
+                resultLen = cipher.processBlock(buf, 0, out, outOff);
+                bufOff = 0;
+            }
+
+            padding.addPadding(buf, bufOff);
+
+            resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+
+            reset();
+        }
+        else
+        {
+            if (bufOff == blockSize)
+            {
+                resultLen = cipher.processBlock(buf, 0, buf, 0);
+                bufOff = 0;
+            }
+            else
+            {
+                reset();
+
+                throw new DataLengthException("last block incomplete in decryption");
+            }
+
+            try
+            {
+                resultLen -= padding.padCount(buf);
+
+                System.arraycopy(buf, 0, out, outOff, resultLen);
+            }
+            finally
+            {
+                reset();
+            }
+        }
+
+        return resultLen;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/TBCPadding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/TBCPadding.java
new file mode 100644
index 0000000..fbaa0f3
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/TBCPadding.java
@@ -0,0 +1,91 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds Trailing-Bit-Compliment padding to a block.
+ * <p>
+ * This padding pads the block out with the compliment of the last bit
+ * of the plain text.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TBCPadding
+    implements BlockCipherPadding
+{
+    /**
+     * Initialise the padder.
+     *
+     * @param random - a SecureRandom if available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        // nothing to do.
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "TBC";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     * <p>
+     * Note: this assumes that the last block of plain text is always 
+     * passed to it inside in. i.e. if inOff is zero, indicating the
+     * entire block is to be overwritten with padding the value of in
+     * should be the same as the last block of plain text.
+     * </p>
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        int     count = in.length - inOff;
+        byte    code;
+        
+        if (inOff > 0)
+        {
+            code = (byte)((in[inOff - 1] & 0x01) == 0 ? 0xff : 0x00);
+        }
+        else
+        {
+            code = (byte)((in[in.length - 1] & 0x01) == 0 ? 0xff : 0x00);
+        }
+            
+        while (inOff < in.length)
+        {
+            in[inOff] = code;
+            inOff++;
+        }
+
+        return count;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        byte code = in[in.length - 1];
+
+        int index = in.length - 1;
+        while (index > 0 && in[index - 1] == code)
+        {
+            index--;
+        }
+
+        return in.length - index;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/X923Padding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/X923Padding.java
new file mode 100644
index 0000000..ca24e81
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/X923Padding.java
@@ -0,0 +1,82 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds X9.23 padding to a block - if a SecureRandom is
+ * passed in random padding is assumed, otherwise padding with zeros is used.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X923Padding
+    implements BlockCipherPadding
+{
+    SecureRandom    random = null;
+
+    /**
+     * Initialise the padder.
+     *
+     * @param random a SecureRandom if one is available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        this.random = random;
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "X9.23";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        byte code = (byte)(in.length - inOff);
+
+        while (inOff < in.length - 1)
+        {
+            if (random == null)
+            {
+                in[inOff] = 0;
+            }
+            else
+            {
+                in[inOff] = (byte)random.nextInt();
+            }
+            inOff++;
+        }
+
+        in[inOff] = code;
+
+        return code;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        int count = in[in.length - 1] & 0xff;
+
+        if (count > in.length)
+        {
+            throw new InvalidCipherTextException("pad block corrupted");
+        }
+
+        return count;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/ZeroBytePadding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/ZeroBytePadding.java
new file mode 100644
index 0000000..9553137
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/paddings/ZeroBytePadding.java
@@ -0,0 +1,75 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds NULL byte padding to a block.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ZeroBytePadding
+    implements BlockCipherPadding
+{
+    /**
+     * Initialise the padder.
+     *
+     * @param random - a SecureRandom if available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        // nothing to do.
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "ZeroByte";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        int added = (in.length - inOff);
+
+        while (inOff < in.length)
+        {
+            in[inOff] = (byte) 0;
+            inOff++;
+        }
+
+        return added;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        int count = in.length;
+
+        while (count > 0)
+        {
+            if (in[count - 1] != 0)
+            {
+                break;
+            }
+
+            count--;
+        }
+
+        return in.length - count;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/AEADParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/AEADParameters.java
new file mode 100644
index 0000000..9fb7190
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/AEADParameters.java
@@ -0,0 +1,65 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AEADParameters
+    implements CipherParameters
+{
+    private byte[] associatedText;
+    private byte[] nonce;
+    private KeyParameter key;
+    private int macSize;
+
+    /**
+     * Base constructor.
+     *
+     * @param key key to be used by underlying cipher
+     * @param macSize macSize in bits
+     * @param nonce nonce to be used
+     */
+   public AEADParameters(KeyParameter key, int macSize, byte[] nonce)
+    {
+       this(key, macSize, nonce, null);
+    }
+
+    /**
+     * Base constructor.
+     *
+     * @param key key to be used by underlying cipher
+     * @param macSize macSize in bits
+     * @param nonce nonce to be used
+     * @param associatedText initial associated text, if any
+     */
+    public AEADParameters(KeyParameter key, int macSize, byte[] nonce, byte[] associatedText)
+    {
+        this.key = key;
+        this.nonce = Arrays.clone(nonce);
+        this.macSize = macSize;
+        this.associatedText = Arrays.clone(associatedText);
+    }
+
+    public KeyParameter getKey()
+    {
+        return key;
+    }
+
+    public int getMacSize()
+    {
+        return macSize;
+    }
+
+    public byte[] getAssociatedText()
+    {
+        return Arrays.clone(associatedText);
+    }
+
+    public byte[] getNonce()
+    {
+        return Arrays.clone(nonce);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/AsymmetricKeyParameter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/AsymmetricKeyParameter.java
new file mode 100644
index 0000000..54a0376
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/AsymmetricKeyParameter.java
@@ -0,0 +1,24 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AsymmetricKeyParameter
+    implements CipherParameters
+{
+    boolean privateKey;
+
+    public AsymmetricKeyParameter(
+        boolean privateKey)
+    {
+        this.privateKey = privateKey;
+    }
+
+    public boolean isPrivate()
+    {
+        return privateKey;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DESParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DESParameters.java
new file mode 100644
index 0000000..b36fcfe
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DESParameters.java
@@ -0,0 +1,111 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DESParameters
+    extends KeyParameter
+{
+    public DESParameters(
+        byte[]  key)
+    {
+        super(key);
+
+        if (isWeakKey(key, 0))
+        {
+            throw new IllegalArgumentException("attempt to create weak DES key");
+        }
+    }
+
+    /*
+     * DES Key length in bytes.
+     */
+    static public final int DES_KEY_LENGTH = 8;
+
+    /*
+     * Table of weak and semi-weak keys taken from Schneier pp281
+     */
+    static private final int N_DES_WEAK_KEYS = 16;
+
+    static private byte[] DES_weak_keys =
+    {
+        /* weak keys */
+        (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01,
+        (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)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe,
+
+        /* semi-weak keys */
+        (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
+    };
+
+    /**
+     * DES has 16 weak keys.  This method will check
+     * if the given DES key material is weak or semi-weak.
+     * Key material that is too short is regarded as weak.
+     * <p>
+     * See <a href="http://www.counterpane.com/applied.html">"Applied
+     * Cryptography"</a> by Bruce Schneier for more information.
+     *
+     * @return true if the given DES key material is weak or semi-weak,
+     *     false otherwise.
+     */
+    public static boolean isWeakKey(
+        byte[] key,
+        int offset)
+    {
+        if (key.length - offset < DES_KEY_LENGTH)
+        {
+            throw new IllegalArgumentException("key material too short.");
+        }
+
+        nextkey: for (int i = 0; i < N_DES_WEAK_KEYS; i++)
+        {
+            for (int j = 0; j < DES_KEY_LENGTH; j++)
+            {
+                if (key[j + offset] != DES_weak_keys[i * DES_KEY_LENGTH + j])
+                {
+                    continue nextkey;
+                }
+            }
+
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * DES Keys use the LSB as the odd parity bit.  This can
+     * be used to check for corrupt keys.
+     *
+     * @param bytes the byte array to set the parity on.
+     */
+    public static void setOddParity(
+        byte[] bytes)
+    {
+        for (int i = 0; i < bytes.length; i++)
+        {
+            int b = bytes[i];
+            bytes[i] = (byte)((b & 0xfe) |
+                            ((((b >> 1) ^
+                            (b >> 2) ^
+                            (b >> 3) ^
+                            (b >> 4) ^
+                            (b >> 5) ^
+                            (b >> 6) ^
+                            (b >> 7)) ^ 0x01) & 0x01));
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DESedeParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DESedeParameters.java
new file mode 100644
index 0000000..1409b88
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DESedeParameters.java
@@ -0,0 +1,110 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DESedeParameters
+    extends DESParameters
+{
+    /*
+     * DES-EDE Key length in bytes.
+     */
+    static public final int DES_EDE_KEY_LENGTH = 24;
+
+    public DESedeParameters(
+        byte[]  key)
+    {
+        super(key);
+
+        if (isWeakKey(key, 0, key.length))
+        {
+            throw new IllegalArgumentException("attempt to create weak DESede key");
+        }
+    }
+
+    /**
+     * return true if the passed in key is a DES-EDE weak key.
+     *
+     * @param key bytes making up the key
+     * @param offset offset into the byte array the key starts at
+     * @param length number of bytes making up the key
+     */
+    public static boolean isWeakKey(
+        byte[]  key,
+        int     offset,
+        int     length)
+    {
+        for (int i = offset; i < length; i += DES_KEY_LENGTH)
+        {
+            if (DESParameters.isWeakKey(key, i))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * return true if the passed in key is a DES-EDE weak key.
+     *
+     * @param key bytes making up the key
+     * @param offset offset into the byte array the key starts at
+     */
+    public static boolean isWeakKey(
+        byte[]  key,
+        int     offset)
+    {
+        return isWeakKey(key, offset, key.length - offset);
+    }
+
+    /**
+     * return true if the passed in key is a real 2/3 part DES-EDE key.
+     *
+     * @param key bytes making up the key
+     * @param offset offset into the byte array the key starts at
+     */
+    public static boolean isRealEDEKey(byte[] key, int offset)
+    {
+        return key.length == 16 ? isReal2Key(key, offset) : isReal3Key(key, offset);
+    }
+
+    /**
+     * return true if the passed in key is a real 2 part DES-EDE key.
+     *
+     * @param key bytes making up the key
+     * @param offset offset into the byte array the key starts at
+     */
+    public static boolean isReal2Key(byte[] key, int offset)
+    {
+        boolean isValid = false;
+        for (int i = offset; i != offset + 8; i++)
+        {
+            if (key[i] != key[i + 8])
+            {
+                isValid = true;
+            }
+        }
+
+        return isValid;
+    }
+
+    /**
+     * return true if the passed in key is a real 3 part DES-EDE key.
+     *
+     * @param key bytes making up the key
+     * @param offset offset into the byte array the key starts at
+     */
+    public static boolean isReal3Key(byte[] key, int offset)
+    {
+        boolean diff12 = false, diff13 = false, diff23 = false;
+        for (int i = offset; i != offset + 8; i++)
+        {
+            diff12 |= (key[i] != key[i + 8]);
+            diff13 |= (key[i] != key[i + 16]);
+            diff23 |= (key[i + 8] != key[i + 16]);
+        }
+        return diff12 && diff13 && diff23;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHKeyGenerationParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHKeyGenerationParameters.java
new file mode 100644
index 0000000..3e206fe
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHKeyGenerationParameters.java
@@ -0,0 +1,34 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHKeyGenerationParameters
+    extends KeyGenerationParameters
+{
+    private DHParameters    params;
+
+    public DHKeyGenerationParameters(
+        SecureRandom    random,
+        DHParameters    params)
+    {
+        super(random, getStrength(params));
+
+        this.params = params;
+    }
+
+    public DHParameters getParameters()
+    {
+        return params;
+    }
+
+    static int getStrength(DHParameters params)
+    {
+        return params.getL() != 0 ? params.getL() : params.getP().bitLength();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHKeyParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHKeyParameters.java
new file mode 100644
index 0000000..133e166
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHKeyParameters.java
@@ -0,0 +1,58 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHKeyParameters
+    extends AsymmetricKeyParameter
+{
+    private DHParameters    params;
+
+    protected DHKeyParameters(
+        boolean         isPrivate,
+        DHParameters    params)
+    {
+        super(isPrivate);
+
+        this.params = params;
+    }   
+
+    public DHParameters getParameters()
+    {
+        return params;
+    }
+
+    public boolean equals(
+        Object  obj)
+    {
+        if (!(obj instanceof DHKeyParameters))
+        {
+            return false;
+        }
+
+        DHKeyParameters    dhKey = (DHKeyParameters)obj;
+
+        if (params == null)
+        {
+            return dhKey.getParameters() == null;
+        }
+        else
+        { 
+            return params.equals(dhKey.getParameters());
+        }
+    }
+    
+    public int hashCode()
+    {
+        int code = isPrivate() ? 0 : 1;
+        
+        if (params != null)
+        {
+            code ^= params.hashCode();
+        }
+        
+        return code;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHParameters.java
new file mode 100644
index 0000000..159a0df
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHParameters.java
@@ -0,0 +1,197 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHParameters
+    implements CipherParameters
+{
+    private static final int DEFAULT_MINIMUM_LENGTH = 160;
+
+    // not final due to compiler bug in "simpler" JDKs
+    private BigInteger              g;
+    private BigInteger              p;
+    private BigInteger              q;
+    private BigInteger              j;
+    private int                     m;
+    private int                     l;
+    private DHValidationParameters  validation;
+
+    private static int getDefaultMParam(
+        int lParam)
+    {
+        if (lParam == 0)
+        {
+            return DEFAULT_MINIMUM_LENGTH;
+        }
+
+        return lParam < DEFAULT_MINIMUM_LENGTH ? lParam : DEFAULT_MINIMUM_LENGTH;
+    }
+
+    public DHParameters(
+        BigInteger  p,
+        BigInteger  g)
+    {
+        this(p, g, null, 0);
+    }
+
+    public DHParameters(
+        BigInteger  p,
+        BigInteger  g,
+        BigInteger  q)
+    {
+        this(p, g, q, 0);
+    }
+
+    public DHParameters(
+        BigInteger  p,
+        BigInteger  g,
+        BigInteger  q,
+        int         l)
+    {
+        this(p, g, q, getDefaultMParam(l), l, null, null);
+    }
+
+    public DHParameters(
+        BigInteger  p,
+        BigInteger  g,
+        BigInteger  q,
+        int         m,
+        int         l)
+    {
+        this(p, g, q, m, l, null, null);
+    }
+
+    public DHParameters(
+        BigInteger              p,
+        BigInteger              g,
+        BigInteger              q,
+        BigInteger              j,
+        DHValidationParameters  validation)
+    {
+        this(p, g, q, DEFAULT_MINIMUM_LENGTH, 0, j, validation);
+    }
+
+    public DHParameters(
+        BigInteger              p,
+        BigInteger              g,
+        BigInteger              q,
+        int                     m,
+        int                     l,
+        BigInteger              j,
+        DHValidationParameters  validation)
+    {
+        if (l != 0)
+        {
+            if (l > p.bitLength())
+            {
+                throw new IllegalArgumentException("when l value specified, it must satisfy 2^(l-1) <= p");
+            }
+            if (l < m)
+            {
+                throw new IllegalArgumentException("when l value specified, it may not be less than m value");
+            }
+        }
+
+        if (m > p.bitLength())
+        {
+            throw new IllegalArgumentException("unsafe p value so small specific l required");
+        }
+
+        this.g = g;
+        this.p = p;
+        this.q = q;
+        this.m = m;
+        this.l = l;
+        this.j = j;
+        this.validation = validation;
+    }
+
+    public BigInteger getP()
+    {
+        return p;
+    }
+
+    public BigInteger getG()
+    {
+        return g;
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    /**
+     * Return the subgroup factor J.
+     *
+     * @return subgroup factor
+     */
+    public BigInteger getJ()
+    {
+        return j;
+    }
+
+    /**
+     * Return the minimum length of the private value.
+     *
+     * @return the minimum length of the private value in bits.
+     */
+    public int getM()
+    {
+        return m;
+    }
+
+    /**
+     * Return the private value length in bits - if set, zero otherwise
+     *
+     * @return the private value length in bits, zero otherwise.
+     */
+    public int getL()
+    {
+        return l;
+    }
+
+    public DHValidationParameters getValidationParameters()
+    {
+        return validation;
+    }
+
+    public boolean equals(
+        Object  obj)
+    {
+        if (!(obj instanceof DHParameters))
+        {
+            return false;
+        }
+
+        DHParameters    pm = (DHParameters)obj;
+
+        if (this.getQ() != null)
+        {
+            if (!this.getQ().equals(pm.getQ()))
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if (pm.getQ() != null)
+            {
+                return false;
+            }
+        }
+
+        return pm.getP().equals(p) && pm.getG().equals(g);
+    }
+    
+    public int hashCode()
+    {
+        return getP().hashCode() ^ getG().hashCode() ^ (getQ() != null ? getQ().hashCode() : 0);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHPrivateKeyParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHPrivateKeyParameters.java
new file mode 100644
index 0000000..9837e77
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHPrivateKeyParameters.java
@@ -0,0 +1,45 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHPrivateKeyParameters
+    extends DHKeyParameters
+{
+    private BigInteger      x;
+
+    public DHPrivateKeyParameters(
+        BigInteger      x,
+        DHParameters    params)
+    {
+        super(true, params);
+
+        this.x = x;
+    }   
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+
+    public int hashCode()
+    {
+        return x.hashCode() ^ super.hashCode();
+    }
+    
+    public boolean equals(
+        Object  obj)
+    {
+        if (!(obj instanceof DHPrivateKeyParameters))
+        {
+            return false;
+        }
+
+        DHPrivateKeyParameters  other = (DHPrivateKeyParameters)obj;
+
+        return other.getX().equals(this.x) && super.equals(obj);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHPublicKeyParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHPublicKeyParameters.java
new file mode 100644
index 0000000..e9d5a96
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHPublicKeyParameters.java
@@ -0,0 +1,76 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHPublicKeyParameters
+    extends DHKeyParameters
+{
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+    private static final BigInteger TWO = BigInteger.valueOf(2);
+
+    private BigInteger      y;
+
+    public DHPublicKeyParameters(
+        BigInteger      y,
+        DHParameters    params)
+    {
+        super(false, params);
+
+        this.y = validate(y, params);
+    }   
+
+    private BigInteger validate(BigInteger y, DHParameters dhParams)
+    {
+        if (y == null)
+        {
+            throw new NullPointerException("y value cannot be null");
+        }
+
+        // TLS check
+        if (y.compareTo(TWO) < 0 || y.compareTo(dhParams.getP().subtract(TWO)) > 0)
+        {
+            throw new IllegalArgumentException("invalid DH public key");
+        }
+
+        if (dhParams.getQ() != null)
+        {
+            if (ONE.equals(y.modPow(dhParams.getQ(), dhParams.getP())))
+            {
+                return y;
+            }
+
+            throw new IllegalArgumentException("Y value does not appear to be in correct group");
+        }
+        else
+        {
+            return y;         // we can't validate without Q.
+        }
+    }
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+
+    public int hashCode()
+    {
+        return y.hashCode() ^ super.hashCode();
+    }
+
+    public boolean equals(
+        Object  obj)
+    {
+        if (!(obj instanceof DHPublicKeyParameters))
+        {
+            return false;
+        }
+
+        DHPublicKeyParameters   other = (DHPublicKeyParameters)obj;
+
+        return other.getY().equals(y) && super.equals(obj);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHValidationParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHValidationParameters.java
new file mode 100644
index 0000000..86ac87c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DHValidationParameters.java
@@ -0,0 +1,54 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHValidationParameters
+{
+    private byte[]  seed;
+    private int     counter;
+
+    public DHValidationParameters(
+        byte[]  seed,
+        int     counter)
+    {
+        this.seed = Arrays.clone(seed);
+        this.counter = counter;
+    }
+
+    public int getCounter()
+    {
+        return counter;
+    }
+
+    public byte[] getSeed()
+    {
+        return Arrays.clone(seed);
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DHValidationParameters))
+        {
+            return false;
+        }
+
+        DHValidationParameters  other = (DHValidationParameters)o;
+
+        if (other.counter != this.counter)
+        {
+            return false;
+        }
+
+        return Arrays.areEqual(this.seed, other.seed);
+    }
+
+    public int hashCode()
+    {
+        return counter ^ Arrays.hashCode(seed);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAKeyGenerationParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAKeyGenerationParameters.java
new file mode 100644
index 0000000..ca6e830
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAKeyGenerationParameters.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSAKeyGenerationParameters
+    extends KeyGenerationParameters
+{
+    private DSAParameters    params;
+
+    public DSAKeyGenerationParameters(
+        SecureRandom    random,
+        DSAParameters   params)
+    {
+        super(random, params.getP().bitLength() - 1);
+
+        this.params = params;
+    }
+
+    public DSAParameters getParameters()
+    {
+        return params;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAKeyParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAKeyParameters.java
new file mode 100644
index 0000000..102a8ce
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAKeyParameters.java
@@ -0,0 +1,25 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSAKeyParameters
+    extends AsymmetricKeyParameter
+{
+    private DSAParameters    params;
+
+    public DSAKeyParameters(
+        boolean         isPrivate,
+        DSAParameters   params)
+    {
+        super(isPrivate);
+
+        this.params = params;
+    }   
+
+    public DSAParameters getParameters()
+    {
+        return params;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAParameterGenerationParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAParameterGenerationParameters.java
new file mode 100644
index 0000000..d393c3f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAParameterGenerationParameters.java
@@ -0,0 +1,84 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSAParameterGenerationParameters
+{
+    public static final int DIGITAL_SIGNATURE_USAGE = 1;
+    public static final int KEY_ESTABLISHMENT_USAGE = 2;
+
+    private final int l;
+    private final int n;
+    private final int usageIndex;
+    private final int certainty;
+    private final SecureRandom random;
+
+    /**
+     * Construct without a usage index, this will do a random construction of G.
+     *
+     * @param L desired length of prime P in bits (the effective key size).
+     * @param N desired length of prime Q in bits.
+     * @param certainty certainty level for prime number generation.
+     * @param random the source of randomness to use.
+     */
+    public DSAParameterGenerationParameters(
+        int L,
+        int N,
+        int certainty,
+        SecureRandom random)
+    {
+        this(L, N, certainty, random, -1);
+    }
+
+    /**
+     * Construct for a specific usage index - this has the effect of using verifiable canonical generation of G.
+     *
+     * @param L desired length of prime P in bits (the effective key size).
+     * @param N desired length of prime Q in bits.
+     * @param certainty certainty level for prime number generation.
+     * @param random the source of randomness to use.
+     * @param usageIndex a valid usage index.
+     */
+    public DSAParameterGenerationParameters(
+        int L,
+        int N,
+        int certainty,
+        SecureRandom random,
+        int usageIndex)
+    {
+        this.l = L;
+        this.n = N;
+        this.certainty = certainty;
+        this.usageIndex = usageIndex;
+        this.random = random;
+    }
+
+    public int getL()
+    {
+        return l;
+    }
+
+    public int getN()
+    {
+        return n;
+    }
+
+    public int getCertainty()
+    {
+        return certainty;
+    }
+
+    public SecureRandom getRandom()
+    {
+        return random;
+    }
+
+    public int getUsageIndex()
+    {
+        return usageIndex;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAParameters.java
new file mode 100644
index 0000000..a94bcf3
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAParameters.java
@@ -0,0 +1,78 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSAParameters
+    implements CipherParameters
+{
+    private BigInteger              g;
+    private BigInteger              q;
+    private BigInteger              p;
+    private DSAValidationParameters validation;
+
+    public DSAParameters(
+        BigInteger  p,
+        BigInteger  q,
+        BigInteger  g)
+    {
+        this.g = g;
+        this.p = p;
+        this.q = q;
+    }   
+
+    public DSAParameters(
+        BigInteger              p,
+        BigInteger              q,
+        BigInteger              g,
+        DSAValidationParameters params)
+    {
+        this.g = g;
+        this.p = p;
+        this.q = q;
+        this.validation = params;
+    }   
+
+    public BigInteger getP()
+    {
+        return p;
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public BigInteger getG()
+    {
+        return g;
+    }
+
+    public DSAValidationParameters getValidationParameters()
+    {
+        return validation;
+    }
+
+    public boolean equals(
+        Object  obj)
+    {
+        if (!(obj instanceof DSAParameters))
+        {
+            return false;
+        }
+
+        DSAParameters    pm = (DSAParameters)obj;
+
+        return (pm.getP().equals(p) && pm.getQ().equals(q) && pm.getG().equals(g));
+    }
+    
+    public int hashCode()
+    {
+        return getP().hashCode() ^ getQ().hashCode() ^ getG().hashCode();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAPrivateKeyParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAPrivateKeyParameters.java
new file mode 100644
index 0000000..c4438e3
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAPrivateKeyParameters.java
@@ -0,0 +1,27 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSAPrivateKeyParameters
+    extends DSAKeyParameters
+{
+    private BigInteger      x;
+
+    public DSAPrivateKeyParameters(
+        BigInteger      x,
+        DSAParameters   params)
+    {
+        super(true, params);
+
+        this.x = x;
+    }   
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java
new file mode 100644
index 0000000..868c39b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java
@@ -0,0 +1,48 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSAPublicKeyParameters
+    extends DSAKeyParameters
+{
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+    private static final BigInteger TWO = BigInteger.valueOf(2);
+
+    private BigInteger      y;
+
+    public DSAPublicKeyParameters(
+        BigInteger      y,
+        DSAParameters   params)
+    {
+        super(false, params);
+
+        this.y = validate(y, params);
+    }   
+
+    private BigInteger validate(BigInteger y, DSAParameters params)
+    {
+        if (params != null)
+        {
+            if (TWO.compareTo(y) <= 0 && params.getP().subtract(TWO).compareTo(y) >= 0
+                && ONE.equals(y.modPow(params.getQ(), params.getP())))
+            {
+                return y;
+            }
+
+            throw new IllegalArgumentException("y value does not appear to be in correct group");
+        }
+        else
+        {
+            return y;         // we can't validate without params, fortunately we can't use the key either...
+        }
+    }
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAValidationParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAValidationParameters.java
new file mode 100644
index 0000000..120302b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/DSAValidationParameters.java
@@ -0,0 +1,69 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSAValidationParameters
+{
+    private int usageIndex;
+    private byte[]  seed;
+    private int     counter;
+
+    public DSAValidationParameters(
+        byte[]  seed,
+        int     counter)
+    {
+        this(seed, counter, -1);
+    }
+
+    public DSAValidationParameters(
+        byte[]  seed,
+        int     counter,
+        int     usageIndex)
+    {
+        this.seed = Arrays.clone(seed);
+        this.counter = counter;
+        this.usageIndex = usageIndex;
+    }
+
+    public int getCounter()
+    {
+        return counter;
+    }
+
+    public byte[] getSeed()
+    {
+        return Arrays.clone(seed);
+    }
+
+    public int getUsageIndex()
+    {
+        return usageIndex;
+    }
+
+    public int hashCode()
+    {
+        return counter ^ Arrays.hashCode(seed);
+    }
+    
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DSAValidationParameters))
+        {
+            return false;
+        }
+
+        DSAValidationParameters  other = (DSAValidationParameters)o;
+
+        if (other.counter != this.counter)
+        {
+            return false;
+        }
+
+        return Arrays.areEqual(this.seed, other.seed);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECDomainParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECDomainParameters.java
new file mode 100644
index 0000000..c782c98
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECDomainParameters.java
@@ -0,0 +1,151 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECAlgorithms;
+import com.android.internal.org.bouncycastle.math.ec.ECConstants;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECDomainParameters
+    implements ECConstants
+{
+    private ECCurve     curve;
+    private byte[]      seed;
+    private ECPoint     G;
+    private BigInteger  n;
+    private BigInteger  h;
+    private BigInteger  hInv = null;
+
+    public ECDomainParameters(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n)
+    {
+        this(curve, G, n, ONE, null);
+    }
+
+    public ECDomainParameters(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h)
+    {
+        this(curve, G, n, h, null);
+    }
+
+    public ECDomainParameters(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h,
+        byte[]      seed)
+    {
+        if (curve == null)
+        {
+            throw new NullPointerException("curve");
+        }
+        if (n == null)
+        {
+            throw new NullPointerException("n");
+        }
+        // we can't check for h == null here as h is optional in X9.62 as it is not required for ECDSA
+
+        this.curve = curve;
+        this.G = validate(curve, G);
+        this.n = n;
+        this.h = h;
+        this.seed = Arrays.clone(seed);
+    }
+
+    public ECCurve getCurve()
+    {
+        return curve;
+    }
+
+    public ECPoint getG()
+    {
+        return G;
+    }
+
+    public BigInteger getN()
+    {
+        return n;
+    }
+
+    public BigInteger getH()
+    {
+        return h;
+    }
+
+    public synchronized BigInteger getHInv()
+    {
+        if (hInv == null)
+        {
+            hInv = h.modInverse(n);
+        }
+        return hInv;
+    }
+
+    public byte[] getSeed()
+    {
+        return Arrays.clone(seed);
+    }
+
+    public boolean equals(
+        Object  obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+
+        if ((obj instanceof ECDomainParameters))
+        {
+            ECDomainParameters other = (ECDomainParameters)obj;
+
+            return this.curve.equals(other.curve) && this.G.equals(other.G) && this.n.equals(other.n) && this.h.equals(other.h);
+        }
+
+        return false;
+    }
+
+    public int hashCode()
+    {
+        int hc = curve.hashCode();
+        hc *= 37;
+        hc ^= G.hashCode();
+        hc *= 37;
+        hc ^= n.hashCode();
+        hc *= 37;
+        hc ^= h.hashCode();
+        return hc;
+    }
+
+    static ECPoint validate(ECCurve c, ECPoint q)
+    {
+        if (q == null)
+        {
+            throw new IllegalArgumentException("Point has null value");
+        }
+
+        q = ECAlgorithms.importPoint(c, q).normalize();
+
+        if (q.isInfinity())
+        {
+            throw new IllegalArgumentException("Point at infinity");
+        }
+
+        if (!q.isValid())
+        {
+            throw new IllegalArgumentException("Point not on curve");
+        }
+
+        return q;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECKeyGenerationParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECKeyGenerationParameters.java
new file mode 100644
index 0000000..fca2c57
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECKeyGenerationParameters.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECKeyGenerationParameters
+    extends KeyGenerationParameters
+{
+    private ECDomainParameters  domainParams;
+
+    public ECKeyGenerationParameters(
+        ECDomainParameters      domainParams,
+        SecureRandom            random)
+    {
+        super(random, domainParams.getN().bitLength());
+
+        this.domainParams = domainParams;
+    }
+
+    public ECDomainParameters getDomainParameters()
+    {
+        return domainParams;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECKeyParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECKeyParameters.java
new file mode 100644
index 0000000..d62e8cf
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECKeyParameters.java
@@ -0,0 +1,25 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECKeyParameters
+    extends AsymmetricKeyParameter
+{
+    ECDomainParameters params;
+
+    protected ECKeyParameters(
+        boolean             isPrivate,
+        ECDomainParameters  params)
+    {
+        super(isPrivate);
+
+        this.params = params;
+    }
+
+    public ECDomainParameters getParameters()
+    {
+        return params;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECNamedDomainParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECNamedDomainParameters.java
new file mode 100644
index 0000000..85055ae
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECNamedDomainParameters.java
@@ -0,0 +1,46 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.math.ec.ECConstants;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECNamedDomainParameters
+    extends ECDomainParameters
+{
+    private ASN1ObjectIdentifier name;
+
+    public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n)
+    {
+        this(name, curve, G, n, ECConstants.ONE, null);
+    }
+
+    public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n, BigInteger h)
+    {
+        this(name, curve, G, n, h, null);
+    }
+
+    public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n, BigInteger h, byte[] seed)
+    {
+        super(curve, G, n, h, seed);
+
+        this.name = name;
+    }
+
+    public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECDomainParameters domainParameters)
+    {
+        super(domainParameters.getCurve(), domainParameters.getG(), domainParameters.getN(), domainParameters.getH(), domainParameters.getSeed());
+        this.name = name;
+    }
+
+    public ASN1ObjectIdentifier getName()
+    {
+        return name;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java
new file mode 100644
index 0000000..ae4ff8b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java
@@ -0,0 +1,26 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECPrivateKeyParameters
+    extends ECKeyParameters
+{
+    BigInteger d;
+
+    public ECPrivateKeyParameters(
+        BigInteger          d,
+        ECDomainParameters  params)
+    {
+        super(true, params);
+        this.d = d;
+    }
+
+    public BigInteger getD()
+    {
+        return d;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECPublicKeyParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
new file mode 100644
index 0000000..7b3321b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
@@ -0,0 +1,27 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECPublicKeyParameters
+    extends ECKeyParameters
+{
+    private final ECPoint Q;
+
+    public ECPublicKeyParameters(
+        ECPoint             Q,
+        ECDomainParameters  params)
+    {
+        super(false, params);
+
+        this.Q = ECDomainParameters.validate(params.getCurve(), Q);
+    }
+
+    public ECPoint getQ()
+    {
+        return Q;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/KDFParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/KDFParameters.java
new file mode 100644
index 0000000..dc76393
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/KDFParameters.java
@@ -0,0 +1,33 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import com.android.internal.org.bouncycastle.crypto.DerivationParameters;
+
+/**
+ * parameters for Key derivation functions for IEEE P1363a
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KDFParameters
+    implements DerivationParameters
+{
+    byte[]  iv;
+    byte[]  shared;
+
+    public KDFParameters(
+        byte[]  shared,
+        byte[]  iv)
+    {
+        this.shared = shared;
+        this.iv = iv;
+    }
+
+    public byte[] getSharedSecret()
+    {
+        return shared;
+    }
+
+    public byte[] getIV()
+    {
+        return iv;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/KeyParameter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/KeyParameter.java
new file mode 100644
index 0000000..210e7d6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/KeyParameter.java
@@ -0,0 +1,34 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyParameter
+    implements CipherParameters
+{
+    private byte[]  key;
+
+    public KeyParameter(
+        byte[]  key)
+    {
+        this(key, 0, key.length);
+    }
+
+    public KeyParameter(
+        byte[]  key,
+        int     keyOff,
+        int     keyLen)
+    {
+        this.key = new byte[keyLen];
+
+        System.arraycopy(key, keyOff, this.key, 0, keyLen);
+    }
+
+    public byte[] getKey()
+    {
+        return key;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ParametersWithID.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ParametersWithID.java
new file mode 100644
index 0000000..7ee3556
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ParametersWithID.java
@@ -0,0 +1,32 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ParametersWithID
+    implements CipherParameters
+{
+    private CipherParameters  parameters;
+    private byte[] id;
+
+    public ParametersWithID(
+        CipherParameters parameters,
+        byte[] id)
+    {
+        this.parameters = parameters;
+        this.id = id;
+    }
+
+    public byte[] getID()
+    {
+        return id;
+    }
+
+    public CipherParameters getParameters()
+    {
+        return parameters;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ParametersWithIV.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ParametersWithIV.java
new file mode 100644
index 0000000..7992100
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ParametersWithIV.java
@@ -0,0 +1,43 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ParametersWithIV
+    implements CipherParameters
+{
+    private byte[]              iv;
+    private CipherParameters    parameters;
+
+    public ParametersWithIV(
+        CipherParameters    parameters,
+        byte[]              iv)
+    {
+        this(parameters, iv, 0, iv.length);
+    }
+
+    public ParametersWithIV(
+        CipherParameters    parameters,
+        byte[]              iv,
+        int                 ivOff,
+        int                 ivLen)
+    {
+        this.iv = new byte[ivLen];
+        this.parameters = parameters;
+
+        System.arraycopy(iv, ivOff, this.iv, 0, ivLen);
+    }
+
+    public byte[] getIV()
+    {
+        return iv;
+    }
+
+    public CipherParameters getParameters()
+    {
+        return parameters;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ParametersWithRandom.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ParametersWithRandom.java
new file mode 100644
index 0000000..1f8e869
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/ParametersWithRandom.java
@@ -0,0 +1,41 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ParametersWithRandom
+    implements CipherParameters
+{
+    private SecureRandom        random;
+    private CipherParameters    parameters;
+
+    public ParametersWithRandom(
+        CipherParameters    parameters,
+        SecureRandom        random)
+    {
+        this.random = random;
+        this.parameters = parameters;
+    }
+
+    public ParametersWithRandom(
+        CipherParameters    parameters)
+    {
+        this(parameters, CryptoServicesRegistrar.getSecureRandom());
+    }
+
+    public SecureRandom getRandom()
+    {
+        return random;
+    }
+
+    public CipherParameters getParameters()
+    {
+        return parameters;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RC2Parameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RC2Parameters.java
new file mode 100644
index 0000000..b1bf166
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RC2Parameters.java
@@ -0,0 +1,30 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RC2Parameters
+    extends KeyParameter
+{
+    private int     bits;
+
+    public RC2Parameters(
+        byte[]  key)
+    {
+        this(key, (key.length > 128) ? 1024 : (key.length * 8));
+    }
+
+    public RC2Parameters(
+        byte[]  key,
+        int     bits)
+    {
+        super(key);
+        this.bits = bits;
+    }
+
+    public int getEffectiveKeyBits()
+    {
+        return bits;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RSAKeyGenerationParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RSAKeyGenerationParameters.java
new file mode 100644
index 0000000..30d1179
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RSAKeyGenerationParameters.java
@@ -0,0 +1,52 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSAKeyGenerationParameters
+    extends KeyGenerationParameters
+{
+    private BigInteger publicExponent;
+    private int certainty;
+
+    public RSAKeyGenerationParameters(
+        BigInteger      publicExponent,
+        SecureRandom    random,
+        int             strength,
+        int             certainty)
+    {
+        super(random, strength);
+
+        if (strength < 12)
+        {
+            throw new IllegalArgumentException("key strength too small");
+        }
+
+        //
+        // public exponent cannot be even
+        //
+        if (!publicExponent.testBit(0)) 
+        {
+                throw new IllegalArgumentException("public exponent cannot be even");
+        }
+        
+        this.publicExponent = publicExponent;
+        this.certainty = certainty;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    public int getCertainty()
+    {
+        return certainty;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RSAKeyParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RSAKeyParameters.java
new file mode 100644
index 0000000..e90097b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RSAKeyParameters.java
@@ -0,0 +1,67 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSAKeyParameters
+    extends AsymmetricKeyParameter
+{
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+
+    private BigInteger      modulus;
+    private BigInteger      exponent;
+
+    public RSAKeyParameters(
+        boolean     isPrivate,
+        BigInteger  modulus,
+        BigInteger  exponent)
+    {
+        super(isPrivate);
+
+        if (!isPrivate)
+        {
+            if ((exponent.intValue() & 1) == 0)
+            {
+                throw new IllegalArgumentException("RSA publicExponent is even");
+            }
+        }
+
+        this.modulus = validate(modulus);
+        this.exponent = exponent;
+    }   
+
+    private BigInteger validate(BigInteger modulus)
+    {
+        if ((modulus.intValue() & 1) == 0)
+        {
+            throw new IllegalArgumentException("RSA modulus is even");
+        }
+
+        // the value is the product of the 132 smallest primes from 3 to 751
+        if (!modulus.gcd(new BigInteger("145188775577763990151158743208307020242261438098488931355057091965" +
+            "931517706595657435907891265414916764399268423699130577757433083166" +
+            "651158914570105971074227669275788291575622090199821297575654322355" +
+            "049043101306108213104080801056529374892690144291505781966373045481" +
+            "8359472391642885328171302299245556663073719855")).equals(ONE))
+        {
+            throw new IllegalArgumentException("RSA modulus has a small prime factor");
+        }
+
+        // TODO: add additional primePower/Composite test - expensive!!
+
+        return modulus;
+    }
+
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getExponent()
+    {
+        return exponent;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RSAPrivateCrtKeyParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RSAPrivateCrtKeyParameters.java
new file mode 100644
index 0000000..1fc5f05
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/params/RSAPrivateCrtKeyParameters.java
@@ -0,0 +1,71 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSAPrivateCrtKeyParameters
+    extends RSAKeyParameters
+{
+    private BigInteger  e;
+    private BigInteger  p;
+    private BigInteger  q;
+    private BigInteger  dP;
+    private BigInteger  dQ;
+    private BigInteger  qInv;
+
+    /**
+     * 
+     */
+    public RSAPrivateCrtKeyParameters(
+        BigInteger  modulus,
+        BigInteger  publicExponent,
+        BigInteger  privateExponent,
+        BigInteger  p,
+        BigInteger  q,
+        BigInteger  dP,
+        BigInteger  dQ,
+        BigInteger  qInv)
+    {
+        super(true, modulus, privateExponent);
+
+        this.e = publicExponent;
+        this.p = p;
+        this.q = q;
+        this.dP = dP;
+        this.dQ = dQ;
+        this.qInv = qInv;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return e;
+    }
+
+    public BigInteger getP()
+    {
+        return p;
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public BigInteger getDP()
+    {
+        return dP;
+    }
+
+    public BigInteger getDQ()
+    {
+        return dQ;
+    }
+
+    public BigInteger getQInv()
+    {
+        return qInv;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/DSAEncoding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/DSAEncoding.java
new file mode 100644
index 0000000..1e5c586
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/DSAEncoding.java
@@ -0,0 +1,33 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.signers;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+/**
+ * An interface for different encoding formats for DSA signatures.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface DSAEncoding
+{
+    /**
+     * Decode the (r, s) pair of a DSA signature.
+     * 
+     * @param n the order of the group that r, s belong to.
+     * @param encoding an encoding of the (r, s) pair of a DSA signature.
+     * @return the (r, s) of a DSA signature, stored in an array of exactly two elements, r followed by s.
+     * @throws IOException
+     */
+    BigInteger[] decode(BigInteger n, byte[] encoding) throws IOException;
+
+    /**
+     * Encode the (r, s) pair of a DSA signature.
+     * 
+     * @param n the order of the group that r, s belong to.
+     * @param r the r value of a DSA signature.
+     * @param s the s value of a DSA signature.
+     * @return an encoding of the DSA signature given by the provided (r, s) pair.
+     * @throws IOException
+     */
+    byte[] encode(BigInteger n, BigInteger r, BigInteger s) throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/DSAKCalculator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/DSAKCalculator.java
new file mode 100644
index 0000000..cb4ed06
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/DSAKCalculator.java
@@ -0,0 +1,43 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.signers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * Interface define calculators of K values for DSA/ECDSA.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface DSAKCalculator
+{
+    /**
+     * Return true if this calculator is deterministic, false otherwise.
+     *
+     * @return true if deterministic, otherwise false.
+     */
+    boolean isDeterministic();
+
+    /**
+     * Non-deterministic initialiser.
+     *
+     * @param n the order of the DSA group.
+     * @param random a source of randomness.
+     */
+    void init(BigInteger n, SecureRandom random);
+
+    /**
+     * Deterministic initialiser.
+     *
+     * @param n the order of the DSA group.
+     * @param d the DSA private value.
+     * @param message the message being signed.
+     */
+    void init(BigInteger n, BigInteger d, byte[] message);
+
+    /**
+     * Return the next valid value of K.
+     *
+     * @return a K value.
+     */
+    BigInteger nextK();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/DSASigner.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/DSASigner.java
new file mode 100644
index 0000000..1594f2c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/DSASigner.java
@@ -0,0 +1,184 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.signers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.DSAExt;
+import com.android.internal.org.bouncycastle.crypto.params.DSAKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * The Digital Signature Algorithm - as described in "Handbook of Applied
+ * Cryptography", pages 452 - 453.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSASigner
+    implements DSAExt
+{
+    private final DSAKCalculator kCalculator;
+
+    private DSAKeyParameters key;
+    private SecureRandom    random;
+
+    /**
+     * Default configuration, random K values.
+     */
+    public DSASigner()
+    {
+        this.kCalculator = new RandomDSAKCalculator();
+    }
+
+    /**
+     * Configuration with an alternate, possibly deterministic calculator of K.
+     *
+     * @param kCalculator a K value calculator.
+     */
+    public DSASigner(DSAKCalculator kCalculator)
+    {
+        this.kCalculator = kCalculator;
+    }
+
+    public void init(
+        boolean                 forSigning,
+        CipherParameters        param)
+    {
+        SecureRandom providedRandom = null;
+
+        if (forSigning)
+        {
+            if (param instanceof ParametersWithRandom)
+            {
+                ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+                this.key = (DSAPrivateKeyParameters)rParam.getParameters();
+                providedRandom = rParam.getRandom();
+            }
+            else
+            {
+                this.key = (DSAPrivateKeyParameters)param;
+            }
+        }
+        else
+        {
+            this.key = (DSAPublicKeyParameters)param;
+        }
+
+        this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom);
+    }
+
+    public BigInteger getOrder()
+    {
+        return key.getParameters().getQ();
+    }
+
+    /**
+     * generate a signature for the given message using the key we were
+     * initialised with. For conventional DSA the message should be a SHA-1
+     * hash of the message of interest.
+     *
+     * @param message the message that will be verified later.
+     */
+    public BigInteger[] generateSignature(
+        byte[] message)
+    {
+        DSAParameters   params = key.getParameters();
+        BigInteger      q = params.getQ();
+        BigInteger      m = calculateE(q, message);
+        BigInteger      x = ((DSAPrivateKeyParameters)key).getX();
+
+        if (kCalculator.isDeterministic())
+        {
+            kCalculator.init(q, x, message);
+        }
+        else
+        {
+            kCalculator.init(q, random);
+        }
+
+        BigInteger  k = kCalculator.nextK();
+
+        // the randomizer is to conceal timing information related to k and x.
+        BigInteger  r = params.getG().modPow(k.add(getRandomizer(q, random)), params.getP()).mod(q);
+
+        k = k.modInverse(q).multiply(m.add(x.multiply(r)));
+
+        BigInteger  s = k.mod(q);
+
+        return new BigInteger[]{ r, s };
+    }
+
+    /**
+     * return true if the value r and s represent a DSA signature for
+     * the passed in message for standard DSA the message should be a
+     * SHA-1 hash of the real message to be verified.
+     */
+    public boolean verifySignature(
+        byte[]      message,
+        BigInteger  r,
+        BigInteger  s)
+    {
+        DSAParameters   params = key.getParameters();
+        BigInteger      q = params.getQ();
+        BigInteger      m = calculateE(q, message);
+        BigInteger      zero = BigInteger.valueOf(0);
+
+        if (zero.compareTo(r) >= 0 || q.compareTo(r) <= 0)
+        {
+            return false;
+        }
+
+        if (zero.compareTo(s) >= 0 || q.compareTo(s) <= 0)
+        {
+            return false;
+        }
+
+        BigInteger  w = s.modInverse(q);
+
+        BigInteger  u1 = m.multiply(w).mod(q);
+        BigInteger  u2 = r.multiply(w).mod(q);
+
+        BigInteger p = params.getP();
+        u1 = params.getG().modPow(u1, p);
+        u2 = ((DSAPublicKeyParameters)key).getY().modPow(u2, p);
+
+        BigInteger  v = u1.multiply(u2).mod(p).mod(q);
+
+        return v.equals(r);
+    }
+
+    private BigInteger calculateE(BigInteger n, byte[] message)
+    {
+        if (n.bitLength() >= message.length * 8)
+        {
+            return new BigInteger(1, message);
+        }
+        else
+        {
+            byte[] trunc = new byte[n.bitLength() / 8];
+
+            System.arraycopy(message, 0, trunc, 0, trunc.length);
+
+            return new BigInteger(1, trunc);
+        }
+    }
+
+    protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided)
+    {
+        return !needed ? null : (provided != null) ? provided : CryptoServicesRegistrar.getSecureRandom();
+    }
+
+    private BigInteger getRandomizer(BigInteger q, SecureRandom provided)
+    {
+        // Calculate a random multiple of q to add to k. Note that g^q = 1 (mod p), so adding multiple of q to k does not change r.
+        int randomBits = 7;
+
+        return BigIntegers.createRandomBigInteger(randomBits, provided != null ? provided : CryptoServicesRegistrar.getSecureRandom()).add(BigInteger.valueOf(128)).multiply(q);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/ECDSASigner.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/ECDSASigner.java
new file mode 100644
index 0000000..710cca0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/ECDSASigner.java
@@ -0,0 +1,260 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.signers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.DSAExt;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.android.internal.org.bouncycastle.math.ec.ECAlgorithms;
+import com.android.internal.org.bouncycastle.math.ec.ECConstants;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECMultiplier;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.ec.FixedPointCombMultiplier;
+
+/**
+ * EC-DSA as described in X9.62
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECDSASigner
+    implements ECConstants, DSAExt
+{
+    private final DSAKCalculator kCalculator;
+
+    private ECKeyParameters key;
+    private SecureRandom    random;
+
+    /**
+     * Default configuration, random K values.
+     */
+    public ECDSASigner()
+    {
+        this.kCalculator = new RandomDSAKCalculator();
+    }
+
+    /**
+     * Configuration with an alternate, possibly deterministic calculator of K.
+     *
+     * @param kCalculator a K value calculator.
+     */
+    public ECDSASigner(DSAKCalculator kCalculator)
+    {
+        this.kCalculator = kCalculator;
+    }
+
+    public void init(
+        boolean                 forSigning,
+        CipherParameters        param)
+    {
+        SecureRandom providedRandom = null;
+
+        if (forSigning)
+        {
+            if (param instanceof ParametersWithRandom)
+            {
+                ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+                this.key = (ECPrivateKeyParameters)rParam.getParameters();
+                providedRandom = rParam.getRandom();
+            }
+            else
+            {
+                this.key = (ECPrivateKeyParameters)param;
+            }
+        }
+        else
+        {
+            this.key = (ECPublicKeyParameters)param;
+        }
+
+        this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom);
+    }
+
+    public BigInteger getOrder()
+    {
+        return key.getParameters().getN();
+    }
+
+    // 5.3 pg 28
+    /**
+     * generate a signature for the given message using the key we were
+     * initialised with. For conventional DSA the message should be a SHA-1
+     * hash of the message of interest.
+     *
+     * @param message the message that will be verified later.
+     */
+    public BigInteger[] generateSignature(
+        byte[] message)
+    {
+        ECDomainParameters ec = key.getParameters();
+        BigInteger n = ec.getN();
+        BigInteger e = calculateE(n, message);
+        BigInteger d = ((ECPrivateKeyParameters)key).getD();
+
+        if (kCalculator.isDeterministic())
+        {
+            kCalculator.init(n, d, message);
+        }
+        else
+        {
+            kCalculator.init(n, random);
+        }
+
+        BigInteger r, s;
+
+        ECMultiplier basePointMultiplier = createBasePointMultiplier();
+
+        // 5.3.2
+        do // generate s
+        {
+            BigInteger k;
+            do // generate r
+            {
+                k = kCalculator.nextK();
+
+                ECPoint p = basePointMultiplier.multiply(ec.getG(), k).normalize();
+
+                // 5.3.3
+                r = p.getAffineXCoord().toBigInteger().mod(n);
+            }
+            while (r.equals(ZERO));
+
+            s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
+        }
+        while (s.equals(ZERO));
+
+        return new BigInteger[]{ r, s };
+    }
+
+    // 5.4 pg 29
+    /**
+     * return true if the value r and s represent a DSA signature for
+     * the passed in message (for standard DSA the message should be
+     * a SHA-1 hash of the real message to be verified).
+     */
+    public boolean verifySignature(
+        byte[]      message,
+        BigInteger  r,
+        BigInteger  s)
+    {
+        ECDomainParameters ec = key.getParameters();
+        BigInteger n = ec.getN();
+        BigInteger e = calculateE(n, message);
+
+        // r in the range [1,n-1]
+        if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0)
+        {
+            return false;
+        }
+
+        // s in the range [1,n-1]
+        if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0)
+        {
+            return false;
+        }
+
+        BigInteger c = s.modInverse(n);
+
+        BigInteger u1 = e.multiply(c).mod(n);
+        BigInteger u2 = r.multiply(c).mod(n);
+
+        ECPoint G = ec.getG();
+        ECPoint Q = ((ECPublicKeyParameters)key).getQ();
+
+        ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2);
+
+        // components must be bogus.
+        if (point.isInfinity())
+        {
+            return false;
+        }
+
+        /*
+         * If possible, avoid normalizing the point (to save a modular inversion in the curve field).
+         * 
+         * There are ~cofactor elements of the curve field that reduce (modulo the group order) to 'r'.
+         * If the cofactor is known and small, we generate those possible field values and project each
+         * of them to the same "denominator" (depending on the particular projective coordinates in use)
+         * as the calculated point.X. If any of the projected values matches point.X, then we have:
+         *     (point.X / Denominator mod p) mod n == r
+         * as required, and verification succeeds.
+         * 
+         * Based on an original idea by Gregory Maxwell (https://github.com/gmaxwell), as implemented in
+         * the libsecp256k1 project (https://github.com/bitcoin/secp256k1).
+         */
+        ECCurve curve = point.getCurve();
+        if (curve != null)
+        {
+            BigInteger cofactor = curve.getCofactor();
+            if (cofactor != null && cofactor.compareTo(EIGHT) <= 0)
+            {
+                ECFieldElement D = getDenominator(curve.getCoordinateSystem(), point);
+                if (D != null && !D.isZero())
+                {
+                    ECFieldElement X = point.getXCoord();
+                    while (curve.isValidFieldElement(r))
+                    {
+                        ECFieldElement R = curve.fromBigInteger(r).multiply(D);
+                        if (R.equals(X))
+                        {
+                            return true;
+                        }
+                        r = r.add(n);
+                    }
+                    return false;
+                }
+            }
+        }
+
+        BigInteger v = point.normalize().getAffineXCoord().toBigInteger().mod(n);
+        return v.equals(r);
+    }
+
+    protected BigInteger calculateE(BigInteger n, byte[] message)
+    {
+        int log2n = n.bitLength();
+        int messageBitLength = message.length * 8;
+
+        BigInteger e = new BigInteger(1, message);
+        if (log2n < messageBitLength)
+        {
+            e = e.shiftRight(messageBitLength - log2n);
+        }
+        return e;
+    }
+
+    protected ECMultiplier createBasePointMultiplier()
+    {
+        return new FixedPointCombMultiplier();
+    }
+
+    protected ECFieldElement getDenominator(int coordinateSystem, ECPoint p)
+    {
+        switch (coordinateSystem)
+        {
+        case ECCurve.COORD_HOMOGENEOUS:
+        case ECCurve.COORD_LAMBDA_PROJECTIVE:
+        case ECCurve.COORD_SKEWED:
+            return p.getZCoord(0);
+        case ECCurve.COORD_JACOBIAN:
+        case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+        case ECCurve.COORD_JACOBIAN_MODIFIED:
+            return p.getZCoord(0).square();
+        default:
+            return null;
+        }
+    }
+
+    protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided)
+    {
+        return !needed ? null : (provided != null) ? provided : CryptoServicesRegistrar.getSecureRandom();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/PlainDSAEncoding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/PlainDSAEncoding.java
new file mode 100644
index 0000000..6b1807b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/PlainDSAEncoding.java
@@ -0,0 +1,66 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.signers;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PlainDSAEncoding
+    implements DSAEncoding
+{
+    public static final PlainDSAEncoding INSTANCE = new PlainDSAEncoding();
+
+    public byte[] encode(BigInteger n, BigInteger r, BigInteger s)
+    {
+        int valueLength = BigIntegers.getUnsignedByteLength(n);
+        byte[] result = new byte[valueLength * 2];
+        encodeValue(n, r, result, 0, valueLength);
+        encodeValue(n, s, result, valueLength, valueLength);
+        return result;
+    }
+
+    public BigInteger[] decode(BigInteger n, byte[] encoding)
+    {
+        int valueLength = BigIntegers.getUnsignedByteLength(n);
+        if (encoding.length != valueLength * 2)
+        {
+            throw new IllegalArgumentException("Encoding has incorrect length");
+        }
+
+        return new BigInteger[] {
+            decodeValue(n, encoding, 0, valueLength),
+            decodeValue(n, encoding, valueLength, valueLength),
+        };
+    }
+
+    protected BigInteger checkValue(BigInteger n, BigInteger x)
+    {
+        if (x.signum() < 0 || x.compareTo(n) >= 0)
+        {
+            throw new IllegalArgumentException("Value out of range");
+        }
+
+        return x;
+    }
+
+    protected BigInteger decodeValue(BigInteger n, byte[] buf, int off, int len)
+    {
+        byte[] bs = Arrays.copyOfRange(buf, off, off + len);
+        return checkValue(n, new BigInteger(1, bs));
+    }
+
+    private void encodeValue(BigInteger n, BigInteger x, byte[] buf, int off, int len)
+    {
+        byte[] bs = checkValue(n, x).toByteArray();
+        int bsOff = Math.max(0, bs.length - len);
+        int bsLen = bs.length - bsOff;
+
+        int pos = len - bsLen;
+        Arrays.fill(buf, off, off + pos, (byte)0);
+        System.arraycopy(bs, bsOff, buf, off + pos, bsLen);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/RSADigestSigner.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/RSADigestSigner.java
new file mode 100644
index 0000000..4ce4da8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/RSADigestSigner.java
@@ -0,0 +1,257 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.signers;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.DigestInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.AsymmetricBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoException;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.Signer;
+import com.android.internal.org.bouncycastle.crypto.encodings.PKCS1Encoding;
+import com.android.internal.org.bouncycastle.crypto.engines.RSABlindedEngine;
+import com.android.internal.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSADigestSigner
+    implements Signer
+{
+    private final AsymmetricBlockCipher rsaEngine = new PKCS1Encoding(new RSABlindedEngine());
+    private final AlgorithmIdentifier algId;
+    private final Digest digest;
+    private boolean forSigning;
+
+    private static final Hashtable oidMap = new Hashtable();
+
+    /*
+     * Load OID table.
+     */
+    static
+    {
+        // BEGIN Android-removed: Unsupported algorithms
+        // oidMap.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128);
+        // oidMap.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160);
+        // oidMap.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256);
+        // END Android-removed: Unsupported algorithms
+
+        oidMap.put("SHA-1", X509ObjectIdentifiers.id_SHA1);
+        oidMap.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+        oidMap.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+        oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384);
+        oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+        oidMap.put("SHA-512/224", NISTObjectIdentifiers.id_sha512_224);
+        oidMap.put("SHA-512/256", NISTObjectIdentifiers.id_sha512_256);
+
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        oidMap.put("SHA3-224", NISTObjectIdentifiers.id_sha3_224);
+        oidMap.put("SHA3-256", NISTObjectIdentifiers.id_sha3_256);
+        oidMap.put("SHA3-384", NISTObjectIdentifiers.id_sha3_384);
+        oidMap.put("SHA3-512", NISTObjectIdentifiers.id_sha3_512);
+
+        oidMap.put("MD2", PKCSObjectIdentifiers.md2);
+        oidMap.put("MD4", PKCSObjectIdentifiers.md4);
+        */
+        // END Android-removed: Unsupported algorithms
+        oidMap.put("MD5", PKCSObjectIdentifiers.md5);
+    }
+
+    public RSADigestSigner(
+        Digest digest)
+    {
+        this(digest, (ASN1ObjectIdentifier)oidMap.get(digest.getAlgorithmName()));
+    }
+
+    public RSADigestSigner(
+        Digest digest,
+        ASN1ObjectIdentifier digestOid)
+    {
+        this.digest = digest;
+        this.algId = new AlgorithmIdentifier(digestOid, DERNull.INSTANCE);
+    }
+
+    /**
+     * @deprecated
+     */
+    public String getAlgorithmName()
+    {
+        return digest.getAlgorithmName() + "withRSA";
+    }
+
+    /**
+     * initialise the signer for signing or verification.
+     *
+     * @param forSigning
+     *            true if for signing, false otherwise
+     * @param parameters
+     *            necessary parameters.
+     */
+    public void init(
+        boolean          forSigning,
+        CipherParameters parameters)
+    {
+        this.forSigning = forSigning;
+        AsymmetricKeyParameter k;
+
+        if (parameters instanceof ParametersWithRandom)
+        {
+            k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).getParameters();
+        }
+        else
+        {
+            k = (AsymmetricKeyParameter)parameters;
+        }
+
+        if (forSigning && !k.isPrivate())
+        {
+            throw new IllegalArgumentException("signing requires private key");
+        }
+
+        if (!forSigning && k.isPrivate())
+        {
+            throw new IllegalArgumentException("verification requires public key");
+        }
+
+        reset();
+
+        rsaEngine.init(forSigning, parameters);
+    }
+
+    /**
+     * update the internal digest with the byte b
+     */
+    public void update(
+        byte input)
+    {
+        digest.update(input);
+    }
+
+    /**
+     * update the internal digest with the byte array in
+     */
+    public void update(
+        byte[]  input,
+        int     inOff,
+        int     length)
+    {
+        digest.update(input, inOff, length);
+    }
+
+    /**
+     * Generate a signature for the message we've been loaded with using the key
+     * we were initialised with.
+     */
+    public byte[] generateSignature()
+        throws CryptoException, DataLengthException
+    {
+        if (!forSigning)
+        {
+            throw new IllegalStateException("RSADigestSigner not initialised for signature generation.");
+        }
+
+        byte[] hash = new byte[digest.getDigestSize()];
+        digest.doFinal(hash, 0);
+
+        try
+        {
+            byte[] data = derEncode(hash);
+            return rsaEngine.processBlock(data, 0, data.length);
+        }
+        catch (IOException e)
+        {
+            throw new CryptoException("unable to encode signature: " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * return true if the internal state represents the signature described in
+     * the passed in array.
+     */
+    public boolean verifySignature(
+        byte[] signature)
+    {
+        if (forSigning)
+        {
+            throw new IllegalStateException("RSADigestSigner not initialised for verification");
+        }
+
+        byte[] hash = new byte[digest.getDigestSize()];
+
+        digest.doFinal(hash, 0);
+
+        byte[] sig;
+        byte[] expected;
+
+        try
+        {
+            sig = rsaEngine.processBlock(signature, 0, signature.length);
+            expected = derEncode(hash);
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+
+        if (sig.length == expected.length)
+        {
+            return Arrays.constantTimeAreEqual(sig, expected);
+        }
+        else if (sig.length == expected.length - 2)  // NULL left out
+        {
+            int sigOffset = sig.length - hash.length - 2;
+            int expectedOffset = expected.length - hash.length - 2;
+
+            expected[1] -= 2;      // adjust lengths
+            expected[3] -= 2;
+
+            int nonEqual = 0;
+
+            for (int i = 0; i < hash.length; i++)
+            {
+                nonEqual |= (sig[sigOffset + i] ^ expected[expectedOffset + i]);
+            }
+
+            for (int i = 0; i < sigOffset; i++)
+            {
+                nonEqual |= (sig[i] ^ expected[i]);  // check header less NULL
+            }
+
+            return nonEqual == 0;
+        }
+        else
+        {
+            Arrays.constantTimeAreEqual(expected, expected);  // keep time "steady".
+
+            return false;
+        }
+    }
+
+    public void reset()
+    {
+        digest.reset();
+    }
+
+    private byte[] derEncode(
+        byte[] hash)
+        throws IOException
+    {
+        DigestInfo dInfo = new DigestInfo(algId, hash);
+
+        return dInfo.getEncoded(ASN1Encoding.DER);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java
new file mode 100644
index 0000000..c37e883
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java
@@ -0,0 +1,49 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.signers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RandomDSAKCalculator
+    implements DSAKCalculator
+{
+    private static final BigInteger ZERO = BigInteger.valueOf(0);
+
+    private BigInteger q;
+    private SecureRandom random;
+
+    public boolean isDeterministic()
+    {
+        return false;
+    }
+
+    public void init(BigInteger n, SecureRandom random)
+    {
+        this.q = n;
+        this.random = random;
+    }
+
+    public void init(BigInteger n, BigInteger d, byte[] message)
+    {
+        throw new IllegalStateException("Operation not supported");
+    }
+
+    public BigInteger nextK()
+    {
+        int qBitLength = q.bitLength();
+
+        BigInteger k;
+        do
+        {
+            k = BigIntegers.createRandomBigInteger(qBitLength, random);
+        }
+        while (k.equals(ZERO) || k.compareTo(q) >= 0);
+
+        return k;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/StandardDSAEncoding.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/StandardDSAEncoding.java
new file mode 100644
index 0000000..30568bc
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/signers/StandardDSAEncoding.java
@@ -0,0 +1,68 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.signers;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class StandardDSAEncoding
+    implements DSAEncoding
+{
+    public static final StandardDSAEncoding INSTANCE = new StandardDSAEncoding();
+
+    public byte[] encode(BigInteger n, BigInteger r, BigInteger s) throws IOException
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        encodeValue(n, v, r);
+        encodeValue(n, v, s);
+        return new DERSequence(v).getEncoded(ASN1Encoding.DER);
+    }
+
+    public BigInteger[] decode(BigInteger n, byte[] encoding) throws IOException
+    {
+        ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
+        if (seq.size() == 2)
+        {
+            BigInteger r = decodeValue(n, seq, 0);
+            BigInteger s = decodeValue(n, seq, 1);
+
+            byte[] expectedEncoding = encode(n, r, s);
+            if (Arrays.areEqual(expectedEncoding,  encoding))
+            {
+                return new BigInteger[]{ r, s };
+            }
+        }
+
+        throw new IllegalArgumentException("Malformed signature");
+    }
+
+    protected BigInteger checkValue(BigInteger n, BigInteger x)
+    {
+        if (x.signum() < 0 || (null != n && x.compareTo(n) >= 0))
+        {
+            throw new IllegalArgumentException("Value out of range");
+        }
+
+        return x;
+    }
+
+    protected BigInteger decodeValue(BigInteger n, ASN1Sequence s, int pos)
+    {
+        return checkValue(n, ((ASN1Integer)s.getObjectAt(pos)).getValue());
+    }
+
+    protected void encodeValue(BigInteger n, ASN1EncodableVector v, BigInteger x)
+    {
+        v.add(new ASN1Integer(checkValue(n, x)));
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/tls/CertificateType.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/tls/CertificateType.java
new file mode 100644
index 0000000..acc4492
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/tls/CertificateType.java
@@ -0,0 +1,17 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.tls;
+
+/**
+ * RFC 6091 
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CertificateType
+{
+    public static final short X509 = 0;
+    public static final short OpenPGP = 1;
+    
+    /*
+     * RFC 7250
+     */
+    public static final short RawPublicKey = 2;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/tls/TlsNoCloseNotifyException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/tls/TlsNoCloseNotifyException.java
new file mode 100644
index 0000000..18efee2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/tls/TlsNoCloseNotifyException.java
@@ -0,0 +1,21 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.tls;
+
+import java.io.EOFException;
+
+/**
+ * This exception will be thrown (only) when the connection is closed by the peer without sending a
+ * {@link AlertDescription#close_notify close_notify} warning alert. If this happens, the TLS
+ * protocol cannot rule out truncation of the connection data (potentially malicious). It may be
+ * possible to check for truncation via some property of a higher level protocol built upon TLS,
+ * e.g. the Content-Length header for HTTPS.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TlsNoCloseNotifyException
+    extends EOFException
+{
+    public TlsNoCloseNotifyException()
+    {
+        super("No close_notify alert received before connection closed");
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/util/Pack.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/util/Pack.java
new file mode 100644
index 0000000..272859c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/util/Pack.java
@@ -0,0 +1,206 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.util;
+
+/**
+ * @deprecated use org.bouncycastle.util.pack
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class Pack
+{
+    public static int bigEndianToInt(byte[] bs, int off)
+    {
+        int n = bs[  off] << 24;
+        n |= (bs[++off] & 0xff) << 16;
+        n |= (bs[++off] & 0xff) << 8;
+        n |= (bs[++off] & 0xff);
+        return n;
+    }
+
+    public static void bigEndianToInt(byte[] bs, int off, int[] ns)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            ns[i] = bigEndianToInt(bs, off);
+            off += 4;
+        }
+    }
+
+    public static byte[] intToBigEndian(int n)
+    {
+        byte[] bs = new byte[4];
+        intToBigEndian(n, bs, 0);
+        return bs;
+    }
+
+    public static void intToBigEndian(int n, byte[] bs, int off)
+    {
+        bs[  off] = (byte)(n >>> 24);
+        bs[++off] = (byte)(n >>> 16);
+        bs[++off] = (byte)(n >>>  8);
+        bs[++off] = (byte)(n       );
+    }
+
+    public static byte[] intToBigEndian(int[] ns)
+    {
+        byte[] bs = new byte[4 * ns.length];
+        intToBigEndian(ns, bs, 0);
+        return bs;
+    }
+
+    public static void intToBigEndian(int[] ns, byte[] bs, int off)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            intToBigEndian(ns[i], bs, off);
+            off += 4;
+        }
+    }
+
+    public static long bigEndianToLong(byte[] bs, int off)
+    {
+        int hi = bigEndianToInt(bs, off);
+        int lo = bigEndianToInt(bs, off + 4);
+        return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
+    }
+
+    public static void bigEndianToLong(byte[] bs, int off, long[] ns)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            ns[i] = bigEndianToLong(bs, off);
+            off += 8;
+        }
+    }
+
+    public static byte[] longToBigEndian(long n)
+    {
+        byte[] bs = new byte[8];
+        longToBigEndian(n, bs, 0);
+        return bs;
+    }
+
+    public static void longToBigEndian(long n, byte[] bs, int off)
+    {
+        intToBigEndian((int)(n >>> 32), bs, off);
+        intToBigEndian((int)(n & 0xffffffffL), bs, off + 4);
+    }
+
+    public static byte[] longToBigEndian(long[] ns)
+    {
+        byte[] bs = new byte[8 * ns.length];
+        longToBigEndian(ns, bs, 0);
+        return bs;
+    }
+
+    public static void longToBigEndian(long[] ns, byte[] bs, int off)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            longToBigEndian(ns[i], bs, off);
+            off += 8;
+        }
+    }
+
+    public static int littleEndianToInt(byte[] bs, int off)
+    {
+        int n = bs[  off] & 0xff;
+        n |= (bs[++off] & 0xff) << 8;
+        n |= (bs[++off] & 0xff) << 16;
+        n |= bs[++off] << 24;
+        return n;
+    }
+
+    public static void littleEndianToInt(byte[] bs, int off, int[] ns)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            ns[i] = littleEndianToInt(bs, off);
+            off += 4;
+        }
+    }
+
+    public static void littleEndianToInt(byte[] bs, int bOff, int[] ns, int nOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            ns[nOff + i] = littleEndianToInt(bs, bOff);
+            bOff += 4;
+        }
+    }
+
+    public static byte[] intToLittleEndian(int n)
+    {
+        byte[] bs = new byte[4];
+        intToLittleEndian(n, bs, 0);
+        return bs;
+    }
+
+    public static void intToLittleEndian(int n, byte[] bs, int off)
+    {
+        bs[  off] = (byte)(n       );
+        bs[++off] = (byte)(n >>>  8);
+        bs[++off] = (byte)(n >>> 16);
+        bs[++off] = (byte)(n >>> 24);
+    }
+
+    public static byte[] intToLittleEndian(int[] ns)
+    {
+        byte[] bs = new byte[4 * ns.length];
+        intToLittleEndian(ns, bs, 0);
+        return bs;
+    }
+
+    public static void intToLittleEndian(int[] ns, byte[] bs, int off)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            intToLittleEndian(ns[i], bs, off);
+            off += 4;
+        }
+    }
+
+    public static long littleEndianToLong(byte[] bs, int off)
+    {
+        int lo = littleEndianToInt(bs, off);
+        int hi = littleEndianToInt(bs, off + 4);
+        return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
+    }
+
+    public static void littleEndianToLong(byte[] bs, int off, long[] ns)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            ns[i] = littleEndianToLong(bs, off);
+            off += 8;
+        }
+    }
+
+    public static byte[] longToLittleEndian(long n)
+    {
+        byte[] bs = new byte[8];
+        longToLittleEndian(n, bs, 0);
+        return bs;
+    }
+
+    public static void longToLittleEndian(long n, byte[] bs, int off)
+    {
+        intToLittleEndian((int)(n & 0xffffffffL), bs, off);
+        intToLittleEndian((int)(n >>> 32), bs, off + 4);
+    }
+
+    public static byte[] longToLittleEndian(long[] ns)
+    {
+        byte[] bs = new byte[8 * ns.length];
+        longToLittleEndian(ns, bs, 0);
+        return bs;
+    }
+
+    public static void longToLittleEndian(long[] ns, byte[] bs, int off)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            longToLittleEndian(ns[i], bs, off);
+            off += 8;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/util/PrivateKeyFactory.java
new file mode 100644
index 0000000..eb943bc
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/util/PrivateKeyFactory.java
@@ -0,0 +1,330 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.oiw.ElGamalParameter;
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+// import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.DHParameter;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.pkcs.RSAPrivateKey;
+// import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.sec.ECPrivateKey;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.DSAParameter;
+import com.android.internal.org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import com.android.internal.org.bouncycastle.asn1.x9.X962Parameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.ec.CustomNamedCurves;
+import com.android.internal.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.params.ECGOST3410Parameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECNamedDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.params.ElGamalParameters;
+// import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
+// import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
+// import org.bouncycastle.crypto.params.Ed448PrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
+// import org.bouncycastle.crypto.params.X448PrivateKeyParameters;
+
+/**
+ * Factory for creating private key objects from PKCS8 PrivateKeyInfo objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PrivateKeyFactory
+{
+    /**
+     * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding.
+     *
+     * @param privateKeyInfoData the PrivateKeyInfo encoding
+     * @return a suitable private key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData)
+        throws IOException
+    {
+        return createKey(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(privateKeyInfoData)));
+    }
+
+    /**
+     * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding read from a
+     * stream.
+     *
+     * @param inStr the stream to read the PrivateKeyInfo encoding from
+     * @return a suitable private key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(InputStream inStr)
+        throws IOException
+    {
+        return createKey(PrivateKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
+    }
+
+    /**
+     * Create a private key parameter from the passed in PKCS8 PrivateKeyInfo object.
+     *
+     * @param keyInfo the PrivateKeyInfo object containing the key material
+     * @return a suitable private key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo)
+        throws IOException
+    {
+        AlgorithmIdentifier algId = keyInfo.getPrivateKeyAlgorithm();
+        ASN1ObjectIdentifier algOID = algId.getAlgorithm();
+
+        if (algOID.equals(PKCSObjectIdentifiers.rsaEncryption)
+            || algOID.equals(PKCSObjectIdentifiers.id_RSASSA_PSS)
+            || algOID.equals(X509ObjectIdentifiers.id_ea_rsa))
+        {
+            RSAPrivateKey keyStructure = RSAPrivateKey.getInstance(keyInfo.parsePrivateKey());
+
+            return new RSAPrivateCrtKeyParameters(keyStructure.getModulus(),
+                keyStructure.getPublicExponent(), keyStructure.getPrivateExponent(),
+                keyStructure.getPrime1(), keyStructure.getPrime2(), keyStructure.getExponent1(),
+                keyStructure.getExponent2(), keyStructure.getCoefficient());
+        }
+        // TODO?
+//      else if (algOID.equals(X9ObjectIdentifiers.dhpublicnumber))
+        else if (algOID.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+            DHParameter params = DHParameter.getInstance(algId.getParameters());
+            ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey();
+
+            BigInteger lVal = params.getL();
+            int l = lVal == null ? 0 : lVal.intValue();
+            DHParameters dhParams = new DHParameters(params.getP(), params.getG(), null, l);
+
+            return new DHPrivateKeyParameters(derX.getValue(), dhParams);
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (algOID.equals(OIWObjectIdentifiers.elGamalAlgorithm))
+        {
+            ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters());
+            ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey();
+
+            return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(
+                params.getP(), params.getG()));
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+        else if (algOID.equals(X9ObjectIdentifiers.id_dsa))
+        {
+            ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey();
+            ASN1Encodable de = algId.getParameters();
+
+            DSAParameters parameters = null;
+            if (de != null)
+            {
+                DSAParameter params = DSAParameter.getInstance(de.toASN1Primitive());
+                parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
+            }
+
+            return new DSAPrivateKeyParameters(derX.getValue(), parameters);
+        }
+        else if (algOID.equals(X9ObjectIdentifiers.id_ecPublicKey))
+        {
+            X962Parameters params = new X962Parameters((ASN1Primitive)algId.getParameters());
+
+            X9ECParameters x9;
+            ECDomainParameters dParams;
+
+            if (params.isNamedCurve())
+            {
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+
+                x9 = CustomNamedCurves.getByOID(oid);
+                if (x9 == null)
+                {
+                    x9 = ECNamedCurveTable.getByOID(oid);
+                }
+                dParams = new ECNamedDomainParameters(
+                    oid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
+            }
+            else
+            {
+                x9 = X9ECParameters.getInstance(params.getParameters());
+                dParams = new ECDomainParameters(
+                    x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
+            }
+
+            ECPrivateKey ec = ECPrivateKey.getInstance(keyInfo.parsePrivateKey());
+            BigInteger d = ec.getKey();
+
+            return new ECPrivateKeyParameters(d, dParams);
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (algOID.equals(EdECObjectIdentifiers.id_X25519))
+        {
+            return new X25519PrivateKeyParameters(getRawKey(keyInfo, X25519PrivateKeyParameters.KEY_SIZE), 0);
+        }
+        else if (algOID.equals(EdECObjectIdentifiers.id_X448))
+        {
+            return new X448PrivateKeyParameters(getRawKey(keyInfo, X448PrivateKeyParameters.KEY_SIZE), 0);
+        }
+        else if (algOID.equals(EdECObjectIdentifiers.id_Ed25519))
+        {
+            return new Ed25519PrivateKeyParameters(getRawKey(keyInfo, Ed25519PrivateKeyParameters.KEY_SIZE), 0);
+        }
+        else if (algOID.equals(EdECObjectIdentifiers.id_Ed448))
+        {
+            return new Ed448PrivateKeyParameters(getRawKey(keyInfo, Ed448PrivateKeyParameters.KEY_SIZE), 0);
+        }
+        else if (
+            algOID.equals(CryptoProObjectIdentifiers.gostR3410_2001) ||
+                algOID.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512) ||
+                algOID.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256))
+        {
+            GOST3410PublicKeyAlgParameters gostParams = GOST3410PublicKeyAlgParameters.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters());
+            ECGOST3410Parameters ecSpec = null;
+            BigInteger d = null;
+            ASN1Primitive p = keyInfo.getPrivateKeyAlgorithm().getParameters().toASN1Primitive();
+            if (p instanceof ASN1Sequence && (ASN1Sequence.getInstance(p).size() == 2 || ASN1Sequence.getInstance(p).size() == 3))
+            {
+
+                ECDomainParameters ecP = ECGOST3410NamedCurves.getByOID(gostParams.getPublicKeyParamSet());
+
+                ecSpec = new ECGOST3410Parameters(
+                    new ECNamedDomainParameters(
+                        gostParams.getPublicKeyParamSet(), ecP),
+                    gostParams.getPublicKeyParamSet(),
+                    gostParams.getDigestParamSet(),
+                    gostParams.getEncryptionParamSet());
+                ASN1Encodable privKey = keyInfo.parsePrivateKey();
+                if (privKey instanceof ASN1Integer)
+                {
+                    d = ASN1Integer.getInstance(privKey).getPositiveValue();
+                }
+                else
+                {
+                    byte[] encVal = ASN1OctetString.getInstance(privKey).getOctets();
+                    byte[] dVal = new byte[encVal.length];
+
+                    for (int i = 0; i != encVal.length; i++)
+                    {
+                        dVal[i] = encVal[encVal.length - 1 - i];
+                    }
+
+                    d = new BigInteger(1, dVal);
+                }
+
+
+            }
+            else
+            {
+                X962Parameters params = X962Parameters.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters());
+
+                if (params.isNamedCurve())
+                {
+                    ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+                    X9ECParameters ecP = ECNamedCurveTable.getByOID(oid);
+                    if (ecP == null)
+                    {
+                        ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
+                        ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters(
+                            oid,
+                            gParam.getCurve(),
+                            gParam.getG(),
+                            gParam.getN(),
+                            gParam.getH(),
+                            gParam.getSeed()), gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet(), gostParams.getEncryptionParamSet());
+                    }
+                    else
+                    {
+                        ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters(
+                            oid,
+                            ecP.getCurve(),
+                            ecP.getG(),
+                            ecP.getN(),
+                            ecP.getH(),
+                            ecP.getSeed()), gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet(), gostParams.getEncryptionParamSet());
+                    }
+                }
+                else if (params.isImplicitlyCA())
+                {
+                    ecSpec = null;
+                }
+                else
+                {
+                    X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+                    ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters(
+                        algOID,
+                        ecP.getCurve(),
+                        ecP.getG(),
+                        ecP.getN(),
+                        ecP.getH(),
+                        ecP.getSeed()), gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet(), gostParams.getEncryptionParamSet());
+                }
+
+                ASN1Encodable privKey = keyInfo.parsePrivateKey();
+                if (privKey instanceof ASN1Integer)
+                {
+                    ASN1Integer derD = ASN1Integer.getInstance(privKey);
+
+                    d = derD.getValue();
+                }
+                else
+                {
+                    org.bouncycastle.asn1.sec.ECPrivateKey ec = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(privKey);
+
+                    d = ec.getKey();
+                }
+
+            }
+
+            return new ECPrivateKeyParameters(
+                d,
+                new ECGOST3410Parameters(
+                    ecSpec,
+                    gostParams.getPublicKeyParamSet(),
+                    gostParams.getDigestParamSet(),
+                    gostParams.getEncryptionParamSet()));
+
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+        else
+        {
+            throw new RuntimeException("algorithm identifier in private key not recognised");
+        }
+    }
+
+    private static byte[] getRawKey(PrivateKeyInfo keyInfo, int expectedSize)
+        throws IOException
+    {
+        byte[] result = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets();
+        if (expectedSize != result.length)
+        {
+            throw new RuntimeException("private key encoding has incorrect length");
+        }
+        return result;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/util/PublicKeyFactory.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/util/PublicKeyFactory.java
new file mode 100644
index 0000000..3cd04c6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/crypto/util/PublicKeyFactory.java
@@ -0,0 +1,556 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.crypto.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+// import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+// import org.bouncycastle.asn1.oiw.ElGamalParameter;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.DHParameter;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.RSAPublicKey;
+// import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
+// import org.bouncycastle.asn1.ua.DSTU4145BinaryField;
+// import org.bouncycastle.asn1.ua.DSTU4145ECBinary;
+// import org.bouncycastle.asn1.ua.DSTU4145NamedCurves;
+// import org.bouncycastle.asn1.ua.DSTU4145Params;
+// import org.bouncycastle.asn1.ua.DSTU4145PointEncoder;
+// import org.bouncycastle.asn1.ua.UAObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.DSAParameter;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x9.DHPublicKey;
+import com.android.internal.org.bouncycastle.asn1.x9.DomainParameters;
+import com.android.internal.org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import com.android.internal.org.bouncycastle.asn1.x9.ValidationParams;
+import com.android.internal.org.bouncycastle.asn1.x9.X962Parameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECPoint;
+import com.android.internal.org.bouncycastle.asn1.x9.X9IntegerConverter;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.ec.CustomNamedCurves;
+import com.android.internal.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHValidationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+// import org.bouncycastle.crypto.params.ECGOST3410Parameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECNamedDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPublicKeyParameters;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
+// import org.bouncycastle.crypto.params.Ed448PublicKeyParameters;
+// import org.bouncycastle.crypto.params.ElGamalParameters;
+// import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAKeyParameters;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
+// import org.bouncycastle.crypto.params.X448PublicKeyParameters;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+
+/**
+ * Factory to create asymmetric public key parameters for asymmetric ciphers from range of
+ * ASN.1 encoded SubjectPublicKeyInfo objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PublicKeyFactory
+{
+    private static Map converters = new HashMap();
+
+    static
+    {
+        converters.put(PKCSObjectIdentifiers.rsaEncryption, new RSAConverter());
+        converters.put(PKCSObjectIdentifiers.id_RSASSA_PSS, new RSAConverter());
+        converters.put(X509ObjectIdentifiers.id_ea_rsa, new RSAConverter());
+        converters.put(X9ObjectIdentifiers.dhpublicnumber, new DHPublicNumberConverter());
+        converters.put(PKCSObjectIdentifiers.dhKeyAgreement, new DHAgreementConverter());
+        converters.put(X9ObjectIdentifiers.id_dsa, new DSAConverter());
+        converters.put(OIWObjectIdentifiers.dsaWithSHA1, new DSAConverter());
+        // Android-removed: Unsupported algorithm
+        // converters.put(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalConverter());
+        converters.put(X9ObjectIdentifiers.id_ecPublicKey, new ECConverter());
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        converters.put(CryptoProObjectIdentifiers.gostR3410_2001, new GOST3410_2001Converter());
+        converters.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256, new GOST3410_2012Converter());
+        converters.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512, new GOST3410_2012Converter());
+        converters.put(UAObjectIdentifiers.dstu4145be, new DSTUConverter());
+        converters.put(UAObjectIdentifiers.dstu4145le, new DSTUConverter());
+        converters.put(EdECObjectIdentifiers.id_X25519, new X25519Converter());
+        converters.put(EdECObjectIdentifiers.id_X448, new X448Converter());
+        converters.put(EdECObjectIdentifiers.id_Ed25519, new Ed25519Converter());
+        converters.put(EdECObjectIdentifiers.id_Ed448, new Ed448Converter());
+        */
+        // END Android-removed: Unsupported algorithms
+    }
+
+    /**
+     * Create a public key from a SubjectPublicKeyInfo encoding
+     *
+     * @param keyInfoData the SubjectPublicKeyInfo encoding
+     * @return the appropriate key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(byte[] keyInfoData)
+        throws IOException
+    {
+        return createKey(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(keyInfoData)));
+    }
+
+    /**
+     * Create a public key from a SubjectPublicKeyInfo encoding read from a stream
+     *
+     * @param inStr the stream to read the SubjectPublicKeyInfo encoding from
+     * @return the appropriate key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(InputStream inStr)
+        throws IOException
+    {
+        return createKey(SubjectPublicKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
+    }
+
+    /**
+     * Create a public key from the passed in SubjectPublicKeyInfo
+     *
+     * @param keyInfo the SubjectPublicKeyInfo containing the key data
+     * @return the appropriate key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo)
+        throws IOException
+    {
+        return createKey(keyInfo, null);
+    }
+
+    /**
+     * Create a public key from the passed in SubjectPublicKeyInfo
+     *
+     * @param keyInfo       the SubjectPublicKeyInfo containing the key data
+     * @param defaultParams default parameters that might be needed.
+     * @return the appropriate key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+        throws IOException
+    {
+        AlgorithmIdentifier algId = keyInfo.getAlgorithm();
+        SubjectPublicKeyInfoConverter converter = (SubjectPublicKeyInfoConverter)converters.get(algId.getAlgorithm());
+
+        if (converter != null)
+        {
+            return converter.getPublicKeyParameters(keyInfo, defaultParams);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier in public key not recognised: " + algId.getAlgorithm());
+        }
+    }
+
+    private static abstract class SubjectPublicKeyInfoConverter
+    {
+        abstract AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException;
+    }
+
+    private static class RSAConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException
+        {
+            RSAPublicKey pubKey = RSAPublicKey.getInstance(keyInfo.parsePublicKey());
+
+            return new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent());
+        }
+    }
+
+    private static class DHPublicNumberConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException
+        {
+            DHPublicKey dhPublicKey = DHPublicKey.getInstance(keyInfo.parsePublicKey());
+
+            BigInteger y = dhPublicKey.getY();
+
+            DomainParameters dhParams = DomainParameters.getInstance(keyInfo.getAlgorithm().getParameters());
+
+            BigInteger p = dhParams.getP();
+            BigInteger g = dhParams.getG();
+            BigInteger q = dhParams.getQ();
+
+            BigInteger j = null;
+            if (dhParams.getJ() != null)
+            {
+                j = dhParams.getJ();
+            }
+
+            DHValidationParameters validation = null;
+            ValidationParams dhValidationParms = dhParams.getValidationParams();
+            if (dhValidationParms != null)
+            {
+                byte[] seed = dhValidationParms.getSeed();
+                BigInteger pgenCounter = dhValidationParms.getPgenCounter();
+
+                // TODO Check pgenCounter size?
+
+                validation = new DHValidationParameters(seed, pgenCounter.intValue());
+            }
+
+            return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation));
+        }
+    }
+
+    private static class DHAgreementConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException
+        {
+            DHParameter params = DHParameter.getInstance(keyInfo.getAlgorithm().getParameters());
+            ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
+
+            BigInteger lVal = params.getL();
+            int l = lVal == null ? 0 : lVal.intValue();
+            DHParameters dhParams = new DHParameters(params.getP(), params.getG(), null, l);
+
+            return new DHPublicKeyParameters(derY.getValue(), dhParams);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithm
+    /*
+    private static class ElGamalConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException
+        {
+            ElGamalParameter params = ElGamalParameter.getInstance(keyInfo.getAlgorithm().getParameters());
+            ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
+
+            return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
+                params.getP(), params.getG()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithm
+
+    private static class DSAConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException
+        {
+            ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
+            ASN1Encodable de = keyInfo.getAlgorithm().getParameters();
+
+            DSAParameters parameters = null;
+            if (de != null)
+            {
+                DSAParameter params = DSAParameter.getInstance(de.toASN1Primitive());
+                parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
+            }
+
+            return new DSAPublicKeyParameters(derY.getValue(), parameters);
+        }
+    }
+
+    private static class ECConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+        {
+            X962Parameters params = X962Parameters.getInstance(keyInfo.getAlgorithm().getParameters());
+            ECDomainParameters dParams;
+
+            if (params.isNamedCurve())
+            {
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+
+                X9ECParameters x9 = CustomNamedCurves.getByOID(oid);
+                if (x9 == null)
+                {
+                    x9 = ECNamedCurveTable.getByOID(oid);
+                }
+                dParams = new ECNamedDomainParameters(
+                    oid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
+            }
+            else if (params.isImplicitlyCA())
+            {
+                dParams = (ECDomainParameters)defaultParams;
+            }
+            else
+            {
+                X9ECParameters x9 = X9ECParameters.getInstance(params.getParameters());
+                dParams = new ECDomainParameters(
+                    x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
+            }
+
+            DERBitString bits = keyInfo.getPublicKeyData();
+            byte[] data = bits.getBytes();
+            ASN1OctetString key = new DEROctetString(data);
+
+            //
+            // extra octet string - the old extra embedded octet string
+            //
+            if (data[0] == 0x04 && data[1] == data.length - 2
+                && (data[2] == 0x02 || data[2] == 0x03))
+            {
+                int qLength = new X9IntegerConverter().getByteLength(dParams.getCurve());
+
+                if (qLength >= data.length - 3)
+                {
+                    try
+                    {
+                        key = (ASN1OctetString)ASN1Primitive.fromByteArray(data);
+                    }
+                    catch (IOException ex)
+                    {
+                        throw new IllegalArgumentException("error recovering public key");
+                    }
+                }
+            }
+
+            X9ECPoint derQ = new X9ECPoint(dParams.getCurve(), key);
+
+            return new ECPublicKeyParameters(derQ.getPoint(), dParams);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    private static class GOST3410_2001Converter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+        {
+            DERBitString bits = keyInfo.getPublicKeyData();
+            ASN1OctetString key;
+
+            try
+            {
+                key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes());
+            }
+            catch (IOException ex)
+            {
+                throw new IllegalArgumentException("error recovering public key");
+            }
+
+            byte[] keyEnc = key.getOctets();
+
+            byte[] x9Encoding = new byte[65];
+            x9Encoding[0] = 0x04;
+            for (int i = 1; i <= 32; ++i)
+            {
+                x9Encoding[i] = keyEnc[32 - i];
+                x9Encoding[i + 32] = keyEnc[64 - i];
+            }
+
+            GOST3410PublicKeyAlgParameters gostParams = GOST3410PublicKeyAlgParameters.getInstance(keyInfo.getAlgorithm().getParameters());
+
+            ECGOST3410Parameters ecDomainParameters =
+                new ECGOST3410Parameters(
+                    new ECNamedDomainParameters(gostParams.getPublicKeyParamSet(), ECGOST3410NamedCurves.getByOID(gostParams.getPublicKeyParamSet())),
+                    gostParams.getPublicKeyParamSet(),
+                    gostParams.getDigestParamSet(),
+                    gostParams.getEncryptionParamSet());
+
+
+            return new ECPublicKeyParameters(ecDomainParameters.getCurve().decodePoint(x9Encoding), ecDomainParameters);
+
+        }
+    }
+
+    private static class GOST3410_2012Converter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+        {
+            ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+            DERBitString bits = keyInfo.getPublicKeyData();
+            ASN1OctetString key;
+
+            try
+            {
+                key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes());
+            }
+            catch (IOException ex)
+            {
+                throw new IllegalArgumentException("error recovering public key");
+            }
+
+            byte[] keyEnc = key.getOctets();
+
+            int fieldSize = 32;
+            if (algOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512))
+            {
+                fieldSize = 64;
+            }
+
+            int keySize = 2 * fieldSize;
+
+            byte[] x9Encoding = new byte[1 + keySize];
+            x9Encoding[0] = 0x04;
+            for (int i = 1; i <= fieldSize; ++i)
+            {
+                x9Encoding[i] = keyEnc[fieldSize - i];
+                x9Encoding[i + fieldSize] = keyEnc[keySize - i];
+            }
+
+            GOST3410PublicKeyAlgParameters gostParams = GOST3410PublicKeyAlgParameters.getInstance(keyInfo.getAlgorithm().getParameters());
+
+            ECGOST3410Parameters ecDomainParameters =
+                new ECGOST3410Parameters(
+                    new ECNamedDomainParameters(gostParams.getPublicKeyParamSet(), ECGOST3410NamedCurves.getByOID(gostParams.getPublicKeyParamSet())),
+                    gostParams.getPublicKeyParamSet(),
+                    gostParams.getDigestParamSet(),
+                    gostParams.getEncryptionParamSet());
+
+
+            return new ECPublicKeyParameters(ecDomainParameters.getCurve().decodePoint(x9Encoding), ecDomainParameters);
+        }
+    }
+
+    private static class DSTUConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException
+        {
+            DERBitString bits = keyInfo.getPublicKeyData();
+            ASN1OctetString key;
+
+            try
+            {
+                key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes());
+            }
+            catch (IOException ex)
+            {
+                throw new IllegalArgumentException("error recovering public key");
+            }
+
+            byte[] keyEnc = key.getOctets();
+
+            if (keyInfo.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le))
+            {
+                reverseBytes(keyEnc);
+            }
+
+            DSTU4145Params dstuParams = DSTU4145Params.getInstance(keyInfo.getAlgorithm().getParameters());
+
+            ECDomainParameters ecDomain;
+            if (dstuParams.isNamedCurve())
+            {
+                ASN1ObjectIdentifier curveOid = dstuParams.getNamedCurve();
+
+                ecDomain = DSTU4145NamedCurves.getByOID(curveOid);
+            }
+            else
+            {
+                DSTU4145ECBinary binary = dstuParams.getECBinary();
+                byte[] b_bytes = binary.getB();
+                if (keyInfo.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le))
+                {
+                    reverseBytes(b_bytes);
+                }
+                DSTU4145BinaryField field = binary.getField();
+                ECCurve curve = new ECCurve.F2m(field.getM(), field.getK1(), field.getK2(), field.getK3(), binary.getA(), new BigInteger(1, b_bytes));
+                byte[] g_bytes = binary.getG();
+                if (keyInfo.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le))
+                {
+                    reverseBytes(g_bytes);
+                }
+                ecDomain = new ECDomainParameters(curve, DSTU4145PointEncoder.decodePoint(curve, g_bytes), binary.getN());
+            }
+
+            return new ECPublicKeyParameters(DSTU4145PointEncoder.decodePoint(ecDomain.getCurve(), keyEnc), ecDomain);
+        }
+
+        private void reverseBytes(byte[] bytes)
+        {
+            byte tmp;
+
+            for (int i = 0; i < bytes.length / 2; i++)
+            {
+                tmp = bytes[i];
+                bytes[i] = bytes[bytes.length - 1 - i];
+                bytes[bytes.length - 1 - i] = tmp;
+            }
+        }
+    }
+
+    private static class X25519Converter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+        {
+            return new X25519PublicKeyParameters(getRawKey(keyInfo, defaultParams, X25519PublicKeyParameters.KEY_SIZE), 0);
+        }
+    }
+
+    private static class X448Converter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+        {
+            return new X448PublicKeyParameters(getRawKey(keyInfo, defaultParams, X448PublicKeyParameters.KEY_SIZE), 0);
+        }
+    }
+
+    private static class Ed25519Converter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+        {
+            return new Ed25519PublicKeyParameters(getRawKey(keyInfo, defaultParams, Ed25519PublicKeyParameters.KEY_SIZE), 0);
+        }
+    }
+
+    private static class Ed448Converter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+        {
+            return new Ed448PublicKeyParameters(getRawKey(keyInfo, defaultParams, Ed448PublicKeyParameters.KEY_SIZE), 0);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    private static byte[] getRawKey(SubjectPublicKeyInfo keyInfo, Object defaultParams, int expectedSize)
+    {
+        /*
+         * TODO[RFC 8422]
+         * - Require defaultParams == null?
+         * - Require keyInfo.getAlgorithm().getParameters() == null?
+         */
+        byte[] result = keyInfo.getPublicKeyData().getOctets();
+        if (expectedSize != result.length)
+        {
+            throw new RuntimeException("public key encoding has incorrect length");
+        }
+        return result;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/iana/AEADAlgorithm.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/iana/AEADAlgorithm.java
new file mode 100644
index 0000000..e6ee599
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/iana/AEADAlgorithm.java
@@ -0,0 +1,59 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.iana;
+
+/**
+ * RFC 5116 
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AEADAlgorithm
+{
+    public static final int AEAD_AES_128_GCM = 1;
+    public static final int AEAD_AES_256_GCM = 2;
+    public static final int AEAD_AES_128_CCM = 3;
+    public static final int AEAD_AES_256_CCM = 4;
+
+    /*
+     * RFC 5282
+     */
+    public static final int AEAD_AES_128_GCM_8 = 5;
+    public static final int AEAD_AES_256_GCM_8 = 6;
+    public static final int AEAD_AES_128_GCM_12 = 7;
+    public static final int AEAD_AES_256_GCM_12 = 8;
+    public static final int AEAD_AES_128_CCM_SHORT = 9;
+    public static final int AEAD_AES_256_CCM_SHORT = 10;
+    public static final int AEAD_AES_128_CCM_SHORT_8 = 11;
+    public static final int AEAD_AES_256_CCM_SHORT_8 = 12;
+    public static final int AEAD_AES_128_CCM_SHORT_12 = 13;
+    public static final int AEAD_AES_256_CCM_SHORT_12 = 14;
+
+    /*
+     * RFC 5297
+     */
+    public static final int AEAD_AES_SIV_CMAC_256 = 15;
+    public static final int AEAD_AES_SIV_CMAC_384 = 16;
+    public static final int AEAD_AES_SIV_CMAC_512 = 17;
+
+    /*
+     * RFC 6655
+     */
+    public static final int AEAD_AES_128_CCM_8 = 18;
+    public static final int AEAD_AES_256_CCM_8 = 19;
+
+    /*
+     * RFC 7253
+     */
+    public static final int AEAD_AES_128_OCB_TAGLEN128 = 20;
+    public static final int AEAD_AES_128_OCB_TAGLEN96 = 21;
+    public static final int AEAD_AES_128_OCB_TAGLEN64 = 22;
+    public static final int AEAD_AES_192_OCB_TAGLEN128 = 23;
+    public static final int AEAD_AES_192_OCB_TAGLEN96 = 24;
+    public static final int AEAD_AES_192_OCB_TAGLEN64 = 25;
+    public static final int AEAD_AES_256_OCB_TAGLEN128 = 26;
+    public static final int AEAD_AES_256_OCB_TAGLEN96 = 27;
+    public static final int AEAD_AES_256_OCB_TAGLEN64 = 28;
+
+    /*
+     * RFC 7539
+     */
+    public static final int AEAD_CHACHA20_POLY1305 = 29;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PBKDFKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PBKDFKey.java
new file mode 100644
index 0000000..c3e1a0f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PBKDFKey.java
@@ -0,0 +1,13 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce;
+
+import javax.crypto.SecretKey;
+
+/**
+ * Base interface for keys associated with various password based key derivation functions (PBKDF).
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface PBKDFKey
+    extends SecretKey
+{
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKCS12Key.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKCS12Key.java
new file mode 100644
index 0000000..a6f6c71
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKCS12Key.java
@@ -0,0 +1,89 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce;
+
+import com.android.internal.org.bouncycastle.crypto.PBEParametersGenerator;
+
+/**
+ * A password based key for use with PKCS#12.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS12Key
+    implements PBKDFKey
+{
+    private final char[] password;
+    private final boolean useWrongZeroLengthConversion;
+    /**
+     * Basic constructor for a password based key - secret key generation parameters will be passed separately..
+     *
+     * @param password password to use.
+     */
+    public PKCS12Key(char[] password)
+    {
+        this(password, false);
+    }
+
+    /**
+     * Unfortunately there seems to be some confusion about how to handle zero length
+     * passwords.
+     *
+     * @param password password to use.
+     * @param useWrongZeroLengthConversion use the incorrect encoding approach (add pad bytes)
+     */
+    public PKCS12Key(char[] password, boolean useWrongZeroLengthConversion)
+    {
+        if (password == null)
+        {
+            password = new char[0];
+        }
+
+        this.password = new char[password.length];
+        this.useWrongZeroLengthConversion = useWrongZeroLengthConversion;
+
+        System.arraycopy(password, 0, this.password, 0, password.length);
+    }
+
+    /**
+     * Return a reference to the char[] array holding the password.
+     *
+     * @return a reference to the password array.
+     */
+    public char[] getPassword()
+    {
+        return password;
+    }
+
+    /**
+     * Return the password based key derivation function this key is for,
+     *
+     * @return the string "PKCS12"
+     */
+    public String getAlgorithm()
+    {
+        return "PKCS12";
+    }
+
+    /**
+     * Return the format encoding.
+     *
+     * @return the string "PKCS12", representing the char[] to byte[] conversion.
+     */
+    public String getFormat()
+    {
+        return "PKCS12";
+    }
+
+    /**
+     * Return the password converted to bytes.
+     *
+     * @return the password converted to a byte array.
+     */
+    public byte[] getEncoded()
+    {
+        if (useWrongZeroLengthConversion && password.length == 0)
+        {
+            return new byte[2];
+        }
+
+        return PBEParametersGenerator.PKCS12PasswordToBytes(password);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKCS12KeyWithParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKCS12KeyWithParameters.java
new file mode 100644
index 0000000..33dfa81
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKCS12KeyWithParameters.java
@@ -0,0 +1,71 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce;
+
+import javax.crypto.interfaces.PBEKey;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * A password based key for use with PKCS#12 with full PBE parameters.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS12KeyWithParameters
+    extends PKCS12Key
+    implements PBEKey
+{
+    private final byte[] salt;
+    private final int iterationCount;
+
+    /**
+     * Basic constructor for a password based key with generation parameters.
+     *
+     * @param password password to use.
+     * @param salt salt for generation algorithm
+     * @param iterationCount iteration count for generation algorithm.
+     */
+    public PKCS12KeyWithParameters(char[] password, byte[] salt, int iterationCount)
+    {
+        super(password);
+
+        this.salt = Arrays.clone(salt);
+        this.iterationCount = iterationCount;
+    }
+
+
+    /**
+     * Basic constructor for a password based key with generation parameters, specifying the wrong conversion for
+     * zero length passwords.
+     *
+     * @param password password to use.
+     * @param salt salt for generation algorithm
+     * @param iterationCount iteration count for generation algorithm.
+     * @param useWrongZeroLengthConversion use the incorrect encoding approach (add pad bytes)
+     */
+    public PKCS12KeyWithParameters(char[] password, boolean useWrongZeroLengthConversion, byte[] salt, int iterationCount)
+    {
+        super(password, useWrongZeroLengthConversion);
+
+        this.salt = Arrays.clone(salt);
+        this.iterationCount = iterationCount;
+    }
+
+    /**
+     * Return the salt to use in the key derivation function.
+     *
+     * @return the salt to use in the KDF.
+     */
+    public byte[] getSalt()
+    {
+        return salt;
+    }
+
+    /**
+     * Return the iteration count to use in the key derivation function.
+     *
+     * @return the iteration count to use in the KDF.
+     */
+    public int getIterationCount()
+    {
+        return iterationCount;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKCS12StoreParameter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKCS12StoreParameter.java
new file mode 100644
index 0000000..615cbbb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKCS12StoreParameter.java
@@ -0,0 +1,64 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce;
+
+import java.io.OutputStream;
+import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.ProtectionParameter;
+
+/**
+ * LoadStoreParameter to allow for additional config with PKCS12 files.
+ * <p>
+ * Note: if you want a straight DER encoding of a PKCS#12 file you should use this.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS12StoreParameter
+    implements LoadStoreParameter
+{
+    private final OutputStream out;
+    private final ProtectionParameter protectionParameter;
+    private final boolean forDEREncoding;
+
+    public PKCS12StoreParameter(OutputStream out, char[] password)
+    {
+        this(out, password, false);
+    }
+
+    public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter)
+    {
+        this(out, protectionParameter, false);
+    }
+
+    public PKCS12StoreParameter(OutputStream out, char[] password, boolean forDEREncoding)
+    {
+        this(out, new KeyStore.PasswordProtection(password), forDEREncoding);
+    }
+
+    public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter, boolean forDEREncoding)
+    {
+        this.out = out;
+        this.protectionParameter = protectionParameter;
+        this.forDEREncoding = forDEREncoding;
+    }
+
+    public OutputStream getOutputStream()
+    {
+        return out;
+    }
+
+    public ProtectionParameter getProtectionParameter()
+    {
+        return protectionParameter;
+    }
+
+    /**
+     * Return whether the KeyStore used with this parameter should be DER encoded on saving.
+     *
+     * @return true for straight DER encoding, false otherwise,
+     */
+    public boolean isForDEREncoding()
+    {
+        return forDEREncoding;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCRLStore.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCRLStore.java
new file mode 100644
index 0000000..add2781
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCRLStore.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce;
+
+import java.security.cert.CRL;
+import java.util.Collection;
+
+import com.android.internal.org.bouncycastle.util.Selector;
+import com.android.internal.org.bouncycastle.util.Store;
+import com.android.internal.org.bouncycastle.util.StoreException;
+
+/**
+ * Generic interface for a PKIX based CRL store.
+ *
+ * @param <T> the CRL type.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface PKIXCRLStore<T extends CRL>
+    extends Store<T>
+{
+    /**
+     * Return the matches associated with the passed in selector.
+     *
+     * @param selector the selector defining the match criteria.
+     * @return a collection of matches with the selector, an empty selector if there are none.
+     * @throws StoreException in the event of an issue doing a match.
+     */
+    Collection<T> getMatches(Selector<T> selector)
+        throws StoreException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCRLStoreSelector.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCRLStoreSelector.java
new file mode 100644
index 0000000..86c3825
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCRLStoreSelector.java
@@ -0,0 +1,350 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce;
+
+import java.math.BigInteger;
+import java.security.cert.CRL;
+import java.security.cert.CRLSelector;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLSelector;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Selector;
+
+/**
+ * This class is a Selector implementation for X.509 certificate revocation
+ * lists.
+ * 
+ * @see com.android.internal.org.bouncycastle.util.Selector
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKIXCRLStoreSelector<T extends CRL>
+    implements Selector<T>
+{
+    /**
+     * Builder for a PKIXCRLStoreSelector.
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Builder
+    {
+        private final CRLSelector baseSelector;
+
+        private boolean deltaCRLIndicator = false;
+        private boolean completeCRLEnabled = false;
+        private BigInteger maxBaseCRLNumber = null;
+        private byte[] issuingDistributionPoint = null;
+        private boolean issuingDistributionPointEnabled = false;
+
+        /**
+         * Constructor initializing a builder with a CertSelector.
+         *
+         * @param crlSelector the CertSelector to copy the match details from.
+         */
+        public Builder(CRLSelector crlSelector)
+        {
+            this.baseSelector = (CRLSelector)crlSelector.clone();
+        }
+
+
+        /**
+         * If set to <code>true</code> only complete CRLs are returned.
+         * <p>
+         * {@link #setCompleteCRLEnabled(boolean)} and
+         * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+         *
+         * @param completeCRLEnabled <code>true</code> if only complete CRLs
+         *            should be returned.
+         */
+        public Builder setCompleteCRLEnabled(boolean completeCRLEnabled)
+        {
+            this.completeCRLEnabled = completeCRLEnabled;
+
+            return this;
+        }
+
+        /**
+         * If this is set to <code>true</code> the CRL reported contains the delta
+         * CRL indicator CRL extension.
+         * <p>
+         * {@link #setCompleteCRLEnabled(boolean)} and
+         * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+         *
+         * @param deltaCRLIndicator <code>true</code> if the delta CRL indicator
+         *            extension must be in the CRL.
+         */
+        public Builder setDeltaCRLIndicatorEnabled(boolean deltaCRLIndicator)
+        {
+            this.deltaCRLIndicator = deltaCRLIndicator;
+
+            return this;
+        }
+
+        /**
+         * Sets the maximum base CRL number. Setting to <code>null</code> disables
+         * this cheack.
+         * <p>
+         * This is only meaningful for delta CRLs. Complete CRLs must have a CRL
+         * number which is greater or equal than the base number of the
+         * corresponding CRL.
+         *
+         * @param maxBaseCRLNumber The maximum base CRL number to set.
+         */
+        public void setMaxBaseCRLNumber(BigInteger maxBaseCRLNumber)
+        {
+            this.maxBaseCRLNumber = maxBaseCRLNumber;
+        }
+
+        /**
+         * Enables or disables the issuing distribution point check.
+         *
+         * @param issuingDistributionPointEnabled <code>true</code> to enable the
+         *            issuing distribution point check.
+         */
+        public void setIssuingDistributionPointEnabled(
+            boolean issuingDistributionPointEnabled)
+        {
+            this.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+        }
+
+        /**
+         * Sets the issuing distribution point.
+         * <p>
+         * The issuing distribution point extension is a CRL extension which
+         * identifies the scope and the distribution point of a CRL. The scope
+         * contains among others information about revocation reasons contained in
+         * the CRL. Delta CRLs and complete CRLs must have matching issuing
+         * distribution points.
+         * <p>
+         * The byte array is cloned to protect against subsequent modifications.
+         * <p>
+         * You must also enable or disable this criteria with
+         * {@link #setIssuingDistributionPointEnabled(boolean)}.
+         *
+         * @param issuingDistributionPoint The issuing distribution point to set.
+         *            This is the DER encoded OCTET STRING extension value.
+         * @see #getIssuingDistributionPoint()
+         */
+        public void setIssuingDistributionPoint(byte[] issuingDistributionPoint)
+        {
+            this.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+        }
+
+        /**
+         * Build a selector.
+         *
+         * @return a new PKIXCRLStoreSelector
+         */
+        public PKIXCRLStoreSelector<? extends CRL> build()
+        {
+            return new PKIXCRLStoreSelector(this);
+        }
+    }
+
+    private final CRLSelector baseSelector;
+    private final boolean deltaCRLIndicator;
+    private final boolean completeCRLEnabled;
+    private final BigInteger maxBaseCRLNumber;
+    private final byte[] issuingDistributionPoint;
+    private final boolean issuingDistributionPointEnabled;
+
+    private PKIXCRLStoreSelector(Builder baseBuilder)
+    {
+        this.baseSelector = baseBuilder.baseSelector;
+        this.deltaCRLIndicator = baseBuilder.deltaCRLIndicator;
+        this.completeCRLEnabled = baseBuilder.completeCRLEnabled;
+        this.maxBaseCRLNumber = baseBuilder.maxBaseCRLNumber;
+        this.issuingDistributionPoint = baseBuilder.issuingDistributionPoint;
+        this.issuingDistributionPointEnabled = baseBuilder.issuingDistributionPointEnabled;
+    }
+
+
+    /**
+     * Returns if the issuing distribution point criteria should be applied.
+     * Defaults to <code>false</code>.
+     * <p>
+     * You may also set the issuing distribution point criteria if not a missing
+     * issuing distribution point should be assumed.
+     * 
+     * @return Returns if the issuing distribution point check is enabled.
+     */
+    public boolean isIssuingDistributionPointEnabled()
+    {
+        return issuingDistributionPointEnabled;
+    }
+
+
+
+    public boolean match(CRL obj)
+    {
+        if (!(obj instanceof X509CRL))
+        {
+            return baseSelector.match(obj);
+        }
+
+        X509CRL crl = (X509CRL)obj;
+        ASN1Integer dci = null;
+        try
+        {
+            byte[] bytes = crl
+                .getExtensionValue(Extension.deltaCRLIndicator.getId());
+            if (bytes != null)
+            {
+                dci = ASN1Integer.getInstance(ASN1OctetString.getInstance(bytes).getOctets());
+            }
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+        if (isDeltaCRLIndicatorEnabled())
+        {
+            if (dci == null)
+            {
+                return false;
+            }
+        }
+        if (isCompleteCRLEnabled())
+        {
+            if (dci != null)
+            {
+                return false;
+            }
+        }
+        if (dci != null)
+        {
+
+            if (maxBaseCRLNumber != null)
+            {
+                if (dci.getPositiveValue().compareTo(maxBaseCRLNumber) == 1)
+                {
+                    return false;
+                }
+            }
+        }
+        if (issuingDistributionPointEnabled)
+        {
+            byte[] idp = crl
+                .getExtensionValue(Extension.issuingDistributionPoint
+                    .getId());
+            if (issuingDistributionPoint == null)
+            {
+                if (idp != null)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                if (!Arrays.areEqual(idp, issuingDistributionPoint))
+                {
+                    return false;
+                }
+            }
+
+        }
+        return baseSelector.match(obj);
+    }
+
+    /**
+     * Returns if this selector must match CRLs with the delta CRL indicator
+     * extension set. Defaults to <code>false</code>.
+     * 
+     * @return Returns <code>true</code> if only CRLs with the delta CRL
+     *         indicator extension are selected.
+     */
+    public boolean isDeltaCRLIndicatorEnabled()
+    {
+        return deltaCRLIndicator;
+    }
+
+    public Object clone()
+    {
+        return this;
+    }
+
+    /**
+     * If <code>true</code> only complete CRLs are returned. Defaults to
+     * <code>false</code>.
+     * 
+     * @return <code>true</code> if only complete CRLs are returned.
+     */
+    public boolean isCompleteCRLEnabled()
+    {
+        return completeCRLEnabled;
+    }
+
+    /**
+     * Get the maximum base CRL number. Defaults to <code>null</code>.
+     * 
+     * @return Returns the maximum base CRL number.
+     */
+    public BigInteger getMaxBaseCRLNumber()
+    {
+        return maxBaseCRLNumber;
+    }
+
+
+    /**
+     * Returns the issuing distribution point. Defaults to <code>null</code>,
+     * which is a missing issuing distribution point extension.
+     * <p>
+     * The internal byte array is cloned before it is returned.
+     * <p>
+     * The criteria must be enable with Builder.setIssuingDistributionPointEnabled(boolean)}.
+     * 
+     * @return Returns the issuing distribution point.
+     */
+    public byte[] getIssuingDistributionPoint()
+    {
+        return Arrays.clone(issuingDistributionPoint);
+    }
+
+    public X509Certificate getCertificateChecking()
+    {
+        if (baseSelector instanceof X509CRLSelector)
+        {
+            return ((X509CRLSelector)baseSelector).getCertificateChecking();
+        }
+
+        return null;
+    }
+
+    public static Collection<? extends CRL> getCRLs(final PKIXCRLStoreSelector selector, CertStore certStore)
+        throws CertStoreException
+    {
+        return certStore.getCRLs(new SelectorClone(selector));
+    }
+
+    private static class SelectorClone
+        extends X509CRLSelector
+    {
+        private final PKIXCRLStoreSelector selector;
+
+        SelectorClone(PKIXCRLStoreSelector selector)
+        {
+            this.selector = selector;
+
+            if (selector.baseSelector instanceof X509CRLSelector)
+            {
+                X509CRLSelector baseSelector = (X509CRLSelector)selector.baseSelector;
+
+                this.setCertificateChecking(baseSelector.getCertificateChecking());
+                this.setDateAndTime(baseSelector.getDateAndTime());
+                this.setIssuers(baseSelector.getIssuers());
+                this.setMinCRLNumber(baseSelector.getMinCRL());
+                this.setMaxCRLNumber(baseSelector.getMaxCRL());
+            }
+        }
+
+        public boolean match(CRL crl)
+        {
+            return (selector == null) ? (crl != null) : selector.match(crl);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCertStore.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCertStore.java
new file mode 100644
index 0000000..113e098
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCertStore.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce;
+
+import java.security.cert.Certificate;
+import java.util.Collection;
+
+import com.android.internal.org.bouncycastle.util.Selector;
+import com.android.internal.org.bouncycastle.util.Store;
+import com.android.internal.org.bouncycastle.util.StoreException;
+
+/**
+ * Generic interface for a PKIX based certificate store.
+ *
+ * @param <T> the certificate type.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface PKIXCertStore<T extends Certificate>
+    extends Store<T>
+{
+    /**
+     * Return the matches associated with the passed in selector.
+     *
+     * @param selector the selector defining the match criteria.
+     * @return a collection of matches with the selector, an empty selector if there are none.
+     * @throws StoreException in the event of an issue doing a match.
+     */
+    Collection<T> getMatches(Selector<T> selector)
+        throws StoreException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCertStoreSelector.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCertStoreSelector.java
new file mode 100644
index 0000000..ba68cc6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXCertStoreSelector.java
@@ -0,0 +1,122 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce;
+
+import java.io.IOException;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.X509CertSelector;
+import java.util.Collection;
+
+import com.android.internal.org.bouncycastle.util.Selector;
+
+/**
+ * This class is a Selector implementation for certificates.
+ * 
+ * @see com.android.internal.org.bouncycastle.util.Selector
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKIXCertStoreSelector<T extends Certificate>
+    implements Selector<T>
+{
+    /**
+     * Builder for a PKIXCertStoreSelector.
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Builder
+    {
+        private final CertSelector baseSelector;
+
+        /**
+         * Constructor initializing a builder with a CertSelector.
+         *
+         * @param certSelector the CertSelector to copy the match details from.
+         */
+        public Builder(CertSelector certSelector)
+        {
+            this.baseSelector = (CertSelector)certSelector.clone();
+        }
+
+        /**
+         * Build a selector.
+         *
+         * @return a new PKIXCertStoreSelector
+         */
+        public PKIXCertStoreSelector<? extends Certificate> build()
+        {
+            return new PKIXCertStoreSelector(baseSelector);
+        }
+    }
+
+    private final CertSelector baseSelector;
+
+    private PKIXCertStoreSelector(CertSelector baseSelector)
+    {
+        this.baseSelector = baseSelector;
+    }
+
+    public boolean match(Certificate cert)
+    {
+        return baseSelector.match(cert);
+    }
+
+    public Object clone()
+    {
+        return new PKIXCertStoreSelector(baseSelector);
+    }
+
+    public static Collection<? extends Certificate> getCertificates(final PKIXCertStoreSelector selector, CertStore certStore)
+        throws CertStoreException
+    {
+        return certStore.getCertificates(new SelectorClone(selector));
+    }
+
+    private static class SelectorClone
+        extends X509CertSelector
+    {
+        private final PKIXCertStoreSelector selector;
+
+        SelectorClone(PKIXCertStoreSelector selector)
+        {
+            this.selector = selector;
+
+            if (selector.baseSelector instanceof X509CertSelector)
+            {
+                X509CertSelector baseSelector = (X509CertSelector)selector.baseSelector;
+
+                this.setAuthorityKeyIdentifier(baseSelector.getAuthorityKeyIdentifier());
+                this.setBasicConstraints(baseSelector.getBasicConstraints());
+                this.setCertificate(baseSelector.getCertificate());
+                this.setCertificateValid(baseSelector.getCertificateValid());
+                this.setKeyUsage(baseSelector.getKeyUsage());
+                this.setMatchAllSubjectAltNames(baseSelector.getMatchAllSubjectAltNames());
+                this.setPrivateKeyValid(baseSelector.getPrivateKeyValid());
+                this.setSerialNumber(baseSelector.getSerialNumber());
+                this.setSubjectKeyIdentifier(baseSelector.getSubjectKeyIdentifier());
+                this.setSubjectPublicKey(baseSelector.getSubjectPublicKey());
+
+                try
+                {
+                    this.setExtendedKeyUsage(baseSelector.getExtendedKeyUsage());
+                    this.setIssuer(baseSelector.getIssuerAsBytes());
+                    this.setNameConstraints(baseSelector.getNameConstraints());
+                    this.setPathToNames(baseSelector.getPathToNames());
+                    this.setPolicy(baseSelector.getPolicy());
+                    this.setSubject(baseSelector.getSubjectAsBytes());
+                    this.setSubjectAlternativeNames(baseSelector.getSubjectAlternativeNames());
+                    this.setSubjectPublicKeyAlgID(baseSelector.getSubjectPublicKeyAlgID());
+                }
+                catch (IOException e)
+                {
+                    throw new IllegalStateException("base selector invalid: " + e.getMessage(), e);
+                }
+            }
+        }
+
+        public boolean match(Certificate certificate)
+        {
+            return (selector == null) ? (certificate != null) : selector.match(certificate);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXExtendedBuilderParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXExtendedBuilderParameters.java
new file mode 100644
index 0000000..9708b7e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXExtendedBuilderParameters.java
@@ -0,0 +1,144 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce;
+
+import java.security.InvalidParameterException;
+import java.security.cert.CertPathParameters;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class contains extended parameters for PKIX certification path builders.
+ * 
+ * @see PKIXBuilderParameters
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKIXExtendedBuilderParameters
+    implements CertPathParameters
+{
+    /**
+     * Builder for a PKIXExtendedBuilderParameters object.
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Builder
+    {
+        private final PKIXExtendedParameters baseParameters;
+
+        private int maxPathLength = 5;
+        private Set<X509Certificate> excludedCerts = new HashSet<X509Certificate>();
+
+        public Builder(PKIXBuilderParameters baseParameters)
+        {
+            this.baseParameters = new PKIXExtendedParameters.Builder(baseParameters).build();
+            this.maxPathLength = baseParameters.getMaxPathLength();
+        }
+
+        public Builder(PKIXExtendedParameters baseParameters)
+        {
+            this.baseParameters = baseParameters;
+        }
+
+        /**
+         * Adds excluded certificates which are not used for building a
+         * certification path.
+         * <p>
+         * The given set is cloned to protect it against subsequent modifications.
+         *
+         * @param excludedCerts The excluded certificates to set.
+         */
+        public Builder addExcludedCerts(Set<X509Certificate> excludedCerts)
+        {
+            this.excludedCerts.addAll(excludedCerts);
+
+            return this;
+        }
+
+        /**
+         * Sets the maximum number of intermediate non-self-issued certificates in a
+         * certification path. The PKIX <code>CertPathBuilder</code> must not
+         * build paths longer then this length.
+         * <p>
+         * A value of 0 implies that the path can only contain a single certificate.
+         * A value of -1 does not limit the length. The default length is 5.
+         *
+         * <p>
+         *
+         * The basic constraints extension of a CA certificate overrides this value
+         * if smaller.
+         *
+         * @param maxPathLength the maximum number of non-self-issued intermediate
+         *            certificates in the certification path
+         * @throws InvalidParameterException if <code>maxPathLength</code> is set
+         *             to a value less than -1
+         *
+         * @see #getMaxPathLength
+         */
+        public Builder setMaxPathLength(int maxPathLength)
+        {
+            if (maxPathLength < -1)
+            {
+                throw new InvalidParameterException("The maximum path "
+                        + "length parameter can not be less than -1.");
+            }
+            this.maxPathLength = maxPathLength;
+
+            return this;
+        }
+
+        public PKIXExtendedBuilderParameters build()
+        {
+            return new PKIXExtendedBuilderParameters(this);
+        }
+    }
+
+    private final PKIXExtendedParameters baseParameters;
+    private final Set<X509Certificate> excludedCerts;
+    private final int maxPathLength;
+
+    private PKIXExtendedBuilderParameters(Builder builder)
+    {
+        this.baseParameters = builder.baseParameters;
+        this.excludedCerts = Collections.unmodifiableSet(builder.excludedCerts);
+        this.maxPathLength = builder.maxPathLength;
+    }
+
+    public PKIXExtendedParameters getBaseParameters()
+    {
+        return baseParameters;
+    }
+
+    /**
+     * Excluded certificates are not used for building a certification path.
+     * <p>
+     * The returned set is immutable.
+     * 
+     * @return Returns the excluded certificates.
+     */
+    public Set getExcludedCerts()
+    {
+        return excludedCerts;
+    }
+
+    /**
+     * Returns the value of the maximum number of intermediate non-self-issued
+     * certificates in the certification path.
+     * 
+     * @return the maximum number of non-self-issued intermediate certificates
+     *         in the certification path, or -1 if no limit exists.
+     */
+    public int getMaxPathLength()
+    {
+        return maxPathLength;
+    }
+
+    /**
+     * @return this object
+     */
+    public Object clone()
+    {
+        return this;
+    }
+}
+
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXExtendedParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXExtendedParameters.java
new file mode 100644
index 0000000..6838536
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/PKIXExtendedParameters.java
@@ -0,0 +1,347 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce;
+
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+
+/**
+ * This class extends the PKIXParameters with a validity model parameter.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKIXExtendedParameters
+    implements CertPathParameters
+{
+    /**
+     * This is the default PKIX validity model. Actually there are two variants
+     * of this: The PKIX model and the modified PKIX model. The PKIX model
+     * verifies that all involved certificates must have been valid at the
+     * current time. The modified PKIX model verifies that all involved
+     * certificates were valid at the signing time. Both are indirectly choosen
+     * with the {@link PKIXParameters#setDate(Date)} method, so this
+     * methods sets the Date when <em>all</em> certificates must have been
+     * valid.
+     */
+    public static final int PKIX_VALIDITY_MODEL = 0;
+
+    /**
+     * This model uses the following validity model. Each certificate must have
+     * been valid at the moment where is was used. That means the end
+     * certificate must have been valid at the time the signature was done. The
+     * CA certificate which signed the end certificate must have been valid,
+     * when the end certificate was signed. The CA (or Root CA) certificate must
+     * have been valid, when the CA certificate was signed and so on. So the
+     * {@link PKIXParameters#setDate(Date)} method sets the time, when
+     * the <em>end certificate</em> must have been valid. It is used e.g.
+     * in the German signature law.
+     */
+    public static final int CHAIN_VALIDITY_MODEL = 1;
+
+    /**
+     * Builder for a PKIXExtendedParameters object.
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Builder
+    {
+        private final PKIXParameters baseParameters;
+        private final Date date;
+
+        private PKIXCertStoreSelector targetConstraints;
+        private List<PKIXCertStore> extraCertStores = new ArrayList<PKIXCertStore>();
+        private Map<GeneralName, PKIXCertStore> namedCertificateStoreMap = new HashMap<GeneralName, PKIXCertStore>();
+        private List<PKIXCRLStore> extraCRLStores = new ArrayList<PKIXCRLStore>();
+        private Map<GeneralName, PKIXCRLStore> namedCRLStoreMap = new HashMap<GeneralName, PKIXCRLStore>();
+        private boolean revocationEnabled;
+        private int validityModel = PKIX_VALIDITY_MODEL;
+        private boolean useDeltas = false;
+        private Set<TrustAnchor> trustAnchors;
+
+        public Builder(PKIXParameters baseParameters)
+        {
+            this.baseParameters = (PKIXParameters)baseParameters.clone();
+            CertSelector constraints = baseParameters.getTargetCertConstraints();
+            if (constraints != null)
+            {
+                this.targetConstraints = new PKIXCertStoreSelector.Builder(constraints).build();
+            }
+            Date checkDate = baseParameters.getDate();
+            this.date = (checkDate == null) ? new Date() : checkDate;
+            this.revocationEnabled = baseParameters.isRevocationEnabled();
+            this.trustAnchors = baseParameters.getTrustAnchors();
+        }
+
+        public Builder(PKIXExtendedParameters baseParameters)
+        {
+            this.baseParameters = baseParameters.baseParameters;
+            this.date = baseParameters.date;
+            this.targetConstraints = baseParameters.targetConstraints;
+            this.extraCertStores = new ArrayList<PKIXCertStore>(baseParameters.extraCertStores);
+            this.namedCertificateStoreMap = new HashMap<GeneralName, PKIXCertStore>(baseParameters.namedCertificateStoreMap);
+            this.extraCRLStores = new ArrayList<PKIXCRLStore>(baseParameters.extraCRLStores);
+            this.namedCRLStoreMap = new HashMap<GeneralName, PKIXCRLStore>(baseParameters.namedCRLStoreMap);
+            this.useDeltas = baseParameters.useDeltas;
+            this.validityModel = baseParameters.validityModel;
+            this.revocationEnabled = baseParameters.isRevocationEnabled();
+            this.trustAnchors = baseParameters.getTrustAnchors();
+        }
+
+        public Builder addCertificateStore(PKIXCertStore store)
+        {
+            extraCertStores.add(store);
+
+            return this;
+        }
+
+        public Builder addNamedCertificateStore(GeneralName issuerAltName, PKIXCertStore store)
+        {
+            namedCertificateStoreMap.put(issuerAltName, store);
+
+            return this;
+        }
+
+        public Builder addCRLStore(PKIXCRLStore store)
+        {
+            extraCRLStores.add(store);
+
+            return this;
+        }
+
+        public Builder addNamedCRLStore(GeneralName issuerAltName, PKIXCRLStore store)
+        {
+            namedCRLStoreMap.put(issuerAltName, store);
+
+            return this;
+        }
+
+        public Builder setTargetConstraints(PKIXCertStoreSelector selector)
+        {
+            targetConstraints = selector;
+
+            return this;
+        }
+
+        /**
+         * Sets if delta CRLs should be used for checking the revocation status.
+         *
+         * @param useDeltas <code>true</code> if delta CRLs should be used.
+         */
+        public Builder setUseDeltasEnabled(boolean useDeltas)
+        {
+            this.useDeltas = useDeltas;
+
+            return this;
+        }
+
+        /**
+         * @param validityModel The validity model to set.
+         * @see #CHAIN_VALIDITY_MODEL
+         * @see #PKIX_VALIDITY_MODEL
+         */
+        public Builder setValidityModel(int validityModel)
+        {
+            this.validityModel = validityModel;
+
+            return this;
+        }
+
+        /**
+         * Set the trustAnchor to be used with these parameters.
+         *
+         * @param trustAnchor the trust anchor end-entity and CRLs must be based on.
+         * @return the current builder.
+         */
+        public Builder setTrustAnchor(TrustAnchor trustAnchor)
+        {
+            this.trustAnchors = Collections.singleton(trustAnchor);
+
+            return this;
+        }
+
+        /**
+         * Set the set of trustAnchors to be used with these parameters.
+         *
+         * @param trustAnchors  a set of trustAnchors, one of which a particular end-entity and it's associated CRLs must be based on.
+         * @return the current builder.
+         */
+        public Builder setTrustAnchors(Set<TrustAnchor> trustAnchors)
+        {
+            this.trustAnchors = trustAnchors;
+
+            return this;
+        }
+
+        /**
+         * Flag whether or not revocation checking is to be enabled.
+         *
+         * @param revocationEnabled  true if revocation checking to be enabled, false otherwise.
+         */
+        public void setRevocationEnabled(boolean revocationEnabled)
+        {
+            this.revocationEnabled = revocationEnabled;
+        }
+
+        public PKIXExtendedParameters build()
+        {
+            return new PKIXExtendedParameters(this);
+        }
+    }
+
+    private final PKIXParameters baseParameters;
+    private final PKIXCertStoreSelector targetConstraints;
+    private final Date date;
+    private final List<PKIXCertStore> extraCertStores;
+    private final Map<GeneralName, PKIXCertStore> namedCertificateStoreMap;
+    private final List<PKIXCRLStore> extraCRLStores;
+    private final Map<GeneralName, PKIXCRLStore> namedCRLStoreMap;
+    private final boolean revocationEnabled;
+    private final boolean useDeltas;
+    private final int validityModel;
+    private final Set<TrustAnchor> trustAnchors;
+
+    private PKIXExtendedParameters(Builder builder)
+    {
+        this.baseParameters = builder.baseParameters;
+        this.date = builder.date;
+        this.extraCertStores = Collections.unmodifiableList(builder.extraCertStores);
+        this.namedCertificateStoreMap = Collections.unmodifiableMap(new HashMap<GeneralName, PKIXCertStore>(builder.namedCertificateStoreMap));
+        this.extraCRLStores = Collections.unmodifiableList(builder.extraCRLStores);
+        this.namedCRLStoreMap = Collections.unmodifiableMap(new HashMap<GeneralName, PKIXCRLStore>(builder.namedCRLStoreMap));
+        this.targetConstraints = builder.targetConstraints;
+        this.revocationEnabled = builder.revocationEnabled;
+        this.useDeltas = builder.useDeltas;
+        this.validityModel = builder.validityModel;
+        this.trustAnchors = Collections.unmodifiableSet(builder.trustAnchors);
+    }
+
+    public List<PKIXCertStore> getCertificateStores()
+    {
+        return extraCertStores;
+    }
+
+
+    public Map<GeneralName, PKIXCertStore> getNamedCertificateStoreMap()
+    {
+        return namedCertificateStoreMap;
+    }
+
+    public List<PKIXCRLStore> getCRLStores()
+    {
+        return extraCRLStores;
+    }
+
+    public Map<GeneralName, PKIXCRLStore> getNamedCRLStoreMap()
+    {
+        return namedCRLStoreMap;
+    }
+
+    public Date getDate()
+    {
+        return new Date(date.getTime());
+    }
+
+
+
+
+    /**
+     * Defaults to <code>false</code>.
+     *
+     * @return Returns if delta CRLs should be used.
+     */
+    public boolean isUseDeltasEnabled()
+    {
+        return useDeltas;
+    }
+
+
+
+    /**
+     * @return Returns the validity model.
+     * @see #CHAIN_VALIDITY_MODEL
+     * @see #PKIX_VALIDITY_MODEL
+     */
+    public int getValidityModel()
+    {
+        return validityModel;
+    }
+
+    public Object clone()
+    {
+        return this;
+    }
+
+    /**
+     * Returns the required constraints on the target certificate.
+     * The constraints are returned as an instance of
+     * <code>Selector</code>. If <code>null</code>, no constraints are
+     * defined.
+     *
+     * @return a <code>Selector</code> specifying the constraints on the
+     *         target certificate or attribute certificate (or <code>null</code>)
+     * @see PKIXCertStoreSelector
+     */
+    public PKIXCertStoreSelector getTargetConstraints()
+    {
+        return targetConstraints;
+    }
+
+    public Set getTrustAnchors()
+    {
+        return trustAnchors;
+    }
+
+    public Set getInitialPolicies()
+    {
+        return baseParameters.getInitialPolicies();
+    }
+
+    public String getSigProvider()
+    {
+        return baseParameters.getSigProvider();
+    }
+
+    public boolean isExplicitPolicyRequired()
+    {
+        return baseParameters.isExplicitPolicyRequired();
+    }
+
+    public boolean isAnyPolicyInhibited()
+    {
+        return baseParameters.isAnyPolicyInhibited();
+    }
+
+    public boolean isPolicyMappingInhibited()
+    {
+        return baseParameters.isPolicyMappingInhibited();
+    }
+
+    public List getCertPathCheckers()
+    {
+        return baseParameters.getCertPathCheckers();
+    }
+
+    public List<CertStore> getCertStores()
+    {
+        return baseParameters.getCertStores();
+    }
+
+    public boolean isRevocationEnabled()
+    {
+        return revocationEnabled;
+    }
+
+    public boolean getPolicyQualifiersRejected()
+    {
+        return baseParameters.getPolicyQualifiersRejected();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/DigestUpdatingOutputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/DigestUpdatingOutputStream.java
new file mode 100644
index 0000000..49233e4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/DigestUpdatingOutputStream.java
@@ -0,0 +1,35 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.MessageDigest;
+
+class DigestUpdatingOutputStream
+    extends OutputStream
+{
+    private MessageDigest digest;
+
+    DigestUpdatingOutputStream(MessageDigest digest)
+    {
+        this.digest = digest;
+    }
+
+    public void write(byte[] bytes, int off, int len)
+        throws IOException
+    {
+        digest.update(bytes, off, len);
+    }
+
+    public void write(byte[] bytes)
+        throws IOException
+    {
+        digest.update(bytes);
+    }
+
+    public void write(int b)
+        throws IOException
+    {
+        digest.update((byte)b);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/MacUpdatingOutputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/MacUpdatingOutputStream.java
new file mode 100644
index 0000000..49ab8d4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/MacUpdatingOutputStream.java
@@ -0,0 +1,36 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.crypto.Mac;
+
+class MacUpdatingOutputStream
+    extends OutputStream
+{
+    private Mac mac;
+
+    MacUpdatingOutputStream(Mac mac)
+    {
+        this.mac = mac;
+    }
+
+    public void write(byte[] bytes, int off, int len)
+        throws IOException
+    {
+        mac.update(bytes, off, len);
+    }
+
+    public void write(byte[] bytes)
+        throws IOException
+    {
+        mac.update(bytes);
+    }
+
+    public void write(int b)
+        throws IOException
+    {
+        mac.update((byte)b);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/OutputStreamFactory.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/OutputStreamFactory.java
new file mode 100644
index 0000000..ea73d46
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/OutputStreamFactory.java
@@ -0,0 +1,48 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.io;
+
+import java.io.OutputStream;
+import java.security.MessageDigest;
+import java.security.Signature;
+
+import javax.crypto.Mac;
+
+/**
+ * Utility class for creating OutputStreams from different JCA/JCE operators.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class OutputStreamFactory
+{
+    /**
+     * Create an OutputStream that wraps a signature.
+     *
+     * @param signature the signature to be updated as the stream is written to.
+     * @return an OutputStream.
+     */
+    public static OutputStream createStream(Signature signature)
+    {
+        return new SignatureUpdatingOutputStream(signature);
+    }
+
+    /**
+     * Create an OutputStream that wraps a digest.
+     *
+     * @param digest the digest to be updated as the stream is written to.
+     * @return an OutputStream.
+     */
+    public static OutputStream createStream(MessageDigest digest)
+    {
+        return new DigestUpdatingOutputStream(digest);
+    }
+
+    /**
+     * Create an OutputStream that wraps a mac.
+     *
+     * @param mac the signature to be updated as the stream is written to.
+     * @return an OutputStream.
+     */
+    public static OutputStream createStream(Mac mac)
+    {
+        return new MacUpdatingOutputStream(mac);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/SignatureUpdatingOutputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/SignatureUpdatingOutputStream.java
new file mode 100644
index 0000000..8127e4d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/io/SignatureUpdatingOutputStream.java
@@ -0,0 +1,57 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.Signature;
+import java.security.SignatureException;
+
+class SignatureUpdatingOutputStream
+    extends OutputStream
+{
+    private Signature sig;
+
+    SignatureUpdatingOutputStream(Signature sig)
+    {
+        this.sig = sig;
+    }
+
+    public void write(byte[] bytes, int off, int len)
+        throws IOException
+    {
+        try
+        {
+            sig.update(bytes, off, len);
+        }
+        catch (SignatureException e)
+        {
+            throw new IOException(e.getMessage());
+        }
+    }
+
+    public void write(byte[] bytes)
+        throws IOException
+    {
+        try
+        {
+            sig.update(bytes);
+        }
+        catch (SignatureException e)
+        {
+            throw new IOException(e.getMessage());
+        }
+    }
+
+    public void write(int b)
+        throws IOException
+    {
+        try
+        {
+            sig.update((byte)b);
+        }
+        catch (SignatureException e)
+        {
+            throw new IOException(e.getMessage());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/DH.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/DH.java
new file mode 100644
index 0000000..3529d21
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/DH.java
@@ -0,0 +1,109 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dh.KeyFactorySpi;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DH
+{
+    private static final String PREFIX = "com.android.internal.org.bouncycastle.jcajce.provider.asymmetric" + ".dh.";
+
+    private static final Map<String, String> generalDhAttributes = new HashMap<String, String>();
+
+    static
+    {
+        generalDhAttributes.put("SupportedKeyClasses", "javax.crypto.interfaces.DHPublicKey|javax.crypto.interfaces.DHPrivateKey");
+        generalDhAttributes.put("SupportedKeyFormats", "PKCS#8|X.509");
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("KeyPairGenerator.DH", PREFIX + "KeyPairGeneratorSpi");
+            provider.addAlgorithm("Alg.Alias.KeyPairGenerator.DIFFIEHELLMAN", "DH");
+
+            provider.addAttributes("KeyAgreement.DH", generalDhAttributes);
+            provider.addAlgorithm("KeyAgreement.DH", PREFIX + "KeyAgreementSpi");
+            provider.addAlgorithm("Alg.Alias.KeyAgreement.DIFFIEHELLMAN", "DH");
+            // BEGIN Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("KeyAgreement", PKCSObjectIdentifiers.id_alg_ESDH, PREFIX + "KeyAgreementSpi$DHwithRFC2631KDF");
+            // provider.addAlgorithm("KeyAgreement", PKCSObjectIdentifiers.id_alg_SSDH, PREFIX + "KeyAgreementSpi$DHwithRFC2631KDF");
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAlgorithm("KeyFactory.DH", PREFIX + "KeyFactorySpi");
+            provider.addAlgorithm("Alg.Alias.KeyFactory.DIFFIEHELLMAN", "DH");
+
+            provider.addAlgorithm("AlgorithmParameters.DH", PREFIX + "AlgorithmParametersSpi");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.DIFFIEHELLMAN", "DH");
+
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator.DIFFIEHELLMAN", "DH");
+
+            provider.addAlgorithm("AlgorithmParameterGenerator.DH", PREFIX + "AlgorithmParameterGeneratorSpi");
+
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("Cipher.IES", PREFIX + "IESCipher$IES");
+            provider.addAlgorithm("Cipher.IESwithAES-CBC", PREFIX + "IESCipher$IESwithAESCBC");
+            provider.addAlgorithm("Cipher.IESWITHAES-CBC", PREFIX + "IESCipher$IESwithAESCBC");
+            provider.addAlgorithm("Cipher.IESWITHDESEDE-CBC", PREFIX + "IESCipher$IESwithDESedeCBC");
+
+            provider.addAlgorithm("Cipher.DHIES", PREFIX + "IESCipher$IES");
+            provider.addAlgorithm("Cipher.DHIESwithAES-CBC", PREFIX + "IESCipher$IESwithAESCBC");
+            provider.addAlgorithm("Cipher.DHIESWITHAES-CBC", PREFIX + "IESCipher$IESwithAESCBC");
+            provider.addAlgorithm("Cipher.DHIESWITHDESEDE-CBC", PREFIX + "IESCipher$IESwithDESedeCBC");
+
+            provider.addAlgorithm("KeyAgreement.DHWITHSHA1KDF", PREFIX + "KeyAgreementSpi$DHwithSHA1KDF");
+            provider.addAlgorithm("KeyAgreement.DHWITHSHA224KDF", PREFIX + "KeyAgreementSpi$DHwithSHA224KDF");
+            provider.addAlgorithm("KeyAgreement.DHWITHSHA256KDF", PREFIX + "KeyAgreementSpi$DHwithSHA256KDF");
+            provider.addAlgorithm("KeyAgreement.DHWITHSHA384KDF", PREFIX + "KeyAgreementSpi$DHwithSHA384KDF");
+            provider.addAlgorithm("KeyAgreement.DHWITHSHA512KDF", PREFIX + "KeyAgreementSpi$DHwithSHA512KDF");
+
+            provider.addAlgorithm("KeyAgreement.DHUWITHSHA1KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA1KDF");
+            provider.addAlgorithm("KeyAgreement.DHUWITHSHA224KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA224KDF");
+            provider.addAlgorithm("KeyAgreement.DHUWITHSHA256KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA256KDF");
+            provider.addAlgorithm("KeyAgreement.DHUWITHSHA384KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA384KDF");
+            provider.addAlgorithm("KeyAgreement.DHUWITHSHA512KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA512KDF");
+
+            provider.addAlgorithm("KeyAgreement.DHUWITHSHA1CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA1CKDF");
+            provider.addAlgorithm("KeyAgreement.DHUWITHSHA224CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA224CKDF");
+            provider.addAlgorithm("KeyAgreement.DHUWITHSHA256CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA256CKDF");
+            provider.addAlgorithm("KeyAgreement.DHUWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA384CKDF");
+            provider.addAlgorithm("KeyAgreement.DHUWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA512CKDF");
+
+            provider.addAlgorithm("KeyAgreement.MQVWITHSHA1KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA1KDF");
+            provider.addAlgorithm("KeyAgreement.MQVWITHSHA224KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA224KDF");
+            provider.addAlgorithm("KeyAgreement.MQVWITHSHA256KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA256KDF");
+            provider.addAlgorithm("KeyAgreement.MQVWITHSHA384KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA384KDF");
+            provider.addAlgorithm("KeyAgreement.MQVWITHSHA512KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA512KDF");
+
+            provider.addAlgorithm("KeyAgreement.MQVWITHSHA1CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA1CKDF");
+            provider.addAlgorithm("KeyAgreement.MQVWITHSHA224CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA224CKDF");
+            provider.addAlgorithm("KeyAgreement.MQVWITHSHA256CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA256CKDF");
+            provider.addAlgorithm("KeyAgreement.MQVWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA384CKDF");
+            provider.addAlgorithm("KeyAgreement.MQVWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA512CKDF");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            registerOid(provider, PKCSObjectIdentifiers.dhKeyAgreement, "DH", new KeyFactorySpi());
+            registerOid(provider, X9ObjectIdentifiers.dhpublicnumber, "DH", new KeyFactorySpi());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/DSA.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
new file mode 100644
index 0000000..869ed54
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
@@ -0,0 +1,107 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric;
+
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dsa.DSAUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dsa.KeyFactorySpi;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSA
+{
+    private static final String PREFIX = "com.android.internal.org.bouncycastle.jcajce.provider.asymmetric" + ".dsa.";
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+        }
+        
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("AlgorithmParameters.DSA", PREFIX + "AlgorithmParametersSpi");
+
+            provider.addAlgorithm("AlgorithmParameterGenerator.DSA", PREFIX + "AlgorithmParameterGeneratorSpi");
+
+            provider.addAlgorithm("KeyPairGenerator.DSA", PREFIX + "KeyPairGeneratorSpi");
+            provider.addAlgorithm("KeyFactory.DSA", PREFIX + "KeyFactorySpi");
+
+            // BEGIN Android-changed: Change primary ID from DSA to SHA1withDSA
+            // provider.addAlgorithm("Signature.DSA", PREFIX + "DSASigner$stdDSA");
+            provider.addAlgorithm("Signature.SHA1withDSA", PREFIX + "DSASigner$stdDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.DSA", "SHA1withDSA");
+            // END Android-changed: Change primary ID from DSA to SHA1withDSA
+            provider.addAlgorithm("Signature.NONEWITHDSA", PREFIX + "DSASigner$noneDSA");
+
+            provider.addAlgorithm("Alg.Alias.Signature.RAWDSA", "NONEWITHDSA");
+
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("Signature.DETDSA", PREFIX + "DSASigner$detDSA");
+            provider.addAlgorithm("Signature.SHA1WITHDETDSA", PREFIX + "DSASigner$detDSA");
+            provider.addAlgorithm("Signature.SHA224WITHDETDSA", PREFIX + "DSASigner$detDSA224");
+            provider.addAlgorithm("Signature.SHA256WITHDETDSA", PREFIX + "DSASigner$detDSA256");
+            provider.addAlgorithm("Signature.SHA384WITHDETDSA", PREFIX + "DSASigner$detDSA384");
+            provider.addAlgorithm("Signature.SHA512WITHDETDSA", PREFIX + "DSASigner$detDSA512");
+
+            provider.addAlgorithm("Signature.DDSA", PREFIX + "DSASigner$detDSA");
+            provider.addAlgorithm("Signature.SHA1WITHDDSA", PREFIX + "DSASigner$detDSA");
+            provider.addAlgorithm("Signature.SHA224WITHDDSA", PREFIX + "DSASigner$detDSA224");
+            provider.addAlgorithm("Signature.SHA256WITHDDSA", PREFIX + "DSASigner$detDSA256");
+            provider.addAlgorithm("Signature.SHA384WITHDDSA", PREFIX + "DSASigner$detDSA384");
+            provider.addAlgorithm("Signature.SHA512WITHDDSA", PREFIX + "DSASigner$detDSA512");
+            provider.addAlgorithm("Signature.SHA3-224WITHDDSA", PREFIX + "DSASigner$detDSASha3_224");
+            provider.addAlgorithm("Signature.SHA3-256WITHDDSA", PREFIX + "DSASigner$detDSASha3_256");
+            provider.addAlgorithm("Signature.SHA3-384WITHDDSA", PREFIX + "DSASigner$detDSASha3_384");
+            provider.addAlgorithm("Signature.SHA3-512WITHDDSA", PREFIX + "DSASigner$detDSASha3_512");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            addSignatureAlgorithm(provider, "SHA224", "DSA", PREFIX + "DSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
+            addSignatureAlgorithm(provider, "SHA256", "DSA", PREFIX + "DSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            addSignatureAlgorithm(provider, "SHA384", "DSA", PREFIX + "DSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384);
+            addSignatureAlgorithm(provider, "SHA512", "DSA", PREFIX + "DSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512);
+
+            addSignatureAlgorithm(provider, "SHA3-224", "DSA", PREFIX + "DSASigner$dsaSha3_224", NISTObjectIdentifiers.id_dsa_with_sha3_224);
+            addSignatureAlgorithm(provider, "SHA3-256", "DSA", PREFIX + "DSASigner$dsaSha3_256", NISTObjectIdentifiers.id_dsa_with_sha3_256);
+            addSignatureAlgorithm(provider, "SHA3-384", "DSA", PREFIX + "DSASigner$dsaSha3_384", NISTObjectIdentifiers.id_dsa_with_sha3_384);
+            addSignatureAlgorithm(provider, "SHA3-512", "DSA", PREFIX + "DSASigner$dsaSha3_512", NISTObjectIdentifiers.id_dsa_with_sha3_512);
+            */
+            // END Android-removed: Unsupported algorithms
+
+            // BEGIN Android-changed: Change primary ID from DSA to SHA1withDSA
+            provider.addAlgorithm("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA1withDSA", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDSA", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.DSAwithSHA1", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.DSAWITHSHA1", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA1WithDSA", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
+            // END Android-changed: Change primary ID from DSA to SHA1withDSA
+
+            AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi();
+
+            for (int i = 0; i != DSAUtil.dsaOids.length; i++)
+            {
+                // BEGIN Android-changed: Change primary ID from DSA to SHA1withDSA
+                provider.addAlgorithm("Alg.Alias.Signature." + DSAUtil.dsaOids[i], "SHA1withDSA");
+                // END Android-changed: Change primary ID from DSA to SHA1withDSA
+
+                registerOid(provider, DSAUtil.dsaOids[i], "DSA", keyFact);
+                registerOidAlgorithmParameterGenerator(provider, DSAUtil.dsaOids[i], "DSA");
+            }
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/EC.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/EC.java
new file mode 100644
index 0000000..fa92c48
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/EC.java
@@ -0,0 +1,285 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric;
+
+import java.util.HashMap;
+import java.util.Map;
+
+// BEGIN Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers;
+// import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
+// import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+// import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END Android-removed: Unsupported algorithms
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+// BEGIN Android-removed: Unsupported algorithms
+// import org.bouncycastle.util.Properties;
+// END Android-removed: Unsupported algorithms
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class EC
+{
+    private static final String PREFIX = "com.android.internal.org.bouncycastle.jcajce.provider.asymmetric" + ".ec.";
+
+    private static final Map<String, String> generalEcAttributes = new HashMap<String, String>();
+
+    static
+    {
+        generalEcAttributes.put("SupportedKeyClasses", "java.security.interfaces.ECPublicKey|java.security.interfaces.ECPrivateKey");
+        generalEcAttributes.put("SupportedKeyFormats", "PKCS#8|X.509");
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("AlgorithmParameters.EC", PREFIX + "AlgorithmParametersSpi");
+
+            provider.addAttributes("KeyAgreement.ECDH", generalEcAttributes);
+            provider.addAlgorithm("KeyAgreement.ECDH", PREFIX + "KeyAgreementSpi$DH");
+            provider.addAttributes("KeyAgreement.ECDHC", generalEcAttributes);
+            provider.addAlgorithm("KeyAgreement.ECDHC", PREFIX + "KeyAgreementSpi$DHC");
+            provider.addAttributes("KeyAgreement.ECCDH", generalEcAttributes);
+            provider.addAlgorithm("KeyAgreement.ECCDH", PREFIX + "KeyAgreementSpi$DHC");
+
+            provider.addAttributes("KeyAgreement.ECCDHU", generalEcAttributes);
+            provider.addAlgorithm("KeyAgreement.ECCDHU", PREFIX + "KeyAgreementSpi$DHUC");
+
+            provider.addAlgorithm("KeyAgreement.ECDHWITHSHA1KDF", PREFIX + "KeyAgreementSpi$DHwithSHA1KDFAndSharedInfo");
+            provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA1KDF", PREFIX + "KeyAgreementSpi$CDHwithSHA1KDFAndSharedInfo");
+
+            provider.addAlgorithm("KeyAgreement.ECDHWITHSHA224KDF", PREFIX + "KeyAgreementSpi$DHwithSHA224KDFAndSharedInfo");
+            provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA224KDF", PREFIX + "KeyAgreementSpi$CDHwithSHA224KDFAndSharedInfo");
+
+            provider.addAlgorithm("KeyAgreement.ECDHWITHSHA256KDF", PREFIX + "KeyAgreementSpi$DHwithSHA256KDFAndSharedInfo");
+            provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA256KDF", PREFIX + "KeyAgreementSpi$CDHwithSHA256KDFAndSharedInfo");
+
+            provider.addAlgorithm("KeyAgreement.ECDHWITHSHA384KDF", PREFIX + "KeyAgreementSpi$DHwithSHA384KDFAndSharedInfo");
+            provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA384KDF", PREFIX + "KeyAgreementSpi$CDHwithSHA384KDFAndSharedInfo");
+
+            provider.addAlgorithm("KeyAgreement.ECDHWITHSHA512KDF", PREFIX + "KeyAgreementSpi$DHwithSHA512KDFAndSharedInfo");
+            provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA512KDF", PREFIX + "KeyAgreementSpi$CDHwithSHA512KDFAndSharedInfo");
+
+            provider.addAlgorithm("KeyAgreement", X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA1KDFAndSharedInfo");
+            provider.addAlgorithm("KeyAgreement", X9ObjectIdentifiers.dhSinglePass_cofactorDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA1KDFAndSharedInfo");
+
+            provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_stdDH_sha224kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA224KDFAndSharedInfo");
+            provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_cofactorDH_sha224kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA224KDFAndSharedInfo");
+
+            provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_stdDH_sha256kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA256KDFAndSharedInfo");
+            provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_cofactorDH_sha256kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA256KDFAndSharedInfo");
+
+            provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_stdDH_sha384kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA384KDFAndSharedInfo");
+            provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_cofactorDH_sha384kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA384KDFAndSharedInfo");
+
+            provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_stdDH_sha512kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA512KDFAndSharedInfo");
+            provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_cofactorDH_sha512kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA512KDFAndSharedInfo");
+
+            provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA1CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA1CKDF");
+            provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA256CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA256CKDF");
+            provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA384CKDF");
+            provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA512CKDF");
+
+            provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA1CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA1CKDF");
+            provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA224CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA224CKDF");
+            provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA256CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA256CKDF");
+            provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA384CKDF");
+            provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA512CKDF");
+
+            provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA1KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA1KDF");
+            provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA224KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA224KDF");
+            provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA256KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA256KDF");
+            provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA384KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA384KDF");
+            provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA512KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA512KDF");
+
+            provider.addAlgorithm("KeyAgreement.ECKAEGWITHSHA1KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithSHA1KDF");
+            provider.addAlgorithm("KeyAgreement.ECKAEGWITHSHA224KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithSHA224KDF");
+            provider.addAlgorithm("KeyAgreement.ECKAEGWITHSHA256KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithSHA256KDF");
+            provider.addAlgorithm("KeyAgreement.ECKAEGWITHSHA384KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithSHA384KDF");
+            provider.addAlgorithm("KeyAgreement.ECKAEGWITHSHA512KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithSHA512KDF");
+
+            provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA1, PREFIX + "KeyAgreementSpi$ECKAEGwithSHA1KDF");
+            provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA224, PREFIX + "KeyAgreementSpi$ECKAEGwithSHA224KDF");
+            provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA256, PREFIX + "KeyAgreementSpi$ECKAEGwithSHA256KDF");
+            provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA384, PREFIX + "KeyAgreementSpi$ECKAEGwithSHA384KDF");
+            provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA512, PREFIX + "KeyAgreementSpi$ECKAEGwithSHA512KDF");
+
+            provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_RIPEMD160, PREFIX + "KeyAgreementSpi$ECKAEGwithRIPEMD160KDF");
+            provider.addAlgorithm("KeyAgreement.ECKAEGWITHRIPEMD160KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithRIPEMD160KDF");
+
+            registerOid(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC", new KeyFactorySpi.EC());
+
+            registerOid(provider, X9ObjectIdentifiers.dhSinglePass_cofactorDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC());
+            registerOid(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
+
+            registerOid(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha224kdf_scheme, "EC", new KeyFactorySpi.EC());
+            registerOid(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha224kdf_scheme, "EC", new KeyFactorySpi.EC());
+
+            registerOid(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha256kdf_scheme, "EC", new KeyFactorySpi.EC());
+            registerOid(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha256kdf_scheme, "EC", new KeyFactorySpi.EC());
+
+            registerOid(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha384kdf_scheme, "EC", new KeyFactorySpi.EC());
+            registerOid(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha384kdf_scheme, "EC", new KeyFactorySpi.EC());
+
+            registerOid(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha512kdf_scheme, "EC", new KeyFactorySpi.EC());
+            registerOid(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha512kdf_scheme, "EC", new KeyFactorySpi.EC());
+
+            registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC");
+
+            registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+            registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.dhSinglePass_cofactorDH_sha1kdf_scheme, "EC");
+
+            registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha224kdf_scheme, "EC");
+            registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha224kdf_scheme, "EC");
+
+            registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha256kdf_scheme, "EC");
+            registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha256kdf_scheme, "EC");
+
+            registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha384kdf_scheme, "EC");
+            registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha384kdf_scheme, "EC");
+
+            registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha512kdf_scheme, "EC");
+            registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha512kdf_scheme, "EC");
+
+            if (!Properties.isOverrideSet("org.bouncycastle.ec.disable_mqv"))
+            {
+                provider.addAlgorithm("KeyAgreement.ECMQV", PREFIX + "KeyAgreementSpi$MQV");
+
+                provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA1CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA1CKDF");
+                provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA224CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA224CKDF");
+                provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA256CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA256CKDF");
+                provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA384CKDF");
+                provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA512CKDF");
+
+                provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA1KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA1KDF");
+                provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA224KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA224KDF");
+                provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA256KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA256KDF");
+                provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA384KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA384KDF");
+                provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA512KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA512KDF");
+
+                provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA1KDFAndSharedInfo");
+                provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA224KDFAndSharedInfo");
+                provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA256KDFAndSharedInfo");
+                provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha384kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA384KDFAndSharedInfo");
+                provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha512kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA512KDFAndSharedInfo");
+
+                registerOid(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC());
+            
+                registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "EC");
+
+                registerOid(provider, SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
+                registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme, "EC");
+
+                registerOid(provider, SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
+                registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme, "EC");
+
+                registerOid(provider, SECObjectIdentifiers.mqvSinglePass_sha384kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
+                registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha384kdf_scheme, "EC");
+
+                registerOid(provider, SECObjectIdentifiers.mqvSinglePass_sha512kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
+                registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha512kdf_scheme, "EC");
+
+                provider.addAlgorithm("KeyFactory.ECMQV", PREFIX + "KeyFactorySpi$ECMQV");
+                provider.addAlgorithm("KeyPairGenerator.ECMQV", PREFIX + "KeyPairGeneratorSpi$ECMQV");
+            }
+            
+            provider.addAlgorithm("KeyFactory.EC", PREFIX + "KeyFactorySpi$EC");
+            provider.addAlgorithm("KeyFactory.ECDSA", PREFIX + "KeyFactorySpi$ECDSA");
+            provider.addAlgorithm("KeyFactory.ECDH", PREFIX + "KeyFactorySpi$ECDH");
+            provider.addAlgorithm("KeyFactory.ECDHC", PREFIX + "KeyFactorySpi$ECDHC");
+            
+            provider.addAlgorithm("KeyPairGenerator.EC", PREFIX + "KeyPairGeneratorSpi$EC");
+            provider.addAlgorithm("KeyPairGenerator.ECDSA", PREFIX + "KeyPairGeneratorSpi$ECDSA");
+            provider.addAlgorithm("KeyPairGenerator.ECDH", PREFIX + "KeyPairGeneratorSpi$ECDH");
+            provider.addAlgorithm("KeyPairGenerator.ECDHWITHSHA1KDF", PREFIX + "KeyPairGeneratorSpi$ECDH");
+            provider.addAlgorithm("KeyPairGenerator.ECDHC", PREFIX + "KeyPairGeneratorSpi$ECDHC");
+            provider.addAlgorithm("KeyPairGenerator.ECIES", PREFIX + "KeyPairGeneratorSpi$ECDH");
+
+            provider.addAlgorithm("Cipher.ECIES", PREFIX + "IESCipher$ECIES");
+
+            provider.addAlgorithm("Cipher.ECIESwithAES-CBC", PREFIX + "IESCipher$ECIESwithAESCBC");
+            provider.addAlgorithm("Cipher.ECIESWITHAES-CBC", PREFIX + "IESCipher$ECIESwithAESCBC");
+            provider.addAlgorithm("Cipher.ECIESwithDESEDE-CBC", PREFIX + "IESCipher$ECIESwithDESedeCBC");
+            provider.addAlgorithm("Cipher.ECIESWITHDESEDE-CBC", PREFIX + "IESCipher$ECIESwithDESedeCBC");
+
+            provider.addAlgorithm("Signature.ECDSA", PREFIX + "SignatureSpi$ecDSA");
+
+            provider.addAlgorithm("Signature.SHA1withECDSA", PREFIX + "SignatureSpi$ecDSA");
+            provider.addAlgorithm("Signature.NONEwithECDSA", PREFIX + "SignatureSpi$ecDSAnone");
+
+            provider.addAlgorithm("Alg.Alias.Signature.ECDSA", "SHA1withECDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.ECDSAwithSHA1", "SHA1withECDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHECDSA", "SHA1withECDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.ECDSAWITHSHA1", "SHA1withECDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA1WithECDSA", "SHA1withECDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.ECDSAWithSHA1", "SHA1withECDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA");
+            provider.addAlgorithm("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
+
+            provider.addAlgorithm("Signature.ECDDSA", PREFIX + "SignatureSpi$ecDetDSA");
+            provider.addAlgorithm("Signature.SHA1WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA");
+            provider.addAlgorithm("Signature.SHA224WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA224");
+            provider.addAlgorithm("Signature.SHA256WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA256");
+            provider.addAlgorithm("Signature.SHA384WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA384");
+            provider.addAlgorithm("Signature.SHA512WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA512");
+            provider.addAlgorithm("Signature.SHA3-224WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSASha3_224");
+            provider.addAlgorithm("Signature.SHA3-256WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSASha3_256");
+            provider.addAlgorithm("Signature.SHA3-384WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSASha3_384");
+            provider.addAlgorithm("Signature.SHA3-512WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSASha3_512");
+
+            provider.addAlgorithm("Alg.Alias.Signature.DETECDSA", "ECDDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDETECDSA", "SHA1WITHECDDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA224WITHDETECDSA", "SHA224WITHECDDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA256WITHDETECDSA", "SHA256WITHECDDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA384WITHDETECDSA", "SHA384WITHECDDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA512WITHDETECDSA", "SHA512WITHECDDSA");
+
+            addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
+            addSignatureAlgorithm(provider, "SHA256", "ECDSA", PREFIX + "SignatureSpi$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
+            addSignatureAlgorithm(provider, "SHA384", "ECDSA", PREFIX + "SignatureSpi$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
+            addSignatureAlgorithm(provider, "SHA512", "ECDSA", PREFIX + "SignatureSpi$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
+            addSignatureAlgorithm(provider, "SHA3-224", "ECDSA", PREFIX + "SignatureSpi$ecDSASha3_224", NISTObjectIdentifiers.id_ecdsa_with_sha3_224);
+            addSignatureAlgorithm(provider, "SHA3-256", "ECDSA", PREFIX + "SignatureSpi$ecDSASha3_256", NISTObjectIdentifiers.id_ecdsa_with_sha3_256);
+            addSignatureAlgorithm(provider, "SHA3-384", "ECDSA", PREFIX + "SignatureSpi$ecDSASha3_384", NISTObjectIdentifiers.id_ecdsa_with_sha3_384);
+            addSignatureAlgorithm(provider, "SHA3-512", "ECDSA", PREFIX + "SignatureSpi$ecDSASha3_512", NISTObjectIdentifiers.id_ecdsa_with_sha3_512);
+
+            addSignatureAlgorithm(provider, "RIPEMD160", "ECDSA", PREFIX + "SignatureSpi$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
+
+            provider.addAlgorithm("Signature.SHA1WITHECNR", PREFIX + "SignatureSpi$ecNR");
+            provider.addAlgorithm("Signature.SHA224WITHECNR", PREFIX + "SignatureSpi$ecNR224");
+            provider.addAlgorithm("Signature.SHA256WITHECNR", PREFIX + "SignatureSpi$ecNR256");
+            provider.addAlgorithm("Signature.SHA384WITHECNR", PREFIX + "SignatureSpi$ecNR384");
+            provider.addAlgorithm("Signature.SHA512WITHECNR", PREFIX + "SignatureSpi$ecNR512");
+
+            addSignatureAlgorithm(provider, "SHA1", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
+            addSignatureAlgorithm(provider, "SHA224", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
+            addSignatureAlgorithm(provider, "SHA256", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
+            addSignatureAlgorithm(provider, "SHA384", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA384", EACObjectIdentifiers.id_TA_ECDSA_SHA_384);
+            addSignatureAlgorithm(provider, "SHA512", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA512", EACObjectIdentifiers.id_TA_ECDSA_SHA_512);
+
+            addSignatureAlgorithm(provider, "SHA1", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA", BSIObjectIdentifiers.ecdsa_plain_SHA1);
+            addSignatureAlgorithm(provider, "SHA224", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA224", BSIObjectIdentifiers.ecdsa_plain_SHA224);
+            addSignatureAlgorithm(provider, "SHA256", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA256", BSIObjectIdentifiers.ecdsa_plain_SHA256);
+            addSignatureAlgorithm(provider, "SHA384", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA384", BSIObjectIdentifiers.ecdsa_plain_SHA384);
+            addSignatureAlgorithm(provider, "SHA512", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA512", BSIObjectIdentifiers.ecdsa_plain_SHA512);
+            addSignatureAlgorithm(provider, "RIPEMD160", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecPlainDSARP160", BSIObjectIdentifiers.ecdsa_plain_RIPEMD160);
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/RSA.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
new file mode 100644
index 0000000..f86a7a9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
@@ -0,0 +1,302 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSA
+{
+    private static final String PREFIX = "com.android.internal.org.bouncycastle.jcajce.provider.asymmetric" + ".rsa.";
+
+    private static final Map<String, String> generalRsaAttributes = new HashMap<String, String>();
+
+    static
+    {
+        generalRsaAttributes.put("SupportedKeyClasses", "javax.crypto.interfaces.RSAPublicKey|javax.crypto.interfaces.RSAPrivateKey");
+        generalRsaAttributes.put("SupportedKeyFormats", "PKCS#8|X.509");
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("AlgorithmParameters.OAEP", PREFIX + "AlgorithmParametersSpi$OAEP");
+            provider.addAlgorithm("AlgorithmParameters.PSS", PREFIX + "AlgorithmParametersSpi$PSS");
+
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSAPSS", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSASSA-PSS", "PSS");
+
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224withRSA/PSS", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256withRSA/PSS", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384withRSA/PSS", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512withRSA/PSS", "PSS");
+
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224WITHRSAANDMGF1", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-224WITHRSAANDMGF1", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-256WITHRSAANDMGF1", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-384WITHRSAANDMGF1", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA3-512WITHRSAANDMGF1", "PSS");
+
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RAWRSAPSS", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAPSS", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSASSA-PSS", "PSS");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAANDMGF1", "PSS");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAttributes("Cipher.RSA", generalRsaAttributes);
+            provider.addAlgorithm("Cipher.RSA", PREFIX + "CipherSpi$NoPadding");
+            // Android-changed: Use an alias for RSA/RAW instead of a concrete implementation
+            provider.addAlgorithm("Alg.Alias.Cipher.RSA/RAW", "RSA");
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("Cipher.RSA/PKCS1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
+            provider.addAlgorithm("Cipher", PKCSObjectIdentifiers.rsaEncryption, PREFIX + "CipherSpi$PKCS1v1_5Padding");
+            provider.addAlgorithm("Cipher", X509ObjectIdentifiers.id_ea_rsa, PREFIX + "CipherSpi$PKCS1v1_5Padding");
+            provider.addAlgorithm("Cipher.RSA/1", PREFIX + "CipherSpi$PKCS1v1_5Padding_PrivateOnly");
+            provider.addAlgorithm("Cipher.RSA/2", PREFIX + "CipherSpi$PKCS1v1_5Padding_PublicOnly");
+            provider.addAlgorithm("Cipher.RSA/OAEP", PREFIX + "CipherSpi$OAEPPadding");
+            provider.addAlgorithm("Cipher", PKCSObjectIdentifiers.id_RSAES_OAEP, PREFIX + "CipherSpi$OAEPPadding");
+            provider.addAlgorithm("Cipher.RSA/ISO9796-1", PREFIX + "CipherSpi$ISO9796d1Padding");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAlgorithm("Alg.Alias.Cipher.RSA//RAW", "RSA");
+            provider.addAlgorithm("Alg.Alias.Cipher.RSA//NOPADDING", "RSA");
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
+            provider.addAlgorithm("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
+            provider.addAlgorithm("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAlgorithm("KeyFactory.RSA", PREFIX + "KeyFactorySpi");
+            provider.addAlgorithm("KeyPairGenerator.RSA", PREFIX + "KeyPairGeneratorSpi");
+
+            AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi();
+
+            registerOid(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA", keyFact);
+            registerOid(provider, X509ObjectIdentifiers.id_ea_rsa, "RSA", keyFact);
+            registerOid(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA", keyFact);
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            registerOid(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "RSA", keyFact);
+
+            registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA");
+            registerOidAlgorithmParameters(provider, X509ObjectIdentifiers.id_ea_rsa, "RSA");
+            registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "OAEP");
+            registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "PSS");
+
+            provider.addAlgorithm("Signature.RSASSA-PSS", PREFIX + "PSSSignatureSpi$PSSwithRSA");
+            provider.addAlgorithm("Signature." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA");
+            provider.addAlgorithm("Signature.OID." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA");
+
+            provider.addAlgorithm("Signature.RSA", PREFIX + "DigestSignatureSpi$noneRSA");
+            provider.addAlgorithm("Signature.RAWRSASSA-PSS", PREFIX + "PSSSignatureSpi$nonePSS");
+
+            provider.addAlgorithm("Alg.Alias.Signature.RAWRSA", "RSA");
+            provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSA", "RSA");
+            provider.addAlgorithm("Alg.Alias.Signature.RAWRSAPSS", "RAWRSASSA-PSS");
+            provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAPSS", "RAWRSASSA-PSS");
+            provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSASSA-PSS", "RAWRSASSA-PSS");
+            provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAANDMGF1", "RAWRSASSA-PSS");
+            provider.addAlgorithm("Alg.Alias.Signature.RSAPSS", "RSASSA-PSS");
+
+            addPSSSignature(provider, "SHA224", PREFIX + "PSSSignatureSpi$SHA224withRSA");
+            addPSSSignature(provider, "SHA256", PREFIX + "PSSSignatureSpi$SHA256withRSA");
+            addPSSSignature(provider, "SHA384", PREFIX + "PSSSignatureSpi$SHA384withRSA");
+            addPSSSignature(provider, "SHA512", PREFIX + "PSSSignatureSpi$SHA512withRSA");
+            addPSSSignature(provider, "SHA512(224)", PREFIX + "PSSSignatureSpi$SHA512_224withRSA");
+            addPSSSignature(provider, "SHA512(256)", PREFIX + "PSSSignatureSpi$SHA512_256withRSA");
+
+            addPSSSignature(provider, "SHA3-224", PREFIX + "PSSSignatureSpi$SHA3_224withRSA");
+            addPSSSignature(provider, "SHA3-256", PREFIX + "PSSSignatureSpi$SHA3_256withRSA");
+            addPSSSignature(provider, "SHA3-384", PREFIX + "PSSSignatureSpi$SHA3_384withRSA");
+            addPSSSignature(provider, "SHA3-512", PREFIX + "PSSSignatureSpi$SHA3_512withRSA");
+
+            if (provider.hasAlgorithm("MessageDigest", "MD2"))
+            {
+                addDigestSignature(provider, "MD2", PREFIX + "DigestSignatureSpi$MD2", PKCSObjectIdentifiers.md2WithRSAEncryption);
+            }
+
+            if (provider.hasAlgorithm("MessageDigest", "MD4"))
+            {
+                addDigestSignature(provider, "MD4", PREFIX + "DigestSignatureSpi$MD4", PKCSObjectIdentifiers.md4WithRSAEncryption);
+            }
+
+            if (provider.hasAlgorithm("MessageDigest", "MD5"))
+            {
+                addDigestSignature(provider, "MD5", PREFIX + "DigestSignatureSpi$MD5", PKCSObjectIdentifiers.md5WithRSAEncryption);
+                addISO9796Signature(provider, "MD5", PREFIX + "ISOSignatureSpi$MD5WithRSAEncryption");
+            }
+
+            if (provider.hasAlgorithm("MessageDigest", "SHA1"))
+            {
+                provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1withRSA/PSS", "PSS");
+                provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1WITHRSAANDMGF1", "PSS");
+
+                addPSSSignature(provider, "SHA1", PREFIX + "PSSSignatureSpi$SHA1withRSA");
+                addDigestSignature(provider, "SHA1", PREFIX + "DigestSignatureSpi$SHA1", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+                addISO9796Signature(provider, "SHA1", PREFIX + "ISOSignatureSpi$SHA1WithRSAEncryption");
+
+                provider.addAlgorithm("Alg.Alias.Signature." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+                provider.addAlgorithm("Alg.Alias.Signature.OID." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+
+                addX931Signature(provider, "SHA1", PREFIX + "X931SignatureSpi$SHA1WithRSAEncryption");
+            }
+
+            addDigestSignature(provider, "SHA224", PREFIX + "DigestSignatureSpi$SHA224", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+            addDigestSignature(provider, "SHA256", PREFIX + "DigestSignatureSpi$SHA256", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+            addDigestSignature(provider, "SHA384", PREFIX + "DigestSignatureSpi$SHA384", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+            addDigestSignature(provider, "SHA512", PREFIX + "DigestSignatureSpi$SHA512", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+            addDigestSignature(provider, "SHA512(224)", PREFIX + "DigestSignatureSpi$SHA512_224", PKCSObjectIdentifiers.sha512_224WithRSAEncryption);
+            addDigestSignature(provider, "SHA512(256)", PREFIX + "DigestSignatureSpi$SHA512_256", PKCSObjectIdentifiers.sha512_256WithRSAEncryption);
+
+            addDigestSignature(provider, "SHA3-224", PREFIX + "DigestSignatureSpi$SHA3_224", NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_224);
+            addDigestSignature(provider, "SHA3-256", PREFIX + "DigestSignatureSpi$SHA3_256", NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_256);
+            addDigestSignature(provider, "SHA3-384", PREFIX + "DigestSignatureSpi$SHA3_384", NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_384);
+            addDigestSignature(provider, "SHA3-512", PREFIX + "DigestSignatureSpi$SHA3_512", NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_512);
+
+            addISO9796Signature(provider, "SHA224", PREFIX + "ISOSignatureSpi$SHA224WithRSAEncryption");
+            addISO9796Signature(provider, "SHA256", PREFIX + "ISOSignatureSpi$SHA256WithRSAEncryption");
+            addISO9796Signature(provider, "SHA384", PREFIX + "ISOSignatureSpi$SHA384WithRSAEncryption");
+            addISO9796Signature(provider, "SHA512", PREFIX + "ISOSignatureSpi$SHA512WithRSAEncryption");
+            addISO9796Signature(provider, "SHA512(224)", PREFIX + "ISOSignatureSpi$SHA512_224WithRSAEncryption");
+            addISO9796Signature(provider, "SHA512(256)", PREFIX + "ISOSignatureSpi$SHA512_256WithRSAEncryption");
+
+            addX931Signature(provider, "SHA224", PREFIX + "X931SignatureSpi$SHA224WithRSAEncryption");
+            addX931Signature(provider, "SHA256", PREFIX + "X931SignatureSpi$SHA256WithRSAEncryption");
+            addX931Signature(provider, "SHA384", PREFIX + "X931SignatureSpi$SHA384WithRSAEncryption");
+            addX931Signature(provider, "SHA512", PREFIX + "X931SignatureSpi$SHA512WithRSAEncryption");
+            addX931Signature(provider, "SHA512(224)", PREFIX + "X931SignatureSpi$SHA512_224WithRSAEncryption");
+            addX931Signature(provider, "SHA512(256)", PREFIX + "X931SignatureSpi$SHA512_256WithRSAEncryption");
+
+            if (provider.hasAlgorithm("MessageDigest", "RIPEMD128"))
+            {
+                addDigestSignature(provider, "RIPEMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+                addDigestSignature(provider, "RMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", null);
+
+                addX931Signature(provider, "RMD128", PREFIX + "X931SignatureSpi$RIPEMD128WithRSAEncryption");
+                addX931Signature(provider, "RIPEMD128", PREFIX + "X931SignatureSpi$RIPEMD128WithRSAEncryption");
+            }
+
+            if (provider.hasAlgorithm("MessageDigest", "RIPEMD160"))
+            {
+                addDigestSignature(provider, "RIPEMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+                addDigestSignature(provider, "RMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", null);
+                provider.addAlgorithm("Alg.Alias.Signature.RIPEMD160WithRSA/ISO9796-2", "RIPEMD160withRSA/ISO9796-2");
+                provider.addAlgorithm("Signature.RIPEMD160withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$RIPEMD160WithRSAEncryption");
+
+                addX931Signature(provider, "RMD160", PREFIX + "X931SignatureSpi$RIPEMD160WithRSAEncryption");
+                addX931Signature(provider, "RIPEMD160", PREFIX + "X931SignatureSpi$RIPEMD160WithRSAEncryption");
+            }
+
+            if (provider.hasAlgorithm("MessageDigest", "RIPEMD256"))
+            {
+                addDigestSignature(provider, "RIPEMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+                addDigestSignature(provider, "RMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", null);
+            }
+
+            if (provider.hasAlgorithm("MessageDigest", "WHIRLPOOL"))
+            {
+                addISO9796Signature(provider, "Whirlpool", PREFIX + "ISOSignatureSpi$WhirlpoolWithRSAEncryption");
+                addISO9796Signature(provider, "WHIRLPOOL", PREFIX + "ISOSignatureSpi$WhirlpoolWithRSAEncryption");
+                addX931Signature(provider, "Whirlpool", PREFIX + "X931SignatureSpi$WhirlpoolWithRSAEncryption");
+                addX931Signature(provider, "WHIRLPOOL", PREFIX + "X931SignatureSpi$WhirlpoolWithRSAEncryption");
+            }
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+
+        private void addDigestSignature(
+            ConfigurableProvider provider,
+            String digest,
+            String className,
+            ASN1ObjectIdentifier oid)
+        {
+            String mainName = digest + "WITHRSA";
+            String jdk11Variation1 = digest + "withRSA";
+            String jdk11Variation2 = digest + "WithRSA";
+            String alias = digest + "/" + "RSA";
+            String longName = digest + "WITHRSAENCRYPTION";
+            String longJdk11Variation1 = digest + "withRSAEncryption";
+            String longJdk11Variation2 = digest + "WithRSAEncryption";
+
+            provider.addAlgorithm("Signature." + mainName, className);
+            provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation1, mainName);
+            provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation2, mainName);
+            provider.addAlgorithm("Alg.Alias.Signature." + longName, mainName);
+            provider.addAlgorithm("Alg.Alias.Signature." + longJdk11Variation1, mainName);
+            provider.addAlgorithm("Alg.Alias.Signature." + longJdk11Variation2, mainName);
+            provider.addAlgorithm("Alg.Alias.Signature." + alias, mainName);
+
+            if (oid != null)
+            {
+                provider.addAlgorithm("Alg.Alias.Signature." + oid, mainName);
+                provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, mainName);
+            }
+        }
+
+        private void addISO9796Signature(
+            ConfigurableProvider provider,
+            String digest,
+            String className)
+        {
+            provider.addAlgorithm("Alg.Alias.Signature." + digest + "withRSA/ISO9796-2", digest + "WITHRSA/ISO9796-2");
+            provider.addAlgorithm("Alg.Alias.Signature." + digest + "WithRSA/ISO9796-2", digest + "WITHRSA/ISO9796-2");
+            provider.addAlgorithm("Signature." + digest + "WITHRSA/ISO9796-2", className);
+        }
+
+        private void addPSSSignature(
+            ConfigurableProvider provider,
+            String digest,
+            String className)
+        {
+            provider.addAlgorithm("Alg.Alias.Signature." + digest + "withRSA/PSS", digest + "WITHRSAANDMGF1");
+            provider.addAlgorithm("Alg.Alias.Signature." + digest + "WithRSA/PSS", digest + "WITHRSAANDMGF1");
+            provider.addAlgorithm("Alg.Alias.Signature." + digest + "withRSAandMGF1", digest + "WITHRSAANDMGF1");
+            provider.addAlgorithm("Alg.Alias.Signature." + digest + "WithRSAAndMGF1", digest + "WITHRSAANDMGF1");
+            provider.addAlgorithm("Signature." + digest + "WITHRSAANDMGF1", className);
+        }
+
+        private void addX931Signature(
+            ConfigurableProvider provider,
+            String digest,
+            String className)
+        {
+            provider.addAlgorithm("Alg.Alias.Signature." + digest + "withRSA/X9.31", digest + "WITHRSA/X9.31");
+            provider.addAlgorithm("Alg.Alias.Signature." + digest + "WithRSA/X9.31", digest + "WITHRSA/X9.31");
+            provider.addAlgorithm("Signature." + digest + "WITHRSA/X9.31", className);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/X509.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/X509.java
new file mode 100644
index 0000000..88db097
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/X509.java
@@ -0,0 +1,40 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric;
+
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+/**
+ * For some reason the class path project thinks that such a KeyFactory will exist.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509
+{
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("KeyFactory.X.509", "org.bouncycastle.jcajce.provider.asymmetric.x509.KeyFactory");
+            provider.addAlgorithm("Alg.Alias.KeyFactory.X509", "X.509");
+
+            //
+            // certificate factories.
+            //
+            provider.addAlgorithm("CertificateFactory.X.509", "org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory");
+            provider.addAlgorithm("Alg.Alias.CertificateFactory.X509", "X.509");
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 0000000..441237b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,85 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.generators.DHParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.BaseAlgorithmParameterGeneratorSpi;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PrimeCertaintyCalculator;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlgorithmParameterGeneratorSpi
+    extends BaseAlgorithmParameterGeneratorSpi
+{
+    protected SecureRandom random;
+    protected int strength = 2048;
+
+    private int l = 0;
+
+    protected void engineInit(
+        int strength,
+        SecureRandom random)
+    {
+        this.strength = strength;
+        this.random = random;
+    }
+
+    protected void engineInit(
+        AlgorithmParameterSpec genParamSpec,
+        SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(genParamSpec instanceof DHGenParameterSpec))
+        {
+            throw new InvalidAlgorithmParameterException("DH parameter generator requires a DHGenParameterSpec for initialisation");
+        }
+        DHGenParameterSpec spec = (DHGenParameterSpec)genParamSpec;
+
+        this.strength = spec.getPrimeSize();
+        this.l = spec.getExponentSize();
+        this.random = random;
+    }
+
+    protected AlgorithmParameters engineGenerateParameters()
+    {
+        DHParametersGenerator pGen = new DHParametersGenerator();
+
+        int certainty = PrimeCertaintyCalculator.getDefaultCertainty(strength);
+
+        if (random != null)
+        {
+            pGen.init(strength, certainty, random);
+        }
+        else
+        {
+            pGen.init(strength, certainty, CryptoServicesRegistrar.getSecureRandom());
+        }
+
+        DHParameters p = pGen.generateParameters();
+
+        AlgorithmParameters params;
+
+        try
+        {
+            params = createParametersInstance("DH");
+            params.init(new DHParameterSpec(p.getP(), p.getG(), l));
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e.getMessage());
+        }
+
+        return params;
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..d8d8883
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java
@@ -0,0 +1,146 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.pkcs.DHParameter;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlgorithmParametersSpi
+    extends java.security.AlgorithmParametersSpi
+{
+    DHParameterSpec     currentSpec;
+
+    protected boolean isASN1FormatString(String format)
+    {
+        return format == null || format.equals("ASN.1");
+    }
+
+    protected AlgorithmParameterSpec engineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == null)
+        {
+            throw new NullPointerException("argument to getParameterSpec must not be null");
+        }
+
+        return localEngineGetParameterSpec(paramSpec);
+    }
+
+
+
+
+        /**
+         * Return the PKCS#3 ASN.1 structure DHParameter.
+         * <p>
+         * <pre>
+         *  DHParameter ::= SEQUENCE {
+         *                   prime INTEGER, -- p
+         *                   base INTEGER, -- g
+         *                   privateValueLength INTEGER OPTIONAL}
+         * </pre>
+         */
+        protected byte[] engineGetEncoded() 
+        {
+            DHParameter dhP = new DHParameter(currentSpec.getP(), currentSpec.getG(), currentSpec.getL());
+
+            try
+            {
+                return dhP.getEncoded(ASN1Encoding.DER);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Error encoding DHParameters");
+            }
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+        {
+            if (isASN1FormatString(format))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == DHParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
+            {
+                return currentSpec;
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to DH parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof DHParameterSpec))
+            {
+                throw new InvalidParameterSpecException("DHParameterSpec required to initialise a Diffie-Hellman algorithm parameters object");
+            }
+
+            this.currentSpec = (DHParameterSpec)paramSpec;
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            try
+            {
+                DHParameter dhP = DHParameter.getInstance(params);
+
+                if (dhP.getL() != null)
+                {
+                    currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG(), dhP.getL().intValue());
+                }
+                else
+                {
+                    currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG());
+                }
+            }
+            catch (ClassCastException e)
+            {
+                throw new IOException("Not a valid DH Parameter encoding.");
+            }
+            catch (ArrayIndexOutOfBoundsException e)
+            {
+                throw new IOException("Not a valid DH Parameter encoding.");
+            }
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (isASN1FormatString(format))
+            {
+                engineInit(params);
+            }
+            else
+            {
+                throw new IOException("Unknown parameter format " + format);
+            }
+        }
+
+        protected String engineToString() 
+        {
+            return "Diffie-Hellman Parameters";
+        }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java
new file mode 100644
index 0000000..00dc932
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java
@@ -0,0 +1,263 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPrivateKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.pkcs.DHParameter;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x9.DomainParameters;
+import com.android.internal.org.bouncycastle.asn1.x9.ValidationParams;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHValidationParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import com.android.internal.org.bouncycastle.jcajce.spec.DHDomainParameterSpec;
+import com.android.internal.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCDHPrivateKey
+    implements DHPrivateKey, PKCS12BagAttributeCarrier
+{
+    static final long serialVersionUID = 311058815616901812L;
+    
+    private BigInteger      x;
+
+    private transient DHParameterSpec dhSpec;
+    private transient PrivateKeyInfo  info;
+    private transient DHPrivateKeyParameters dhPrivateKey;
+
+    private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected BCDHPrivateKey()
+    {
+    }
+
+    BCDHPrivateKey(
+        DHPrivateKey key)
+    {
+        this.x = key.getX();
+        this.dhSpec = key.getParams();
+    }
+
+    BCDHPrivateKey(
+        DHPrivateKeySpec spec)
+    {
+        this.x = spec.getX();
+        this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+    }
+
+    public BCDHPrivateKey(
+        PrivateKeyInfo info)
+        throws IOException
+    {
+        ASN1Sequence    seq = ASN1Sequence.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+        ASN1Integer      derX = (ASN1Integer)info.parsePrivateKey();
+        ASN1ObjectIdentifier id = info.getPrivateKeyAlgorithm().getAlgorithm();
+
+        this.info = info;
+        this.x = derX.getValue();
+
+        if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+            DHParameter params = DHParameter.getInstance(seq);
+
+            if (params.getL() != null)
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+                this.dhPrivateKey = new DHPrivateKeyParameters(x,
+                          new DHParameters(params.getP(), params.getG(), null, params.getL().intValue()));
+            }
+            else
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+                this.dhPrivateKey = new DHPrivateKeyParameters(x,
+                          new DHParameters(params.getP(), params.getG()));
+            }
+        }
+        else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            DomainParameters params = DomainParameters.getInstance(seq);
+
+            this.dhSpec = new DHDomainParameterSpec(params.getP(), params.getQ(), params.getG(), params.getJ(), 0);
+            this.dhPrivateKey = new DHPrivateKeyParameters(x,
+                new DHParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), null));
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown algorithm type: " + id);
+        }
+
+
+    }
+
+    BCDHPrivateKey(
+        DHPrivateKeyParameters params)
+    {
+        this.x = params.getX();
+        this.dhSpec = new DHDomainParameterSpec(params.getParameters());
+    }
+
+    public String getAlgorithm()
+    {
+        return "DH";
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        try
+        {
+            if (info != null)
+            {
+                return info.getEncoded(ASN1Encoding.DER);
+            }
+
+            PrivateKeyInfo          info;
+            if (dhSpec instanceof DHDomainParameterSpec && ((DHDomainParameterSpec)dhSpec).getQ() != null)
+            {
+                DHParameters params = ((DHDomainParameterSpec)dhSpec).getDomainParameters();
+                DHValidationParameters validationParameters = params.getValidationParameters();
+                ValidationParams vParams = null;
+                if (validationParameters != null)
+                {
+                    vParams = new ValidationParams(validationParameters.getSeed(), validationParameters.getCounter());
+                }
+                info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.dhpublicnumber, new DomainParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), vParams).toASN1Primitive()), new ASN1Integer(getX()));
+            }
+            else
+            {
+                info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(getX()));
+            }
+            return info.getEncoded(ASN1Encoding.DER);
+        }
+        catch (Exception e)
+        {              
+            return null;
+        }
+    }
+
+    public String toString()
+    {
+        return DHUtil.privateKeyToString("DH", x, new DHParameters(dhSpec.getP(), dhSpec.getG()));
+    }
+
+    public DHParameterSpec getParams()
+    {
+        return dhSpec;
+    }
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+
+    DHPrivateKeyParameters engineGetKeyParameters()
+    {
+        if (dhPrivateKey != null)
+        {
+            return dhPrivateKey;
+        }
+
+        if (dhSpec instanceof DHDomainParameterSpec)
+        {
+            return new DHPrivateKeyParameters(x, ((DHDomainParameterSpec)dhSpec).getDomainParameters());
+        }
+        return new DHPrivateKeyParameters(x, new DHParameters(dhSpec.getP(), dhSpec.getG(), null, dhSpec.getL()));
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DHPrivateKey))
+        {
+            return false;
+        }
+
+        DHPrivateKey other = (DHPrivateKey)o;
+
+        return this.getX().equals(other.getX())
+            && this.getParams().getG().equals(other.getParams().getG())
+            && this.getParams().getP().equals(other.getParams().getP())
+            && this.getParams().getL() == other.getParams().getL();
+    }
+
+    public int hashCode()
+    {
+        return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+                ^ this.getParams().getP().hashCode() ^ this.getParams().getL();
+    }
+
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        ASN1ObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    private void readObject(
+        ObjectInputStream   in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+        this.info = null;
+        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+    }
+
+    private void writeObject(
+        ObjectOutputStream  out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeObject(dhSpec.getP());
+        out.writeObject(dhSpec.getG());
+        out.writeInt(dhSpec.getL());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java
new file mode 100644
index 0000000..3288df1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java
@@ -0,0 +1,257 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.pkcs.DHParameter;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.DomainParameters;
+import com.android.internal.org.bouncycastle.asn1.x9.ValidationParams;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHValidationParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import com.android.internal.org.bouncycastle.jcajce.spec.DHDomainParameterSpec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCDHPublicKey
+    implements DHPublicKey
+{
+    static final long serialVersionUID = -216691575254424324L;
+    
+    private BigInteger              y;
+
+    private transient DHPublicKeyParameters   dhPublicKey;
+    private transient DHParameterSpec         dhSpec;
+    private transient SubjectPublicKeyInfo    info;
+    
+    BCDHPublicKey(
+        DHPublicKeySpec spec)
+    {
+        this.y = spec.getY();
+        this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+        this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(spec.getP(), spec.getG()));
+    }
+
+    BCDHPublicKey(
+        DHPublicKey key)
+    {
+        this.y = key.getY();
+        this.dhSpec = key.getParams();
+        this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG()));
+    }
+
+    BCDHPublicKey(
+        DHPublicKeyParameters params)
+    {
+        this.y = params.getY();
+        this.dhSpec = new DHDomainParameterSpec(params.getParameters());
+        this.dhPublicKey = params;
+    }
+
+    BCDHPublicKey(
+        BigInteger y,
+        DHParameterSpec dhSpec)
+    {
+        this.y = y;
+        this.dhSpec = dhSpec;
+
+        if (dhSpec instanceof DHDomainParameterSpec)
+        {
+            this.dhPublicKey = new DHPublicKeyParameters(y, ((DHDomainParameterSpec)dhSpec).getDomainParameters());
+        }
+        else
+        {
+            this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG()));
+        }
+    }
+
+    public BCDHPublicKey(
+        SubjectPublicKeyInfo info)
+    {
+        this.info = info;
+
+        ASN1Integer              derY;
+        try
+        {
+            derY = (ASN1Integer)info.parsePublicKey();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("invalid info structure in DH public key");
+        }
+
+        this.y = derY.getValue();
+
+        ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithm().getParameters());
+        ASN1ObjectIdentifier id = info.getAlgorithm().getAlgorithm();
+
+        // we need the PKCS check to handle older keys marked with the X9 oid.
+        if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement) || isPKCSParam(seq))
+        {
+            DHParameter             params = DHParameter.getInstance(seq);
+
+            if (params.getL() != null)
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+            }
+            else
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+            }
+            this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG()));
+        }
+        else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            DomainParameters params = DomainParameters.getInstance(seq);
+
+            ValidationParams validationParams = params.getValidationParams();
+            if (validationParams != null)
+            {
+                this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(params.getP(), params.getG(), params.getQ(), params.getJ(),
+                                            new DHValidationParameters(validationParams.getSeed(), validationParams.getPgenCounter().intValue())));
+            }
+            else
+            {
+                this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), null));
+            }
+            this.dhSpec = new DHDomainParameterSpec(dhPublicKey.getParameters());
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown algorithm type: " + id);
+        }
+    }
+
+    public String getAlgorithm()
+    {
+        return "DH";
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        if (info != null)
+        {
+            return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+        }
+
+        if (dhSpec instanceof DHDomainParameterSpec && ((DHDomainParameterSpec)dhSpec).getQ() != null)
+        {
+            DHParameters params = ((DHDomainParameterSpec)dhSpec).getDomainParameters();
+            DHValidationParameters validationParameters = params.getValidationParameters();
+            ValidationParams vParams = null;
+            if (validationParameters != null)
+            {
+                vParams = new ValidationParams(validationParameters.getSeed(), validationParameters.getCounter());
+            }
+            return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.dhpublicnumber, new DomainParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), vParams).toASN1Primitive()), new ASN1Integer(y));
+        }
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(y));
+    }
+
+    public String toString()
+    {
+        return DHUtil.publicKeyToString("DH", y, new DHParameters(dhSpec.getP(), dhSpec.getG()));
+    }
+
+    public DHParameterSpec getParams()
+    {
+        return dhSpec;
+    }
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+
+    public DHPublicKeyParameters engineGetKeyParameters()
+    {
+        return dhPublicKey;
+    }
+
+    private boolean isPKCSParam(ASN1Sequence seq)
+    {
+        if (seq.size() == 2)
+        {
+            return true;
+        }
+        
+        if (seq.size() > 3)
+        {
+            return false;
+        }
+
+        ASN1Integer l = ASN1Integer.getInstance(seq.getObjectAt(2));
+        ASN1Integer p = ASN1Integer.getInstance(seq.getObjectAt(0));
+
+        if (l.getValue().compareTo(BigInteger.valueOf(p.getValue().bitLength())) > 0)
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    public int hashCode()
+    {
+        return this.getY().hashCode() ^ this.getParams().getG().hashCode()
+                ^ this.getParams().getP().hashCode() ^ this.getParams().getL();
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DHPublicKey))
+        {
+            return false;
+        }
+
+        DHPublicKey other = (DHPublicKey)o;
+
+        return this.getY().equals(other.getY())
+            && this.getParams().getG().equals(other.getParams().getG())
+            && this.getParams().getP().equals(other.getParams().getP())
+            && this.getParams().getL() == other.getParams().getL();
+    }
+
+    private void readObject(
+        ObjectInputStream   in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+        this.info = null;
+    }
+
+    private void writeObject(
+        ObjectOutputStream  out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeObject(dhSpec.getP());
+        out.writeObject(dhSpec.getG());
+        out.writeInt(dhSpec.getL());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java
new file mode 100644
index 0000000..72bd708
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java
@@ -0,0 +1,46 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Fingerprint;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+class DHUtil
+{
+    static String privateKeyToString(String algorithm, BigInteger x, DHParameters dhParams)
+    {
+        StringBuffer buf = new StringBuffer();
+        String       nl = Strings.lineSeparator();
+
+        BigInteger y = dhParams.getG().modPow(x, dhParams.getP());
+
+        buf.append(algorithm);
+        buf.append(" Private Key [").append(generateKeyFingerprint(y, dhParams)).append("]").append(nl);
+        buf.append("              Y: ").append(y.toString(16)).append(nl);
+
+        return buf.toString();
+    }
+
+    static String publicKeyToString(String algorithm, BigInteger y, DHParameters dhParams)
+    {
+        StringBuffer buf = new StringBuffer();
+        String       nl = Strings.lineSeparator();
+
+        buf.append(algorithm);
+        buf.append(" Public Key [").append(generateKeyFingerprint(y, dhParams)).append("]").append(nl);
+        buf.append("             Y: ").append(y.toString(16)).append(nl);
+
+        return buf.toString();
+    }
+
+    private static String generateKeyFingerprint(BigInteger y, DHParameters dhParams)
+    {
+            return new Fingerprint(
+                Arrays.concatenate(
+                    y.toByteArray(),
+                    dhParams.getP().toByteArray(), dhParams.getG().toByteArray())).toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
new file mode 100644
index 0000000..97a1e6c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
@@ -0,0 +1,730 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.android.internal.org.bouncycastle.crypto.BasicAgreement;
+import com.android.internal.org.bouncycastle.crypto.DerivationFunction;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.agreement.DHUnifiedAgreement;
+// import org.bouncycastle.crypto.agreement.MQVBasicAgreement;
+// import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator;
+// import org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator;
+// import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
+// import org.bouncycastle.crypto.params.DHMQVPrivateParameters;
+// import org.bouncycastle.crypto.params.DHMQVPublicParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPublicKeyParameters;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.params.DHUPrivateParameters;
+// import org.bouncycastle.crypto.params.DHUPublicParameters;
+// import org.bouncycastle.crypto.util.DigestFactory;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi;
+import com.android.internal.org.bouncycastle.jcajce.spec.DHDomainParameterSpec;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.spec.DHUParameterSpec;
+// import org.bouncycastle.jcajce.spec.MQVParameterSpec;
+import com.android.internal.org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
+
+/**
+ * Diffie-Hellman key agreement. There's actually a better way of doing this
+ * if you are using long term public keys, see the light-weight version for
+ * details.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyAgreementSpi
+    extends BaseAgreementSpi
+{
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+    private static final BigInteger TWO = BigInteger.valueOf(2);
+
+    // Android-removed: Unsupported algorithms
+    // private final DHUnifiedAgreement unifiedAgreement;
+    private final BasicAgreement mqvAgreement;
+
+    // Android-removed: Unsupported algorithms
+    // private DHUParameterSpec dheParameters;
+    // private MQVParameterSpec mqvParameters;
+
+    private BigInteger      x;
+    private BigInteger      p;
+    private BigInteger      g;
+
+    private byte[]          result;
+
+    public KeyAgreementSpi()
+    {
+        this("Diffie-Hellman", null);
+    }
+
+    public KeyAgreementSpi(
+        String kaAlgorithm,
+        DerivationFunction kdf)
+    {
+        super(kaAlgorithm, kdf);
+        // Android-removed: Unsupported algorithm
+        // this.unifiedAgreement = null;
+        this.mqvAgreement = null;
+    }
+
+    // BEGIN Android-removed: Unsupported algorithm
+    /*
+    public KeyAgreementSpi(
+        String kaAlgorithm,
+        DHUnifiedAgreement unifiedAgreement,
+        DerivationFunction kdf)
+    {
+        super(kaAlgorithm, kdf);
+        this.unifiedAgreement = unifiedAgreement;
+        this.mqvAgreement = null;
+    }
+    */
+    // END Android-removed: Unsupported algorithm
+
+    public KeyAgreementSpi(
+        String kaAlgorithm,
+        BasicAgreement mqvAgreement,
+        DerivationFunction kdf)
+    {
+        super(kaAlgorithm, kdf);
+        // Android-removed: Unsupported algorithm
+        // this.unifiedAgreement = null;
+        this.mqvAgreement = mqvAgreement;
+    }
+
+    protected byte[] bigIntToBytes(
+        BigInteger    r)
+    {
+        //
+        // RFC 2631 (2.1.2) specifies that the secret should be padded with leading zeros if necessary
+        // must be the same length as p
+        //
+        int expectedLength = (p.bitLength() + 7) / 8;
+
+        byte[]    tmp = r.toByteArray();
+
+        if (tmp.length == expectedLength)
+        {
+            return tmp;
+        }
+
+        if (tmp[0] == 0 && tmp.length == expectedLength + 1)
+        {
+            byte[]    rv = new byte[tmp.length - 1];
+            
+            System.arraycopy(tmp, 1, rv, 0, rv.length);
+            return rv;
+        }
+
+        // tmp must be shorter than expectedLength
+        // pad to the left with zeros.
+        byte[]    rv = new byte[expectedLength];
+
+        System.arraycopy(tmp, 0, rv, rv.length - tmp.length, tmp.length);
+
+        return rv;
+    }
+    
+    protected Key engineDoPhase(
+        Key     key,
+        boolean lastPhase) 
+        throws InvalidKeyException, IllegalStateException
+    {
+        if (x == null)
+        {
+            throw new IllegalStateException("Diffie-Hellman not initialised.");
+        }
+
+        if (!(key instanceof DHPublicKey))
+        {
+            throw new InvalidKeyException("DHKeyAgreement doPhase requires DHPublicKey");
+        }
+        DHPublicKey pubKey = (DHPublicKey)key;
+
+        if (!pubKey.getParams().getG().equals(g) || !pubKey.getParams().getP().equals(p))
+        {
+            throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!");
+        }
+
+        BigInteger peerY = ((DHPublicKey)key).getY();
+        if (peerY == null || peerY.compareTo(TWO) < 0
+            || peerY.compareTo(p.subtract(ONE)) >= 0)
+        {
+            throw new InvalidKeyException("Invalid DH PublicKey");
+        }
+
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        if (unifiedAgreement != null)
+        {
+            if (!lastPhase)
+            {
+                throw new IllegalStateException("unified Diffie-Hellman can use only two key pairs");
+            }
+
+            DHPublicKeyParameters staticKey = generatePublicKeyParameter((PublicKey)key);
+            DHPublicKeyParameters ephemKey = generatePublicKeyParameter(dheParameters.getOtherPartyEphemeralKey());
+
+            DHUPublicParameters pKey = new DHUPublicParameters(staticKey, ephemKey);
+
+            result = unifiedAgreement.calculateAgreement(pKey);
+
+            return null;
+        }
+        else if (mqvAgreement != null)
+        {
+            if (!lastPhase)
+            {
+                throw new IllegalStateException("MQV Diffie-Hellman can use only two key pairs");
+            }
+
+            DHPublicKeyParameters staticKey = generatePublicKeyParameter((PublicKey)key);
+            DHPublicKeyParameters ephemKey = generatePublicKeyParameter(mqvParameters.getOtherPartyEphemeralKey());
+
+            DHMQVPublicParameters pKey = new DHMQVPublicParameters(staticKey, ephemKey);
+
+            result = bigIntToBytes(mqvAgreement.calculateAgreement(pKey));
+
+            return null;
+        }
+        else
+        {
+        */
+        // END Android-removed: Unsupported algorithms
+            BigInteger res = peerY.modPow(x, p);
+            if (res.compareTo(ONE) == 0)
+            {
+                throw new InvalidKeyException("Shared key can't be 1");
+            }
+
+            result = bigIntToBytes(res);
+
+            if (lastPhase)
+            {
+                return null;
+            }
+
+            return new BCDHPublicKey(res, pubKey.getParams());
+        /*
+        }
+        */
+    }
+
+    protected byte[] engineGenerateSecret() 
+        throws IllegalStateException
+    {
+        if (x == null)
+        {
+            throw new IllegalStateException("Diffie-Hellman not initialised.");
+        }
+
+        return super.engineGenerateSecret();
+    }
+
+    protected int engineGenerateSecret(
+        byte[]  sharedSecret,
+        int     offset) 
+        throws IllegalStateException, ShortBufferException
+    {
+        if (x == null)
+        {
+            throw new IllegalStateException("Diffie-Hellman not initialised.");
+        }
+
+        return super.engineGenerateSecret(sharedSecret, offset);
+    }
+
+    protected SecretKey engineGenerateSecret(
+        String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        if (x == null)
+        {
+            throw new IllegalStateException("Diffie-Hellman not initialised.");
+        }
+
+        // for JSSE compatibility
+        if (algorithm.equals("TlsPremasterSecret"))
+        {
+            return new SecretKeySpec(trimZeroes(result), algorithm);
+        }
+
+        return super.engineGenerateSecret(algorithm);
+    }
+
+    protected void engineInit(
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random) 
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        if (!(key instanceof DHPrivateKey))
+        {
+            throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey for initialisation");
+        }
+        DHPrivateKey    privKey = (DHPrivateKey)key;
+
+        if (params != null)
+        {
+            if (params instanceof DHParameterSpec)    // p, g override.
+            {
+                DHParameterSpec p = (DHParameterSpec)params;
+
+                this.p = p.getP();
+                this.g = p.getG();
+                // Android-removed: Unsupported algorithm
+                // this.dheParameters = null;
+                this.ukmParameters = null;
+            }
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            else if (params instanceof DHUParameterSpec)
+            {
+                if (unifiedAgreement == null)
+                {
+                    throw new InvalidAlgorithmParameterException("agreement algorithm not DHU based");
+                }
+                this.p = privKey.getParams().getP();
+                this.g = privKey.getParams().getG();
+                this.dheParameters = (DHUParameterSpec)params;
+                this.ukmParameters = ((DHUParameterSpec)params).getUserKeyingMaterial();
+
+                if (dheParameters.getEphemeralPublicKey() != null)
+                {
+                    unifiedAgreement.init(new DHUPrivateParameters(generatePrivateKeyParameter(privKey),
+                        generatePrivateKeyParameter(dheParameters.getEphemeralPrivateKey()),
+                        generatePublicKeyParameter(dheParameters.getEphemeralPublicKey())));
+                }
+                else
+                {
+                    unifiedAgreement.init(new DHUPrivateParameters(generatePrivateKeyParameter(privKey),
+                            generatePrivateKeyParameter(dheParameters.getEphemeralPrivateKey())));
+                }
+            }
+            else if (params instanceof MQVParameterSpec)
+            {
+                if (mqvAgreement == null)
+                {
+                    throw new InvalidAlgorithmParameterException("agreement algorithm not MQV based");
+                }
+                this.p = privKey.getParams().getP();
+                this.g = privKey.getParams().getG();
+                this.mqvParameters = (MQVParameterSpec)params;
+                this.ukmParameters = ((MQVParameterSpec)params).getUserKeyingMaterial();
+
+                if (mqvParameters.getEphemeralPublicKey() != null)
+                {
+                    mqvAgreement.init(new DHMQVPrivateParameters(generatePrivateKeyParameter(privKey),
+                        generatePrivateKeyParameter(mqvParameters.getEphemeralPrivateKey()),
+                        generatePublicKeyParameter(mqvParameters.getEphemeralPublicKey())));
+                }
+                else
+                {
+                    mqvAgreement.init(new DHMQVPrivateParameters(generatePrivateKeyParameter(privKey),
+                            generatePrivateKeyParameter(mqvParameters.getEphemeralPrivateKey())));
+                }
+            }
+            */
+            // END Android-removed: Unsupported algorithms
+            else if (params instanceof UserKeyingMaterialSpec)
+            {
+                if (kdf == null)
+                {
+                    throw new InvalidAlgorithmParameterException("no KDF specified for UserKeyingMaterialSpec");
+                }
+                this.p = privKey.getParams().getP();
+                this.g = privKey.getParams().getG();
+                // Android-removed: Unsupported algorithm
+                // this.dheParameters = null;
+                this.ukmParameters = ((UserKeyingMaterialSpec)params).getUserKeyingMaterial();
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("DHKeyAgreement only accepts DHParameterSpec");
+            }
+        }
+        else
+        {
+            this.p = privKey.getParams().getP();
+            this.g = privKey.getParams().getG();
+        }
+
+        this.x = privKey.getX();
+        this.result = bigIntToBytes(x);
+    }
+
+    protected void engineInit(
+        Key             key,
+        SecureRandom    random) 
+        throws InvalidKeyException
+    {
+        if (!(key instanceof DHPrivateKey))
+        {
+            throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey");
+        }
+
+        DHPrivateKey    privKey = (DHPrivateKey)key;
+
+        this.p = privKey.getParams().getP();
+        this.g = privKey.getParams().getG();
+        this.x = privKey.getX();
+        this.result = bigIntToBytes(x);
+    }
+
+    protected byte[] calcSecret()
+    {
+        return result;
+    }
+
+    private DHPrivateKeyParameters generatePrivateKeyParameter(PrivateKey privKey)
+        throws InvalidKeyException
+    {
+        if (privKey instanceof DHPrivateKey)
+        {
+            if (privKey instanceof BCDHPrivateKey)
+            {
+                return ((BCDHPrivateKey)privKey).engineGetKeyParameters();
+            }
+            else
+            {
+                DHPrivateKey pub = (DHPrivateKey)privKey;
+
+                DHParameterSpec params = pub.getParams();
+                return new DHPrivateKeyParameters(pub.getX(),
+                            new DHParameters(params.getP(), params.getG(), null, params.getL()));
+            }
+        }
+        else
+        {
+            throw new InvalidKeyException("private key not a DHPrivateKey");
+        }
+    }
+
+    private DHPublicKeyParameters generatePublicKeyParameter(PublicKey pubKey)
+        throws InvalidKeyException
+    {
+        if (pubKey instanceof DHPublicKey)
+        {
+            if (pubKey instanceof BCDHPublicKey)
+            {
+                return ((BCDHPublicKey)pubKey).engineGetKeyParameters();
+            }
+            else
+            {
+                DHPublicKey pub = (DHPublicKey)pubKey;
+
+                DHParameterSpec params = pub.getParams();
+
+                if (params instanceof DHDomainParameterSpec)
+                {
+                    return new DHPublicKeyParameters(pub.getY(), ((DHDomainParameterSpec)params).getDomainParameters());
+                }
+                return new DHPublicKeyParameters(pub.getY(),
+                            new DHParameters(params.getP(), params.getG(), null, params.getL()));
+            }
+        }
+        else
+        {
+            throw new InvalidKeyException("public key not a DHPublicKey");
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class DHwithRFC2631KDF
+        extends KeyAgreementSpi
+    {
+        public DHwithRFC2631KDF()
+        {
+            super("DHwithRFC2631KDF", new DHKEKGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class DHwithSHA1KDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA1KDF()
+        {
+            super("DHwithSHA1CKDF", new KDF2BytesGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class DHwithSHA224KDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA224KDF()
+        {
+            super("DHwithSHA224CKDF", new KDF2BytesGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class DHwithSHA256KDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA256KDF()
+        {
+            super("DHwithSHA256CKDF", new KDF2BytesGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class DHwithSHA384KDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA384KDF()
+        {
+            super("DHwithSHA384KDF", new KDF2BytesGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class DHwithSHA512KDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA512KDF()
+        {
+            super("DHwithSHA512KDF", new KDF2BytesGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class DHwithSHA1CKDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA1CKDF()
+        {
+            super("DHwithSHA1CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class DHwithSHA224CKDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA224CKDF()
+        {
+            super("DHwithSHA224CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class DHwithSHA256CKDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA256CKDF()
+        {
+            super("DHwithSHA256CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class DHwithSHA384CKDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA384CKDF()
+        {
+            super("DHwithSHA384CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class DHwithSHA512CKDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA512CKDF()
+        {
+            super("DHwithSHA512CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class DHUwithSHA1KDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA1KDF()
+        {
+            super("DHUwithSHA1KDF", new DHUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class DHUwithSHA224KDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA224KDF()
+        {
+            super("DHUwithSHA224KDF", new DHUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class DHUwithSHA256KDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA256KDF()
+        {
+            super("DHUwithSHA256KDF", new DHUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class DHUwithSHA384KDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA384KDF()
+        {
+            super("DHUwithSHA384KDF", new DHUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class DHUwithSHA512KDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA512KDF()
+        {
+            super("DHUwithSHA512KDF", new DHUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class DHUwithSHA1CKDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA1CKDF()
+        {
+            super("DHUwithSHA1CKDF", new DHUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class DHUwithSHA224CKDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA224CKDF()
+        {
+            super("DHUwithSHA224CKDF", new DHUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class DHUwithSHA256CKDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA256CKDF()
+        {
+            super("DHUwithSHA256CKDF", new DHUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class DHUwithSHA384CKDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA384CKDF()
+        {
+            super("DHUwithSHA384CKDF", new DHUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class DHUwithSHA512CKDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA512CKDF()
+        {
+            super("DHUwithSHA512CKDF", new DHUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class MQVwithSHA1KDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA1KDF()
+        {
+            super("MQVwithSHA1KDF", new MQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class MQVwithSHA224KDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA224KDF()
+        {
+            super("MQVwithSHA224KDF", new MQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class MQVwithSHA256KDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA256KDF()
+        {
+            super("MQVwithSHA256KDF", new MQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class MQVwithSHA384KDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA384KDF()
+        {
+            super("MQVwithSHA384KDF", new MQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class MQVwithSHA512KDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA512KDF()
+        {
+            super("MQVwithSHA512KDF", new MQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class MQVwithSHA1CKDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA1CKDF()
+        {
+            super("MQVwithSHA1CKDF", new MQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class MQVwithSHA224CKDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA224CKDF()
+        {
+            super("MQVwithSHA224CKDF", new MQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class MQVwithSHA256CKDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA256CKDF()
+        {
+            super("MQVwithSHA256CKDF", new MQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class MQVwithSHA384CKDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA384CKDF()
+        {
+            super("MQVwithSHA384CKDF", new MQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class MQVwithSHA512CKDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA512CKDF()
+        {
+            super("MQVwithSHA512CKDF", new MQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java
new file mode 100644
index 0000000..b0f6904
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java
@@ -0,0 +1,140 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyFactorySpi
+    extends BaseKeyFactorySpi
+{
+    public KeyFactorySpi()
+    {
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key key,
+        Class spec)
+        throws InvalidKeySpecException
+    {
+        if (spec.isAssignableFrom(DHPrivateKeySpec.class) && key instanceof DHPrivateKey)
+        {
+            DHPrivateKey k = (DHPrivateKey)key;
+
+            return new DHPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getG());
+        }
+        else if (spec.isAssignableFrom(DHPublicKeySpec.class) && key instanceof DHPublicKey)
+        {
+            DHPublicKey k = (DHPublicKey)key;
+
+            return new DHPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getG());
+        }
+
+        return super.engineGetKeySpec(key, spec);
+    }
+
+    protected Key engineTranslateKey(
+        Key key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DHPublicKey)
+        {
+            return new BCDHPublicKey((DHPublicKey)key);
+        }
+        else if (key instanceof DHPrivateKey)
+        {
+            return new BCDHPrivateKey((DHPrivateKey)key);
+        }
+
+        throw new InvalidKeyException("key type unknown");
+    }
+
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof DHPrivateKeySpec)
+        {
+            return new BCDHPrivateKey((DHPrivateKeySpec)keySpec);
+        }
+
+        return super.engineGeneratePrivate(keySpec);
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof DHPublicKeySpec)
+        {
+            try
+            {
+                return new BCDHPublicKey((DHPublicKeySpec)keySpec);
+            }
+            catch (IllegalArgumentException e)
+            {
+                throw new ExtendedInvalidKeySpecException(e.getMessage(), e);
+            }
+        }
+
+        return super.engineGeneratePublic(keySpec);
+    }
+
+    public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+        if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+            return new BCDHPrivateKey(keyInfo);
+        }
+        else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            return new BCDHPrivateKey(keyInfo);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+        if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+            return new BCDHPublicKey(keyInfo);
+        }
+        else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            return new BCDHPublicKey(keyInfo);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..dfe6893
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
@@ -0,0 +1,153 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.generators.DHBasicKeyPairGenerator;
+import com.android.internal.org.bouncycastle.crypto.generators.DHParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.DHKeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PrimeCertaintyCalculator;
+import com.android.internal.org.bouncycastle.jcajce.spec.DHDomainParameterSpec;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.util.Integers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyPairGeneratorSpi
+    extends java.security.KeyPairGenerator
+{
+    private static Hashtable params = new Hashtable();
+    private static Object    lock = new Object();
+
+    DHKeyGenerationParameters param;
+    DHBasicKeyPairGenerator engine = new DHBasicKeyPairGenerator();
+    int strength = 2048;
+    SecureRandom random = CryptoServicesRegistrar.getSecureRandom();
+    boolean initialised = false;
+
+    public KeyPairGeneratorSpi()
+    {
+        super("DH");
+    }
+
+    public void initialize(
+        int strength,
+        SecureRandom random)
+    {
+        this.strength = strength;
+        this.random = random;
+        this.initialised = false;
+    }
+
+    public void initialize(
+        AlgorithmParameterSpec params,
+        SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(params instanceof DHParameterSpec))
+        {
+            throw new InvalidAlgorithmParameterException("parameter object not a DHParameterSpec");
+        }
+        DHParameterSpec dhParams = (DHParameterSpec)params;
+
+        try
+        {
+            param = convertParams(random, dhParams);
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw new InvalidAlgorithmParameterException(e.getMessage(), e);
+        }
+        
+        engine.init(param);
+        initialised = true;
+    }
+
+    private DHKeyGenerationParameters convertParams(SecureRandom random, DHParameterSpec dhParams)
+    {
+        // BEGIN Android-removed: Don't special-case DHDomainParameterSpec
+        // When DHDomainParameterSpec is special-cased here, it supplies a value for q that
+        // ultimately results in a smaller value of x, which runs afoul of the Wycheproof test
+        // com.google.security.wycheproof.DhTest.testKeyPairGenerator().  See the docs in DhTest
+        // for more details of why that requirement is made.
+        //
+        // While we believe this code would be safe (and likely somewhat faster), in the interest
+        // of being conservative we've disabled it to preserve the old behavior that also passes
+        // the Wycheproof test.
+        /*
+        if (dhParams instanceof DHDomainParameterSpec)
+        {
+            return new DHKeyGenerationParameters(random, ((DHDomainParameterSpec)dhParams).getDomainParameters());
+        }
+        */
+        // END Android-removed: Don't special-case DHDomainParameterSpec
+        return new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG(), null, dhParams.getL()));
+    }
+
+    public KeyPair generateKeyPair()
+    {
+        if (!initialised)
+        {
+            Integer paramStrength = Integers.valueOf(strength);
+
+            if (params.containsKey(paramStrength))
+            {
+                param = (DHKeyGenerationParameters)params.get(paramStrength);
+            }
+            else
+            {
+                DHParameterSpec dhParams = BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(strength);
+
+                if (dhParams != null)
+                {   
+                    param = convertParams(random, dhParams);
+                }
+                else
+                {
+                    synchronized (lock)
+                    {
+                        // we do the check again in case we were blocked by a generator for
+                        // our key size.
+                        if (params.containsKey(paramStrength))
+                        {
+                            param = (DHKeyGenerationParameters)params.get(paramStrength);
+                        }
+                        else
+                        {
+
+                            DHParametersGenerator pGen = new DHParametersGenerator();
+
+                            pGen.init(strength, PrimeCertaintyCalculator.getDefaultCertainty(strength), random);
+
+                            param = new DHKeyGenerationParameters(random, pGen.generateParameters());
+
+                            params.put(paramStrength, param);
+                        }
+                    }
+                }
+            }
+
+            engine.init(param);
+
+            initialised = true;
+        }
+
+        AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+        DHPublicKeyParameters pub = (DHPublicKeyParameters)pair.getPublic();
+        DHPrivateKeyParameters priv = (DHPrivateKeyParameters)pair.getPrivate();
+
+        return new KeyPair(new BCDHPublicKey(pub), new BCDHPrivateKey(priv));
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 0000000..e8a2fb1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,115 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.digests.SHA256Digest;
+import com.android.internal.org.bouncycastle.crypto.generators.DSAParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameterGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.BaseAlgorithmParameterGeneratorSpi;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PrimeCertaintyCalculator;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlgorithmParameterGeneratorSpi
+    extends BaseAlgorithmParameterGeneratorSpi
+{
+    protected SecureRandom random;
+    // Android-changed: Change default strength to 1024
+    // In 1.57, the default strength was changed to 2048.  We keep it at 1024 for app
+    // compatibility, particularly because the default digest (SHA-1) doesn't have
+    // a sufficiently long digest to work with 2048-bit keys.
+    protected int strength = 1024;
+    protected DSAParameterGenerationParameters params;
+
+    protected void engineInit(
+        int strength,
+        SecureRandom random)
+    {
+        if (strength < 512 || strength > 3072)
+        {
+            throw new InvalidParameterException("strength must be from 512 - 3072");
+        }
+
+        if (strength <= 1024 && strength % 64 != 0)
+        {
+            throw new InvalidParameterException("strength must be a multiple of 64 below 1024 bits.");
+        }
+
+        if (strength > 1024 && strength % 1024 != 0)
+        {
+            throw new InvalidParameterException("strength must be a multiple of 1024 above 1024 bits.");
+        }
+
+        this.strength = strength;
+        this.random = random;
+    }
+
+    protected void engineInit(
+        AlgorithmParameterSpec genParamSpec,
+        SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DSA parameter generation.");
+    }
+
+    protected AlgorithmParameters engineGenerateParameters()
+    {
+        DSAParametersGenerator pGen;
+
+        if (strength <= 1024)
+        {
+            pGen = new DSAParametersGenerator();
+        }
+        else
+        {
+            pGen = new DSAParametersGenerator(new SHA256Digest());
+        }
+
+        if (random == null)
+        {
+            random = CryptoServicesRegistrar.getSecureRandom();
+        }
+
+        int certainty = PrimeCertaintyCalculator.getDefaultCertainty(strength);
+
+        if (strength == 1024)
+        {
+            params = new DSAParameterGenerationParameters(1024, 160, certainty, random);
+            pGen.init(params);
+        }
+        else if (strength > 1024)
+        {
+            params = new DSAParameterGenerationParameters(strength, 256, certainty, random);
+            pGen.init(params);
+        }
+        else
+        {
+            pGen.init(strength, certainty, random);
+        }
+
+        DSAParameters p = pGen.generateParameters();
+
+        AlgorithmParameters params;
+
+        try
+        {
+            params = createParametersInstance("DSA");
+            params.init(new DSAParameterSpec(p.getP(), p.getQ(), p.getG()));
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e.getMessage());
+        }
+
+        return params;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..3e34e06
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java
@@ -0,0 +1,135 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.x509.DSAParameter;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlgorithmParametersSpi
+    extends java.security.AlgorithmParametersSpi
+{
+    DSAParameterSpec currentSpec;
+
+    protected boolean isASN1FormatString(String format)
+    {
+        return format == null || format.equals("ASN.1");
+    }
+
+    protected AlgorithmParameterSpec engineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == null)
+        {
+            throw new NullPointerException("argument to getParameterSpec must not be null");
+        }
+
+        return localEngineGetParameterSpec(paramSpec);
+    }
+
+    /**
+     * Return the X.509 ASN.1 structure DSAParameter.
+     * <pre>
+     *  DSAParameter ::= SEQUENCE {
+     *                   prime INTEGER, -- p
+     *                   subprime INTEGER, -- q
+     *                   base INTEGER, -- g}
+     * </pre>
+     */
+    protected byte[] engineGetEncoded()
+    {
+        DSAParameter dsaP = new DSAParameter(currentSpec.getP(), currentSpec.getQ(), currentSpec.getG());
+
+        try
+        {
+            return dsaP.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("Error encoding DSAParameters");
+        }
+    }
+
+    protected byte[] engineGetEncoded(
+        String format)
+    {
+        if (isASN1FormatString(format))
+        {
+            return engineGetEncoded();
+        }
+
+        return null;
+    }
+
+    protected AlgorithmParameterSpec localEngineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == DSAParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
+        {
+            return currentSpec;
+        }
+
+        throw new InvalidParameterSpecException("unknown parameter spec passed to DSA parameters object.");
+    }
+
+    protected void engineInit(
+        AlgorithmParameterSpec paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (!(paramSpec instanceof DSAParameterSpec))
+        {
+            throw new InvalidParameterSpecException("DSAParameterSpec required to initialise a DSA algorithm parameters object");
+        }
+
+        this.currentSpec = (DSAParameterSpec)paramSpec;
+    }
+
+    protected void engineInit(
+        byte[] params)
+        throws IOException
+    {
+        try
+        {
+            DSAParameter dsaP = DSAParameter.getInstance(ASN1Primitive.fromByteArray(params));
+
+            currentSpec = new DSAParameterSpec(dsaP.getP(), dsaP.getQ(), dsaP.getG());
+        }
+        catch (ClassCastException e)
+        {
+            throw new IOException("Not a valid DSA Parameter encoding.");
+        }
+        catch (ArrayIndexOutOfBoundsException e)
+        {
+            throw new IOException("Not a valid DSA Parameter encoding.");
+        }
+    }
+
+    protected void engineInit(
+        byte[] params,
+        String format)
+        throws IOException
+    {
+        if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+        {
+            engineInit(params);
+        }
+        else
+        {
+            throw new IOException("Unknown parameter format " + format);
+        }
+    }
+
+    protected String engineToString()
+    {
+        return "DSA Parameters";
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java
new file mode 100644
index 0000000..8b9db67
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java
@@ -0,0 +1,185 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.DSAParameter;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import com.android.internal.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCDSAPrivateKey
+    implements DSAPrivateKey, PKCS12BagAttributeCarrier
+{
+    private static final long serialVersionUID = -4677259546958385734L;
+
+    private BigInteger          x;
+    private transient DSAParams dsaSpec;
+
+    private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected BCDSAPrivateKey()
+    {
+    }
+
+    BCDSAPrivateKey(
+        DSAPrivateKey key)
+    {
+        this.x = key.getX();
+        this.dsaSpec = key.getParams();
+    }
+
+    BCDSAPrivateKey(
+        DSAPrivateKeySpec spec)
+    {
+        this.x = spec.getX();
+        this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+    }
+
+    public BCDSAPrivateKey(
+        PrivateKeyInfo info)
+        throws IOException
+    {
+        DSAParameter    params = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+        ASN1Integer      derX = (ASN1Integer)info.parsePrivateKey();
+
+        this.x = derX.getValue();
+        this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+    }
+
+    BCDSAPrivateKey(
+        DSAPrivateKeyParameters params)
+    {
+        this.x = params.getX();
+        this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+    }
+
+    public String getAlgorithm()
+    {
+        return "DSA";
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).toASN1Primitive()), new ASN1Integer(getX()));
+    }
+
+    public DSAParams getParams()
+    {
+        return dsaSpec;
+    }
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DSAPrivateKey))
+        {
+            return false;
+        }
+        
+        DSAPrivateKey other = (DSAPrivateKey)o;
+        
+        return this.getX().equals(other.getX()) 
+            && this.getParams().getG().equals(other.getParams().getG()) 
+            && this.getParams().getP().equals(other.getParams().getP()) 
+            && this.getParams().getQ().equals(other.getParams().getQ());
+    }
+
+    public int hashCode()
+    {
+        return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+                ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+    }
+
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        ASN1ObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeObject(dsaSpec.getP());
+        out.writeObject(dsaSpec.getQ());
+        out.writeObject(dsaSpec.getG());
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = Strings.lineSeparator();
+
+        BigInteger y = getParams().getG().modPow(x, getParams().getP());
+
+        buf.append("DSA Private Key [").append(DSAUtil.generateKeyFingerprint(y, getParams())).append("]").append(nl);
+        buf.append("            Y: ").append(y.toString(16)).append(nl);
+
+        return buf.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
new file mode 100644
index 0000000..cad5df5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
@@ -0,0 +1,222 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPublicKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.DSAParameter;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCDSAPublicKey
+    implements DSAPublicKey
+{
+    private static final long serialVersionUID = 1752452449903495175L;
+    private static BigInteger ZERO = BigInteger.valueOf(0);
+
+    private BigInteger      y;
+
+    private transient DSAPublicKeyParameters lwKeyParams;
+    private transient DSAParams              dsaSpec;
+
+    BCDSAPublicKey(
+        DSAPublicKeySpec spec)
+    {
+        this.y = spec.getY();
+        this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+        this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec));
+    }
+
+    BCDSAPublicKey(
+        DSAPublicKey key)
+    {
+        this.y = key.getY();
+        this.dsaSpec = key.getParams();
+        this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec));
+    }
+
+    BCDSAPublicKey(
+        DSAPublicKeyParameters params)
+    {
+        this.y = params.getY();
+        if (params != null)
+        {
+            this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+        }
+        else
+        {
+            this.dsaSpec = null;
+        }
+        this.lwKeyParams = params;
+    }
+
+    public BCDSAPublicKey(
+        SubjectPublicKeyInfo info)
+    {
+        ASN1Integer              derY;
+
+        try
+        {
+            derY = (ASN1Integer)info.parsePublicKey();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("invalid info structure in DSA public key");
+        }
+
+        this.y = derY.getValue();
+
+        if (isNotNull(info.getAlgorithm().getParameters()))
+        {
+            DSAParameter params = DSAParameter.getInstance(info.getAlgorithm().getParameters());
+            
+            this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+        }
+        else
+        {
+            this.dsaSpec = null;
+        }
+
+        this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec));
+    }
+
+    private boolean isNotNull(ASN1Encodable parameters)
+    {
+        return parameters != null && !DERNull.INSTANCE.equals(parameters.toASN1Primitive());
+    }
+
+    public String getAlgorithm()
+    {
+        return "DSA";
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    DSAPublicKeyParameters engineGetKeyParameters()
+    {
+        return lwKeyParams;
+    }
+
+    public byte[] getEncoded()
+    {
+        if (dsaSpec == null)
+        {
+            return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new ASN1Integer(y));
+        }
+
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).toASN1Primitive()), new ASN1Integer(y));
+    }
+
+    public DSAParams getParams()
+    {
+        return dsaSpec;
+    }
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = Strings.lineSeparator();
+
+        buf.append("DSA Public Key [").append(DSAUtil.generateKeyFingerprint(y, getParams())).append("]").append(nl);
+        buf.append("            Y: ").append(this.getY().toString(16)).append(nl);
+
+        return buf.toString();
+    }
+
+    public int hashCode()
+    {
+        if (dsaSpec != null)
+        {
+            return this.getY().hashCode() ^ this.getParams().getG().hashCode()
+                ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+        }
+        else
+        {
+            return this.getY().hashCode();
+        }
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DSAPublicKey))
+        {
+            return false;
+        }
+        
+        DSAPublicKey other = (DSAPublicKey)o;
+
+        if (this.dsaSpec != null)
+        {
+            return this.getY().equals(other.getY())
+                && other.getParams() != null
+                && this.getParams().getG().equals(other.getParams().getG())
+                && this.getParams().getP().equals(other.getParams().getP())
+                && this.getParams().getQ().equals(other.getParams().getQ());
+        }
+        else
+        {
+            return this.getY().equals(other.getY()) && other.getParams() == null;
+        }
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        BigInteger p = (BigInteger)in.readObject();
+        if (p.equals(ZERO))
+        {
+            this.dsaSpec = null;
+        }
+        else
+        {
+            this.dsaSpec = new DSAParameterSpec(p, (BigInteger)in.readObject(), (BigInteger)in.readObject());
+        }
+        this.lwKeyParams = new DSAPublicKeyParameters(y, DSAUtil.toDSAParameters(dsaSpec));
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        if (dsaSpec == null)
+        {
+            out.writeObject(ZERO);
+        }
+        else
+        {
+            out.writeObject(dsaSpec.getP());
+            out.writeObject(dsaSpec.getQ());
+            out.writeObject(dsaSpec.getG());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
new file mode 100644
index 0000000..50679fd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
@@ -0,0 +1,394 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.spec.AlgorithmParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DSAExt;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.digests.NullDigest;
+// Android-added: Check DSA keys when generated
+import com.android.internal.org.bouncycastle.crypto.params.DSAKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.android.internal.org.bouncycastle.crypto.signers.DSAEncoding;
+// Android-removed: Unsupported algorithm
+// import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
+import com.android.internal.org.bouncycastle.crypto.signers.StandardDSAEncoding;
+// Android-changed: Use Android digests
+// import org.bouncycastle.crypto.util.DigestFactory;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSASigner
+    extends SignatureSpi
+    implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+    private Digest                  digest;
+    private DSAExt                  signer;
+    private DSAEncoding             encoding = StandardDSAEncoding.INSTANCE;
+    private SecureRandom            random;
+
+    protected DSASigner(
+        Digest digest,
+        DSAExt signer)
+    {
+        this.digest = digest;
+        this.signer = signer;
+    }
+
+    protected void engineInitVerify(
+        PublicKey   publicKey)
+        throws InvalidKeyException
+    {
+        CipherParameters    param = DSAUtil.generatePublicKeyParameter(publicKey);
+
+        digest.reset();
+        signer.init(false, param);
+    }
+
+    protected void engineInitSign(
+        PrivateKey      privateKey,
+        SecureRandom    random)
+        throws InvalidKeyException
+    {
+        this.random = random;
+        engineInitSign(privateKey);
+    }
+
+    protected void engineInitSign(
+        PrivateKey  privateKey)
+        throws InvalidKeyException
+    {
+        CipherParameters    param = DSAUtil.generatePrivateKeyParameter(privateKey);
+
+        // Android-added: Check DSA keys when generated
+        DSAParameters dsaParam = ((DSAKeyParameters) param).getParameters();
+        checkKey(dsaParam);
+
+        if (random != null)
+        {
+            param = new ParametersWithRandom(param, random);
+        }
+
+        digest.reset();
+        signer.init(true, param);
+    }
+
+    protected void engineUpdate(
+        byte    b)
+        throws SignatureException
+    {
+        digest.update(b);
+    }
+
+    protected void engineUpdate(
+        byte[]  b,
+        int     off,
+        int     len) 
+        throws SignatureException
+    {
+        digest.update(b, off, len);
+    }
+
+    protected byte[] engineSign()
+        throws SignatureException
+    {
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        digest.doFinal(hash, 0);
+
+        try
+        {
+            BigInteger[] sig = signer.generateSignature(hash);
+
+            return encoding.encode(signer.getOrder(), sig[0], sig[1]);
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException(e.toString());
+        }
+    }
+
+    protected boolean engineVerify(
+        byte[]  sigBytes) 
+        throws SignatureException
+    {
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        digest.doFinal(hash, 0);
+
+        BigInteger[] sig;
+
+        try
+        {
+            sig = encoding.decode(signer.getOrder(), sigBytes);
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException("error decoding signature bytes.");
+        }
+
+        return signer.verifySignature(hash, sig[0], sig[1]);
+    }
+
+    protected void engineSetParameter(
+        AlgorithmParameterSpec params)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    // BEGIN Android-added: Check DSA keys when generated
+    protected void checkKey(DSAParameters params) throws InvalidKeyException {
+        int valueL = params.getP().bitLength();
+        int valueN = params.getQ().bitLength();
+        int digestSize = digest.getDigestSize();
+
+        // The checks are consistent with DSAParametersGenerator's init method.
+        if ((valueL < 1024 || valueL > 3072) || valueL % 1024 != 0) {
+            throw new InvalidKeyException("valueL values must be between 1024 and 3072 and a multiple of 1024");
+        } else if (valueL == 1024 && valueN != 160) {
+            throw new InvalidKeyException("valueN must be 160 for valueL = 1024");
+        } else if (valueL == 2048 && (valueN != 224 && valueN != 256)) {
+            throw new InvalidKeyException("valueN must be 224 or 256 for valueL = 2048");
+        } else if (valueL == 3072 && valueN != 256) {
+            throw new InvalidKeyException("valueN must be 256 for valueL = 3072");
+        }
+        if (!(digest instanceof NullDigest) && valueN > digestSize * 8) {
+            throw new InvalidKeyException("Key is too strong for this signature algorithm");
+        }
+    }
+
+    // END Android-added: Check DSA keys when generated
+    /**
+     * @deprecated replaced with #engineSetParameter(java.security.spec.AlgorithmParameterSpec)
+     */
+    protected void engineSetParameter(
+        String  param,
+        Object  value)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated
+     */
+    protected Object engineGetParameter(
+        String      param)
+    {
+        throw new UnsupportedOperationException("engineGetParameter unsupported");
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class stdDSA
+        extends DSASigner
+    {
+        public stdDSA()
+        {
+            // Android-changed: Use Android digests
+            // super(DigestFactory.createSHA1(), new org.bouncycastle.crypto.signers.DSASigner());
+            super(AndroidDigestFactory.getSHA1(), new com.android.internal.org.bouncycastle.crypto.signers.DSASigner());
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithm
+    /*
+    static public class detDSA
+        extends DSASigner
+    {
+        public detDSA()
+        {
+            super(DigestFactory.createSHA1(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1())));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithm
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class dsa224
+        extends DSASigner
+    {
+        public dsa224()
+        {
+            // Android-changed: Use Android digests
+            // super(DigestFactory.createSHA224(), new org.bouncycastle.crypto.signers.DSASigner());
+            super(AndroidDigestFactory.getSHA224(), new com.android.internal.org.bouncycastle.crypto.signers.DSASigner());
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithm
+    /*
+    static public class detDSA224
+        extends DSASigner
+    {
+        public detDSA224()
+        {
+            super(DigestFactory.createSHA224(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224())));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithm
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class dsa256
+        extends DSASigner
+    {
+        public dsa256()
+        {
+            // Android-changed: Use Android digests
+            // super(DigestFactory.createSHA256(), new org.bouncycastle.crypto.signers.DSASigner());
+            super(AndroidDigestFactory.getSHA256(), new com.android.internal.org.bouncycastle.crypto.signers.DSASigner());
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    static public class detDSA256
+        extends DSASigner
+    {
+        public detDSA256()
+        {
+            super(DigestFactory.createSHA256(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256())));
+        }
+    }
+
+    static public class dsa384
+        extends DSASigner
+    {
+        public dsa384()
+        {
+            super(DigestFactory.createSHA384(), new org.bouncycastle.crypto.signers.DSASigner());
+        }
+    }
+
+    static public class detDSA384
+        extends DSASigner
+    {
+        public detDSA384()
+        {
+            super(DigestFactory.createSHA384(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384())));
+        }
+    }
+
+    static public class dsa512
+        extends DSASigner
+    {
+        public dsa512()
+        {
+            super(DigestFactory.createSHA512(), new org.bouncycastle.crypto.signers.DSASigner());
+        }
+    }
+
+    static public class detDSA512
+        extends DSASigner
+    {
+        public detDSA512()
+        {
+            super(DigestFactory.createSHA512(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512())));
+        }
+    }
+
+    static public class dsaSha3_224
+        extends DSASigner
+    {
+        public dsaSha3_224()
+        {
+            super(DigestFactory.createSHA3_224(), new org.bouncycastle.crypto.signers.DSASigner());
+        }
+    }
+
+    static public class detDSASha3_224
+        extends DSASigner
+    {
+        public detDSASha3_224()
+        {
+            super(DigestFactory.createSHA3_224(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224())));
+        }
+    }
+
+    static public class dsaSha3_256
+        extends DSASigner
+    {
+        public dsaSha3_256()
+        {
+            super(DigestFactory.createSHA3_256(), new org.bouncycastle.crypto.signers.DSASigner());
+        }
+    }
+
+    static public class detDSASha3_256
+        extends DSASigner
+    {
+        public detDSASha3_256()
+        {
+            super(DigestFactory.createSHA3_256(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256())));
+        }
+    }
+
+    static public class dsaSha3_384
+        extends DSASigner
+    {
+        public dsaSha3_384()
+        {
+            super(DigestFactory.createSHA3_384(), new org.bouncycastle.crypto.signers.DSASigner());
+        }
+    }
+
+    static public class detDSASha3_384
+        extends DSASigner
+    {
+        public detDSASha3_384()
+        {
+            super(DigestFactory.createSHA3_384(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384())));
+        }
+    }
+
+    static public class dsaSha3_512
+        extends DSASigner
+    {
+        public dsaSha3_512()
+        {
+            super(DigestFactory.createSHA3_512(), new org.bouncycastle.crypto.signers.DSASigner());
+        }
+    }
+
+    static public class detDSASha3_512
+        extends DSASigner
+    {
+        public detDSASha3_512()
+        {
+            super(DigestFactory.createSHA3_512(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512())));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class noneDSA
+        extends DSASigner
+    {
+        public noneDSA()
+        {
+            super(new NullDigest(), new com.android.internal.org.bouncycastle.crypto.signers.DSASigner());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
new file mode 100644
index 0000000..823298c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
@@ -0,0 +1,113 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Fingerprint;
+
+/**
+ * utility class for converting jce/jca DSA objects
+ * objects into their org.bouncycastle.crypto counterparts.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DSAUtil
+{
+    public static final ASN1ObjectIdentifier[] dsaOids =
+    {
+        X9ObjectIdentifiers.id_dsa,
+        OIWObjectIdentifiers.dsaWithSHA1,
+        X9ObjectIdentifiers.id_dsa_with_sha1
+    };
+
+    /**
+     * Return true if the passed in OID could be associated with a DSA key.
+     *
+     * @param algOid algorithm OID from a key.
+     * @return true if it's for a DSA key, false otherwise.
+     */
+    public static boolean isDsaOid(
+        ASN1ObjectIdentifier algOid)
+    {
+        for (int i = 0; i != dsaOids.length; i++)
+        {
+            if (algOid.equals(dsaOids[i]))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    static DSAParameters toDSAParameters(DSAParams spec)
+    {
+        if (spec != null)
+        {
+             return new DSAParameters(spec.getP(), spec.getQ(), spec.getG());
+        }
+
+        return null;
+    }
+
+    static public AsymmetricKeyParameter generatePublicKeyParameter(
+        PublicKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof BCDSAPublicKey)
+        {
+            return ((BCDSAPublicKey)key).engineGetKeyParameters();
+        }
+
+        if (key instanceof DSAPublicKey)
+        {
+            return new BCDSAPublicKey((DSAPublicKey)key).engineGetKeyParameters();
+        }
+
+        try
+        {
+            byte[]  bytes = key.getEncoded();
+
+            BCDSAPublicKey bckey = new BCDSAPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+            return bckey.engineGetKeyParameters();
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeyException("can't identify DSA public key: " + key.getClass().getName());
+        }
+    }
+
+    static public AsymmetricKeyParameter generatePrivateKeyParameter(
+        PrivateKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DSAPrivateKey)
+        {
+            DSAPrivateKey    k = (DSAPrivateKey)key;
+
+            return new DSAPrivateKeyParameters(k.getX(),
+                new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()));
+        }
+                        
+        throw new InvalidKeyException("can't identify DSA private key.");
+    }
+
+    static String generateKeyFingerprint(BigInteger y, DSAParams params)
+    {
+        return new Fingerprint(Arrays.concatenate(y.toByteArray(), params.getP().toByteArray(), params.getQ().toByteArray(), params.getG().toByteArray())).toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java
new file mode 100644
index 0000000..201f4f1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java
@@ -0,0 +1,214 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
+// import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec;
+// import org.bouncycastle.jce.spec.OpenSSHPublicKeySpec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyFactorySpi
+    extends BaseKeyFactorySpi
+{
+    public KeyFactorySpi()
+    {
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key key,
+        Class spec)
+        throws InvalidKeySpecException
+    {
+        if (spec.isAssignableFrom(DSAPublicKeySpec.class) && key instanceof DSAPublicKey)
+        {
+            DSAPublicKey k = (DSAPublicKey)key;
+
+            return new DSAPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
+        }
+        else if (spec.isAssignableFrom(DSAPrivateKeySpec.class) && key instanceof java.security.interfaces.DSAPrivateKey)
+        {
+            java.security.interfaces.DSAPrivateKey k = (java.security.interfaces.DSAPrivateKey)key;
+
+            return new DSAPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (spec.isAssignableFrom(OpenSSHPublicKeySpec.class) && key instanceof java.security.interfaces.DSAPublicKey)
+        {
+            DSAPublicKey k = (DSAPublicKey)key;
+            try
+            {
+                return new OpenSSHPublicKeySpec(OpenSSHPublicKeyUtil.encodePublicKey(new DSAPublicKeyParameters(k.getY(), new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()))));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage());
+            }
+        }
+        else if (spec.isAssignableFrom(OpenSSHPrivateKeySpec.class) && key instanceof java.security.interfaces.DSAPrivateKey)
+        {
+            DSAPrivateKey k = (DSAPrivateKey)key;
+            try
+            {
+                return new OpenSSHPrivateKeySpec(OpenSSHPrivateKeyUtil.encodePrivateKey(new DSAPrivateKeyParameters(k.getX(), new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()))));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage());
+            }
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+
+        return super.engineGetKeySpec(key, spec);
+    }
+
+    protected Key engineTranslateKey(
+        Key key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DSAPublicKey)
+        {
+            return new BCDSAPublicKey((DSAPublicKey)key);
+        }
+        else if (key instanceof DSAPrivateKey)
+        {
+            return new BCDSAPrivateKey((DSAPrivateKey)key);
+        }
+
+        throw new InvalidKeyException("key type unknown");
+    }
+
+    public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+        if (DSAUtil.isDsaOid(algOid))
+        {
+            return new BCDSAPrivateKey(keyInfo);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+        if (DSAUtil.isDsaOid(algOid))
+        {
+            return new BCDSAPublicKey(keyInfo);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof DSAPrivateKeySpec)
+        {
+            return new BCDSAPrivateKey((DSAPrivateKeySpec)keySpec);
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (keySpec instanceof OpenSSHPrivateKeySpec)
+        {
+            CipherParameters params = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(((OpenSSHPrivateKeySpec)keySpec).getEncoded());
+            if (params instanceof DSAPrivateKeyParameters)
+            {
+                return engineGeneratePrivate(
+                    new DSAPrivateKeySpec(
+                        ((DSAPrivateKeyParameters)params).getX(),
+                        ((DSAPrivateKeyParameters)params).getParameters().getP(),
+                        ((DSAPrivateKeyParameters)params).getParameters().getQ(),
+                        ((DSAPrivateKeyParameters)params).getParameters().getG()));
+            }
+            else
+            {
+                throw new IllegalArgumentException("openssh private key is not dsa privare key");
+            }
+
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+
+        return super.engineGeneratePrivate(keySpec);
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof DSAPublicKeySpec)
+        {
+            try
+            {
+                return new BCDSAPublicKey((DSAPublicKeySpec)keySpec);
+            }
+            catch (final Exception e)
+            {
+                throw new InvalidKeySpecException("invalid KeySpec: " + e.getMessage())
+                {
+                    public Throwable getCause()
+                    {
+                        return e;
+                    }
+                };
+            }
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (keySpec instanceof OpenSSHPublicKeySpec)
+        {
+            CipherParameters parameters = OpenSSHPublicKeyUtil.parsePublicKey(((OpenSSHPublicKeySpec)keySpec).getEncoded());
+
+            if (parameters instanceof DSAPublicKeyParameters)
+            {
+                return engineGeneratePublic(
+                    new DSAPublicKeySpec(((DSAPublicKeyParameters)parameters).getY(),
+                        ((DSAPublicKeyParameters)parameters).getParameters().getP(),
+                        ((DSAPublicKeyParameters)parameters).getParameters().getQ(),
+                        ((DSAPublicKeyParameters)parameters).getParameters().getG()));
+            }
+
+            throw new IllegalArgumentException("openssh public key is not dsa public key");
+
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+
+        return super.engineGeneratePublic(keySpec);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..5541f66
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
@@ -0,0 +1,180 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.util.Hashtable;
+
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.digests.SHA256Digest;
+import com.android.internal.org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
+import com.android.internal.org.bouncycastle.crypto.generators.DSAParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameterGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PrimeCertaintyCalculator;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.util.Integers;
+import com.android.internal.org.bouncycastle.util.Properties;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyPairGeneratorSpi
+    extends java.security.KeyPairGenerator
+{
+    private static Hashtable params = new Hashtable();
+    private static Object    lock = new Object();
+
+    DSAKeyGenerationParameters param;
+    DSAKeyPairGenerator engine = new DSAKeyPairGenerator();
+    // Android-changed: Change default strength to 1024
+    // In 1.57, the default strength was changed to 2048.  We keep it at 1024 for app
+    // compatibility, particularly because the default digest (SHA-1) doesn't have
+    // a sufficiently long digest to work with 2048-bit keys.
+    int strength = 1024;
+
+    SecureRandom random = CryptoServicesRegistrar.getSecureRandom();
+    boolean initialised = false;
+
+    public KeyPairGeneratorSpi()
+    {
+        super("DSA");
+    }
+
+    public void initialize(
+        int strength,
+        SecureRandom random)
+    {
+        if (strength < 512 || strength > 4096 || ((strength < 1024) && strength % 64 != 0) || (strength >= 1024 && strength % 1024 != 0))
+        {
+            throw new InvalidParameterException("strength must be from 512 - 4096 and a multiple of 1024 above 1024");
+        }
+
+        // Android-added: Treat null SecureRandom as default
+        if (random == null) {
+            random = new SecureRandom();
+        }
+
+        DSAParameterSpec spec = BouncyCastleProvider.CONFIGURATION.getDSADefaultParameters(strength);
+
+        if (spec != null)
+        {
+            param = new DSAKeyGenerationParameters(random, new DSAParameters(spec.getP(), spec.getQ(), spec.getG()));
+
+            engine.init(param);
+            this.initialised = true;
+        }
+        else
+        {
+            this.strength = strength;
+            this.random = random;
+            this.initialised = false;
+        }
+    }
+
+    public void initialize(
+        AlgorithmParameterSpec params,
+        SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(params instanceof DSAParameterSpec))
+        {
+            throw new InvalidAlgorithmParameterException("parameter object not a DSAParameterSpec");
+        }
+        DSAParameterSpec dsaParams = (DSAParameterSpec)params;
+
+        // Android-added: Treat null SecureRandom as default
+        if (random == null) {
+            random = new SecureRandom();
+        }
+
+        param = new DSAKeyGenerationParameters(random, new DSAParameters(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()));
+
+        engine.init(param);
+        initialised = true;
+    }
+
+    public KeyPair generateKeyPair()
+    {
+        if (!initialised)
+        {
+            Integer paramStrength = Integers.valueOf(strength);
+
+            if (params.containsKey(paramStrength))
+            {
+                param = (DSAKeyGenerationParameters)params.get(paramStrength);
+            }
+            else
+            {
+                synchronized (lock)
+                {
+                    // we do the check again in case we were blocked by a generator for
+                    // our key size.
+                    if (params.containsKey(paramStrength))
+                    {
+                        param = (DSAKeyGenerationParameters)params.get(paramStrength);
+                    }
+                    else
+                    {
+                        DSAParametersGenerator pGen;
+                        DSAParameterGenerationParameters dsaParams;
+
+                        int certainty = PrimeCertaintyCalculator.getDefaultCertainty(strength);
+
+                        // Typical combination of keysize and size of q.
+                        //     keysize = 1024, q's size = 160
+                        //     keysize = 2048, q's size = 224
+                        //     keysize = 2048, q's size = 256
+                        //     keysize = 3072, q's size = 256
+                        // For simplicity if keysize is greater than 1024 then we choose q's size to be 256.
+                        // For legacy keysize that is less than 1024-bit, we just use the 186-2 style parameters
+                        if (strength == 1024)
+                        {
+                            pGen = new DSAParametersGenerator();
+                            if (Properties.isOverrideSet("com.android.internal.org.bouncycastle.dsa.FIPS186-2for1024bits"))
+                            {
+                                pGen.init(strength, certainty, random);
+                            }
+                            else
+                            {
+                                dsaParams = new DSAParameterGenerationParameters(1024, 160, certainty, random);
+                                pGen.init(dsaParams);
+                            }
+                        }
+                        else if (strength > 1024)
+                        {
+                            dsaParams = new DSAParameterGenerationParameters(strength, 256, certainty, random);
+                            pGen = new DSAParametersGenerator(new SHA256Digest());
+                            pGen.init(dsaParams);
+                        }
+                        else
+                        {
+                            pGen = new DSAParametersGenerator();
+                            pGen.init(strength, certainty, random);
+                        }
+                        param = new DSAKeyGenerationParameters(random, pGen.generateParameters());
+
+                        params.put(paramStrength, param);
+                    }
+                }
+            }
+
+            engine.init(param);
+            initialised = true;
+        }
+
+        AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+        DSAPublicKeyParameters pub = (DSAPublicKeyParameters)pair.getPublic();
+        DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)pair.getPrivate();
+
+        return new KeyPair(new BCDSAPublicKey(pub), new BCDSAPrivateKey(priv));
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..1c98a71
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java
@@ -0,0 +1,188 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import com.android.internal.org.bouncycastle.asn1.x9.X962Parameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlgorithmParametersSpi
+    extends java.security.AlgorithmParametersSpi
+{
+    private ECParameterSpec ecParameterSpec;
+    private String curveName;
+
+    protected boolean isASN1FormatString(String format)
+    {
+        return format == null || format.equals("ASN.1");
+    }
+
+    @Override
+    protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec)
+        throws InvalidParameterSpecException
+    {
+        if (algorithmParameterSpec instanceof ECGenParameterSpec)
+        {
+            ECGenParameterSpec ecGenParameterSpec = (ECGenParameterSpec)algorithmParameterSpec;
+            X9ECParameters params = ECUtils.getDomainParametersFromGenSpec(ecGenParameterSpec);
+
+            if (params == null)
+            {
+                throw new InvalidParameterSpecException("EC curve name not recognized: " + ecGenParameterSpec.getName());
+            }
+            curveName = ecGenParameterSpec.getName();
+            ECParameterSpec baseSpec = EC5Util.convertToSpec(params);
+            ecParameterSpec = new ECNamedCurveSpec(curveName,
+                baseSpec.getCurve(), baseSpec.getGenerator(), baseSpec.getOrder(), BigInteger.valueOf(baseSpec.getCofactor()));
+        }
+        else if (algorithmParameterSpec instanceof ECParameterSpec)
+        {
+            if (algorithmParameterSpec instanceof ECNamedCurveSpec)
+            {
+                curveName = ((ECNamedCurveSpec)algorithmParameterSpec).getName();
+            }
+            else
+            {
+                curveName = null;
+            }
+            ecParameterSpec = (ECParameterSpec)algorithmParameterSpec;
+        }
+        else
+        {
+            throw new InvalidParameterSpecException("AlgorithmParameterSpec class not recognized: " + algorithmParameterSpec.getClass().getName());
+        }
+    }
+
+    @Override
+    protected void engineInit(byte[] bytes)
+        throws IOException
+    {
+        engineInit(bytes, "ASN.1");
+    }
+
+    @Override
+    protected void engineInit(byte[] bytes, String format)
+        throws IOException
+    {
+        if (isASN1FormatString(format))
+        {
+            X962Parameters params = X962Parameters.getInstance(bytes);
+
+            ECCurve curve = EC5Util.getCurve(BouncyCastleProvider.CONFIGURATION, params);
+
+            if (params.isNamedCurve())
+            {
+                ASN1ObjectIdentifier curveId = ASN1ObjectIdentifier.getInstance(params.getParameters());
+
+                curveName = ECNamedCurveTable.getName(curveId);
+                if (curveName == null)
+                {
+                    curveName = curveId.getId();
+                }
+            }
+
+            ecParameterSpec = EC5Util.convertToSpec(params, curve);
+        }
+        else
+        {
+            throw new IOException("Unknown encoded parameters format in AlgorithmParameters object: " + format);
+        }
+    }
+
+    @Override
+    protected <T extends AlgorithmParameterSpec> T engineGetParameterSpec(Class<T> paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (ECParameterSpec.class.isAssignableFrom(paramSpec) || paramSpec == AlgorithmParameterSpec.class)
+        {
+            return (T)ecParameterSpec;
+        }
+        else if (ECGenParameterSpec.class.isAssignableFrom(paramSpec))
+        {
+            if (curveName != null)
+            {
+                ASN1ObjectIdentifier namedCurveOid = ECUtil.getNamedCurveOid(curveName);
+
+                if (namedCurveOid != null)
+                {
+                    return (T)new ECGenParameterSpec(namedCurveOid.getId());
+                }
+                return (T)new ECGenParameterSpec(curveName);
+            }
+            else
+            {
+                ASN1ObjectIdentifier namedCurveOid = ECUtil.getNamedCurveOid(EC5Util.convertSpec(ecParameterSpec, false));
+
+                if (namedCurveOid != null)
+                {
+                    return (T)new ECGenParameterSpec(namedCurveOid.getId());
+                }
+            }
+        }
+        throw new InvalidParameterSpecException("EC AlgorithmParameters cannot convert to " + paramSpec.getName());
+    }
+
+    @Override
+    protected byte[] engineGetEncoded()
+        throws IOException
+    {
+        return engineGetEncoded("ASN.1");
+    }
+
+    @Override
+    protected byte[] engineGetEncoded(String format)
+        throws IOException
+    {
+        if (isASN1FormatString(format))
+        {
+            X962Parameters params;
+
+            if (ecParameterSpec == null)     // implicitly CA
+            {
+                params = new X962Parameters(DERNull.INSTANCE);
+            }
+            else if (curveName != null)
+            {
+                params = new X962Parameters(ECUtil.getNamedCurveOid(curveName));
+            }
+            else
+            {
+                com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec ecSpec = EC5Util.convertSpec(ecParameterSpec, false);
+                X9ECParameters ecP = new X9ECParameters(
+                    ecSpec.getCurve(),
+                    ecSpec.getG(),
+                    ecSpec.getN(),
+                    ecSpec.getH(),
+                    ecSpec.getSeed());
+
+                params = new X962Parameters(ecP);
+            }
+
+            return params.getEncoded();
+        }
+
+        throw new IOException("Unknown parameters format in AlgorithmParameters object: " + format);
+    }
+
+    @Override
+    protected String engineToString()
+    {
+        return "EC AlgorithmParameters ";
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
new file mode 100644
index 0000000..1574a21
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
@@ -0,0 +1,415 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.EllipticCurve;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.X962Parameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import com.android.internal.org.bouncycastle.jce.interfaces.ECPointEncoder;
+import com.android.internal.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCECPrivateKey
+    implements ECPrivateKey, com.android.internal.org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+    static final long serialVersionUID = 994553197664784084L;
+
+    private String          algorithm = "EC";
+    private boolean         withCompression;
+
+    private transient BigInteger              d;
+    private transient ECParameterSpec         ecSpec;
+    private transient ProviderConfiguration   configuration;
+    private transient DERBitString            publicKey;
+
+    private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected BCECPrivateKey()
+    {
+    }
+
+    public BCECPrivateKey(
+        ECPrivateKey key,
+        ProviderConfiguration configuration)
+    {
+        this.d = key.getS();
+        this.algorithm = key.getAlgorithm();
+        this.ecSpec = key.getParams();
+        this.configuration = configuration;
+    }
+
+    public BCECPrivateKey(
+        String algorithm,
+        com.android.internal.org.bouncycastle.jce.spec.ECPrivateKeySpec spec,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.d = spec.getD();
+
+        if (spec.getParams() != null) // can be null if implicitlyCA
+        {
+            ECCurve curve = spec.getParams().getCurve();
+            EllipticCurve ellipticCurve;
+
+            ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+        }
+        else
+        {
+            this.ecSpec = null;
+        }
+
+        this.configuration = configuration;
+    }
+
+
+    public BCECPrivateKey(
+        String algorithm,
+        ECPrivateKeySpec spec,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.d = spec.getS();
+        this.ecSpec = spec.getParams();
+        this.configuration = configuration;
+    }
+
+    public BCECPrivateKey(
+        String algorithm,
+        BCECPrivateKey key)
+    {
+        this.algorithm = algorithm;
+        this.d = key.d;
+        this.ecSpec = key.ecSpec;
+        this.withCompression = key.withCompression;
+        this.attrCarrier = key.attrCarrier;
+        this.publicKey = key.publicKey;
+        this.configuration = key.configuration;
+    }
+
+    public BCECPrivateKey(
+        String algorithm,
+        ECPrivateKeyParameters params,
+        BCECPublicKey pubKey,
+        ECParameterSpec spec,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.d = params.getD();
+        this.configuration = configuration;
+
+        if (spec == null)
+        {
+            ECDomainParameters dp = params.getParameters();
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                ellipticCurve,
+                EC5Util.convertPoint(dp.getG()),
+                dp.getN(),
+                dp.getH().intValue());
+        }
+        else
+        {
+            this.ecSpec = spec;
+        }
+
+        this.publicKey = getPublicKeyDetails(pubKey);
+    }
+
+    public BCECPrivateKey(
+        String algorithm,
+        ECPrivateKeyParameters params,
+        BCECPublicKey pubKey,
+        com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec spec,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.d = params.getD();
+        this.configuration = configuration;
+
+        if (spec == null)
+        {
+            ECDomainParameters dp = params.getParameters();
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                ellipticCurve,
+                EC5Util.convertPoint(dp.getG()),
+                dp.getN(),
+                dp.getH().intValue());
+        }
+        else
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+        }
+
+        try
+        {
+            this.publicKey = getPublicKeyDetails(pubKey);
+        }
+        catch (Exception e)
+        {
+            this.publicKey = null; // not all curves are encodable
+        }
+    }
+
+    public BCECPrivateKey(
+        String algorithm,
+        ECPrivateKeyParameters params,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.d = params.getD();
+        this.ecSpec = null;
+        this.configuration = configuration;
+    }
+
+    BCECPrivateKey(
+        String         algorithm,
+        PrivateKeyInfo info,
+        ProviderConfiguration configuration)
+        throws IOException
+    {
+        this.algorithm = algorithm;
+        this.configuration = configuration;
+        populateFromPrivKeyInfo(info);
+    }
+
+    private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+        throws IOException
+    {
+        X962Parameters params = X962Parameters.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+
+        ECCurve curve = EC5Util.getCurve(configuration, params);
+        ecSpec = EC5Util.convertToSpec(params, curve);
+
+        ASN1Encodable privKey = info.parsePrivateKey();
+        if (privKey instanceof ASN1Integer)
+        {
+            ASN1Integer          derD = ASN1Integer.getInstance(privKey);
+
+            this.d = derD.getValue();
+        }
+        else
+        {
+            com.android.internal.org.bouncycastle.asn1.sec.ECPrivateKey ec = com.android.internal.org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(privKey);
+
+            this.d = ec.getKey();
+            this.publicKey = ec.getPublicKey();
+        }
+    }
+
+    public String getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        X962Parameters  params = ECUtils.getDomainParametersFromName(ecSpec, withCompression);
+
+        int orderBitLength;
+        if (ecSpec == null)
+        {
+            orderBitLength = ECUtil.getOrderBitLength(configuration, null, this.getS());
+        }
+        else
+        {
+            orderBitLength = ECUtil.getOrderBitLength(configuration, ecSpec.getOrder(), this.getS());
+        }
+        
+        PrivateKeyInfo          info;
+        com.android.internal.org.bouncycastle.asn1.sec.ECPrivateKey            keyStructure;
+
+        if (publicKey != null)
+        {
+            keyStructure = new com.android.internal.org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(), publicKey, params);
+        }
+        else
+        {
+            keyStructure = new com.android.internal.org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(), params);
+        }
+
+        try
+        {
+            info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure);
+
+            return info.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+
+    public ECParameterSpec getParams()
+    {
+        return ecSpec;
+    }
+
+    public com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+    {
+        if (ecSpec == null)
+        {
+            return null;
+        }
+        
+        return EC5Util.convertSpec(ecSpec, withCompression);
+    }
+
+    com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+    {
+        if (ecSpec != null)
+        {
+            return EC5Util.convertSpec(ecSpec, withCompression);
+        }
+
+        return configuration.getEcImplicitlyCa();
+    }
+
+    public BigInteger getS()
+    {
+        return d;
+    }
+
+    public BigInteger getD()
+    {
+        return d;
+    }
+    
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable        attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        ASN1ObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    public void setPointFormat(String style)
+    {
+       withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof BCECPrivateKey))
+        {
+            return false;
+        }
+
+        BCECPrivateKey other = (BCECPrivateKey)o;
+
+        return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+    }
+
+    public int hashCode()
+    {
+        return getD().hashCode() ^ engineGetSpec().hashCode();
+    }
+
+    public String toString()
+    {
+        return ECUtil.privateKeyToString("EC", d, engineGetSpec());
+    }
+
+    private com.android.internal.org.bouncycastle.math.ec.ECPoint calculateQ(com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec spec)
+    {
+        return spec.getG().multiply(d).normalize();
+    }
+
+    private DERBitString getPublicKeyDetails(BCECPublicKey pub)
+    {
+        try
+        {
+            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+            return info.getPublicKeyData();
+        }
+        catch (IOException e)
+        {   // should never happen
+            return null;
+        }
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        byte[] enc = (byte[])in.readObject();
+
+        this.configuration = BouncyCastleProvider.CONFIGURATION;
+
+        populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeObject(this.getEncoded());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
new file mode 100644
index 0000000..f9fb6f0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
@@ -0,0 +1,345 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.X962Parameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECPoint;
+import com.android.internal.org.bouncycastle.asn1.x9.X9IntegerConverter;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import com.android.internal.org.bouncycastle.jce.interfaces.ECPointEncoder;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCECPublicKey
+    implements ECPublicKey, com.android.internal.org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder
+{
+    static final long serialVersionUID = 2422789860422731812L;
+
+    private String    algorithm = "EC";
+    private boolean   withCompression;
+
+    private transient ECPublicKeyParameters   ecPublicKey;
+    private transient ECParameterSpec         ecSpec;
+    private transient ProviderConfiguration   configuration;
+
+    public BCECPublicKey(
+        String algorithm,
+        BCECPublicKey key)
+    {
+        this.algorithm = algorithm;
+        this.ecPublicKey = key.ecPublicKey;
+        this.ecSpec = key.ecSpec;
+        this.withCompression = key.withCompression;
+        this.configuration = key.configuration;
+    }
+    
+    public BCECPublicKey(
+        String algorithm,
+        ECPublicKeySpec spec,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.ecSpec = spec.getParams();
+        this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(configuration, spec.getParams()));
+        this.configuration = configuration;
+    }
+
+    public BCECPublicKey(
+        String algorithm,
+        com.android.internal.org.bouncycastle.jce.spec.ECPublicKeySpec spec,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+
+        if (spec.getParams() != null) // can be null if implictlyCa
+        {
+            ECCurve curve = spec.getParams().getCurve();
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+            // this may seem a little long-winded but it's how we pick up the custom curve.
+            this.ecPublicKey = new ECPublicKeyParameters(
+                spec.getQ(), ECUtil.getDomainParameters(configuration, spec.getParams()));
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+        }
+        else
+        {
+            com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa();
+
+            this.ecPublicKey = new ECPublicKeyParameters(s.getCurve().createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger()), EC5Util.getDomainParameters(configuration, (ECParameterSpec)null));
+            this.ecSpec = null;
+        }
+
+        this.configuration = configuration;
+    }
+    
+    public BCECPublicKey(
+        String algorithm,
+        ECPublicKeyParameters params,
+        ECParameterSpec spec,
+        ProviderConfiguration configuration)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+        this.ecPublicKey = params;
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = createSpec(ellipticCurve, dp);
+        }
+        else
+        {
+            this.ecSpec = spec;
+        }
+
+        this.configuration = configuration;
+    }
+
+    public BCECPublicKey(
+        String algorithm,
+        ECPublicKeyParameters params,
+        com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec spec,
+        ProviderConfiguration configuration)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = createSpec(ellipticCurve, dp);
+        }
+        else
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+        }
+
+        this.ecPublicKey = params;
+        this.configuration = configuration;
+    }
+
+    /*
+     * called for implicitCA
+     */
+    public BCECPublicKey(
+        String algorithm,
+        ECPublicKeyParameters params,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.ecPublicKey = params;
+        this.ecSpec = null;
+        this.configuration = configuration;
+    }
+
+    public BCECPublicKey(
+        ECPublicKey key,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = key.getAlgorithm();
+        this.ecSpec = key.getParams();
+        this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW(), false), EC5Util.getDomainParameters(configuration, key.getParams()));
+    }
+
+    BCECPublicKey(
+        String algorithm,
+        SubjectPublicKeyInfo info,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.configuration = configuration;
+        populateFromPubKeyInfo(info);
+    }
+
+    private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
+    {
+        return new ECParameterSpec(
+            ellipticCurve,
+            EC5Util.convertPoint(dp.getG()),
+            dp.getN(),
+            dp.getH().intValue());
+    }
+
+    private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+    {
+        X962Parameters params = X962Parameters.getInstance(info.getAlgorithm().getParameters());
+        ECCurve curve = EC5Util.getCurve(configuration, params);
+        ecSpec = EC5Util.convertToSpec(params, curve);
+
+        DERBitString    bits = info.getPublicKeyData();
+        byte[]          data = bits.getBytes();
+        ASN1OctetString key = new DEROctetString(data);
+
+        //
+        // extra octet string - one of our old certs...
+        //
+        if (data[0] == 0x04 && data[1] == data.length - 2
+            && (data[2] == 0x02 || data[2] == 0x03))
+        {
+            int qLength = new X9IntegerConverter().getByteLength(curve);
+
+            if (qLength >= data.length - 3)
+            {
+                try
+                {
+                    key = (ASN1OctetString) ASN1Primitive.fromByteArray(data);
+                }
+                catch (IOException ex)
+                {
+                    throw new IllegalArgumentException("error recovering public key");
+                }
+            }
+        }
+
+        X9ECPoint derQ = new X9ECPoint(curve, key);
+
+        this.ecPublicKey = new ECPublicKeyParameters(derQ.getPoint(), ECUtil.getDomainParameters(configuration, params));
+    }
+
+    public String getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        ASN1Encodable   params = ECUtils.getDomainParametersFromName(ecSpec, withCompression);
+        ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(ecPublicKey.getQ(), withCompression).toASN1Primitive());
+
+        // stored curve is null if ImplicitlyCa
+        SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+    }
+
+    public ECParameterSpec getParams()
+    {
+        return ecSpec;
+    }
+
+    public com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+    {
+        if (ecSpec == null)     // implictlyCA
+        {
+            return null;
+        }
+
+        return EC5Util.convertSpec(ecSpec, withCompression);
+    }
+
+    public ECPoint getW()
+    {
+        return EC5Util.convertPoint(ecPublicKey.getQ());
+    }
+
+    public com.android.internal.org.bouncycastle.math.ec.ECPoint getQ()
+    {
+        com.android.internal.org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ();
+
+        if (ecSpec == null)
+        {
+            return q.getDetachedPoint();
+        }
+
+        return q;
+    }
+
+    ECPublicKeyParameters engineGetKeyParameters()
+    {
+        return ecPublicKey;
+    }
+
+    com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+    {
+        if (ecSpec != null)
+        {
+            return EC5Util.convertSpec(ecSpec, withCompression);
+        }
+
+        return configuration.getEcImplicitlyCa();
+    }
+
+    public String toString()
+    {
+        return ECUtil.publicKeyToString("EC", ecPublicKey.getQ(), engineGetSpec());
+    }
+    
+    public void setPointFormat(String style)
+    {
+       withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof BCECPublicKey))
+        {
+            return false;
+        }
+
+        BCECPublicKey other = (BCECPublicKey)o;
+
+        return ecPublicKey.getQ().equals(other.ecPublicKey.getQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+    }
+
+    public int hashCode()
+    {
+        return ecPublicKey.getQ().hashCode() ^ engineGetSpec().hashCode();
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        byte[] enc = (byte[])in.readObject();
+
+        this.configuration = BouncyCastleProvider.CONFIGURATION;
+
+        populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeObject(this.getEncoded());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java
new file mode 100644
index 0000000..fa0f1d5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java
@@ -0,0 +1,97 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.x9.X962Parameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+import com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+
+class ECUtils
+{
+    static AsymmetricKeyParameter generatePublicKeyParameter(
+            PublicKey key)
+        throws InvalidKeyException
+    {
+        return (key instanceof BCECPublicKey) ? ((BCECPublicKey)key).engineGetKeyParameters() : ECUtil.generatePublicKeyParameter(key);
+    }
+
+    static X9ECParameters getDomainParametersFromGenSpec(ECGenParameterSpec genSpec)
+    {
+        return getDomainParametersFromName(genSpec.getName());
+    }
+
+    static X9ECParameters getDomainParametersFromName(String curveName)
+    {
+        X9ECParameters domainParameters;
+        try
+        {
+            if (curveName.charAt(0) >= '0' && curveName.charAt(0) <= '2')
+            {
+                ASN1ObjectIdentifier oidID = new ASN1ObjectIdentifier(curveName);
+                domainParameters = ECUtil.getNamedCurveByOid(oidID);
+            }
+            else
+            {
+                if (curveName.indexOf(' ') > 0)
+                {
+                    curveName = curveName.substring(curveName.indexOf(' ') + 1);
+                    domainParameters = ECUtil.getNamedCurveByName(curveName);
+                }
+                else
+                {
+                    domainParameters = ECUtil.getNamedCurveByName(curveName);
+                }
+            }
+        }
+        catch (IllegalArgumentException ex)
+        {
+            domainParameters = ECUtil.getNamedCurveByName(curveName);
+        }
+        return domainParameters;
+    }
+
+    static X962Parameters getDomainParametersFromName(ECParameterSpec ecSpec, boolean withCompression)
+    {
+        X962Parameters params;
+
+        if (ecSpec instanceof ECNamedCurveSpec)
+        {
+            ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+            if (curveOid == null)
+            {
+                curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+            }
+            params = new X962Parameters(curveOid);
+        }
+        else if (ecSpec == null)
+        {
+            params = new X962Parameters(DERNull.INSTANCE);
+        }
+        else
+        {
+            ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+            X9ECParameters ecP = new X9ECParameters(
+                curve,
+                EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+                ecSpec.getOrder(),
+                BigInteger.valueOf(ecSpec.getCofactor()),
+                ecSpec.getCurve().getSeed());
+
+            params = new X962Parameters(ecP);
+        }
+
+        return params;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
new file mode 100644
index 0000000..324623c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
@@ -0,0 +1,834 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.x9.X9IntegerConverter;
+import com.android.internal.org.bouncycastle.crypto.BasicAgreement;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DerivationFunction;
+import com.android.internal.org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
+// BEGIN Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
+// import org.bouncycastle.crypto.agreement.ECDHCUnifiedAgreement;
+// import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
+// import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator;
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
+// import org.bouncycastle.crypto.params.ECDHUPrivateParameters;
+// import org.bouncycastle.crypto.params.ECDHUPublicParameters;
+// END Android-removed: Unsupported algorithms
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPublicKeyParameters;
+// BEGIN Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.params.MQVPrivateParameters;
+// import org.bouncycastle.crypto.params.MQVPublicParameters;
+// import org.bouncycastle.crypto.util.DigestFactory;
+// END Android-removed: Unsupported algorithms
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+// BEGIN Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.spec.DHUParameterSpec;
+// import org.bouncycastle.jcajce.spec.MQVParameterSpec;
+// END Android-removed: Unsupported algorithms
+import com.android.internal.org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
+import com.android.internal.org.bouncycastle.jce.interfaces.ECPrivateKey;
+import com.android.internal.org.bouncycastle.jce.interfaces.ECPublicKey;
+// BEGIN Android-removed: Unsupported algorithms
+// import org.bouncycastle.jce.interfaces.MQVPrivateKey;
+// import org.bouncycastle.jce.interfaces.MQVPublicKey;
+// END Android-removed: Unsupported algorithms
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
+ * both the simple one, and the simple one with cofactors are supported.
+ * <p>
+ * Also, MQV key agreement per SEC-1
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyAgreementSpi
+    extends BaseAgreementSpi
+{
+    private static final X9IntegerConverter converter = new X9IntegerConverter();
+
+    private String kaAlgorithm;
+
+    private ECDomainParameters parameters;
+    private Object agreement;
+
+    // Android-removed: Unsupported algorithms
+    // private MQVParameterSpec       mqvParameters;
+    // private DHUParameterSpec dheParameters;
+    private byte[] result;
+
+    protected KeyAgreementSpi(
+        String kaAlgorithm,
+        BasicAgreement agreement,
+        DerivationFunction kdf)
+    {
+        super(kaAlgorithm, kdf);
+
+        this.kaAlgorithm = kaAlgorithm;
+        this.agreement = agreement;
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    protected KeyAgreementSpi(
+        String kaAlgorithm,
+        ECDHCUnifiedAgreement agreement,
+        DerivationFunction kdf)
+    {
+        super(kaAlgorithm, kdf);
+
+        this.kaAlgorithm = kaAlgorithm;
+        this.agreement = agreement;
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    protected byte[] bigIntToBytes(
+        BigInteger r)
+    {
+        return converter.integerToBytes(r, converter.getByteLength(parameters.getCurve()));
+    }
+
+    protected Key engineDoPhase(
+        Key key,
+        boolean lastPhase)
+        throws InvalidKeyException, IllegalStateException
+    {
+        if (parameters == null)
+        {
+            throw new IllegalStateException(kaAlgorithm + " not initialised.");
+        }
+
+        if (!lastPhase)
+        {
+            throw new IllegalStateException(kaAlgorithm + " can only be between two parties.");
+        }
+
+        CipherParameters pubKey;
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        if (agreement instanceof ECMQVBasicAgreement)
+        {
+            if (!(key instanceof MQVPublicKey))
+            {
+                ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
+                    ECUtils.generatePublicKeyParameter((PublicKey)key);
+                ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
+                    ECUtils.generatePublicKeyParameter(mqvParameters.getOtherPartyEphemeralKey());
+
+                pubKey = new MQVPublicParameters(staticKey, ephemKey);
+            }
+            else
+            {
+                MQVPublicKey mqvPubKey = (MQVPublicKey)key;
+                ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
+                    ECUtils.generatePublicKeyParameter(mqvPubKey.getStaticKey());
+                ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
+                    ECUtils.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
+
+                pubKey = new MQVPublicParameters(staticKey, ephemKey);
+            }
+        }
+        else if (agreement instanceof ECDHCUnifiedAgreement)
+        {
+            ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
+                ECUtils.generatePublicKeyParameter((PublicKey)key);
+            ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
+                ECUtils.generatePublicKeyParameter(dheParameters.getOtherPartyEphemeralKey());
+
+            pubKey = new ECDHUPublicParameters(staticKey, ephemKey);
+        }
+        else
+        */
+        // END Android-removed: Unsupported algorithms
+        {
+            if (!(key instanceof PublicKey))
+            {
+                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+                    + getSimpleName(ECPublicKey.class) + " for doPhase");
+            }
+
+            pubKey = ECUtils.generatePublicKeyParameter((PublicKey)key);
+        }
+
+        try
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            if (agreement instanceof BasicAgreement)
+            {
+            */
+            // END Android-removed: Unsupported algorithms
+                result = bigIntToBytes(((BasicAgreement)agreement).calculateAgreement(pubKey));
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            }
+            else
+            {
+                result = ((ECDHCUnifiedAgreement)agreement).calculateAgreement(pubKey);
+            }
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+        catch (final Exception e)
+        {
+            throw new InvalidKeyException("calculation failed: " + e.getMessage())
+            {
+                public Throwable getCause()
+                {
+                    return e;
+                }
+            };
+        }
+
+        return null;
+    }
+
+    protected void engineInit(
+        Key key,
+        AlgorithmParameterSpec params,
+        SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        // Android-removed: Unsupported algorithms
+        // if (params != null &&
+        //     !(params instanceof MQVParameterSpec || params instanceof UserKeyingMaterialSpec || params instanceof DHUParameterSpec))
+        if (params != null && !(params instanceof UserKeyingMaterialSpec))
+        {
+            throw new InvalidAlgorithmParameterException("No algorithm parameters supported");
+        }
+
+        initFromKey(key, params);
+    }
+
+    protected void engineInit(
+        Key key,
+        SecureRandom random)
+        throws InvalidKeyException
+    {
+        try
+        {
+            initFromKey(key, null);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            // this should never occur.
+            throw new InvalidKeyException(e.getMessage());
+        }
+    }
+
+    private void initFromKey(Key key, AlgorithmParameterSpec parameterSpec)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        if (agreement instanceof ECMQVBasicAgreement)
+        {
+            mqvParameters = null;
+            if (!(key instanceof MQVPrivateKey) && !(parameterSpec instanceof MQVParameterSpec))
+            {
+                throw new InvalidAlgorithmParameterException(kaAlgorithm + " key agreement requires "
+                    + getSimpleName(MQVParameterSpec.class) + " for initialisation");
+            }
+
+            ECPrivateKeyParameters staticPrivKey;
+            ECPrivateKeyParameters ephemPrivKey;
+            ECPublicKeyParameters ephemPubKey;
+            if (key instanceof MQVPrivateKey)
+            {
+                MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
+                staticPrivKey = (ECPrivateKeyParameters)
+                    ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
+                ephemPrivKey = (ECPrivateKeyParameters)
+                    ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
+
+                ephemPubKey = null;
+                if (mqvPrivKey.getEphemeralPublicKey() != null)
+                {
+                    ephemPubKey = (ECPublicKeyParameters)
+                        ECUtils.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
+                }
+            }
+            else
+            {
+                MQVParameterSpec mqvParameterSpec = (MQVParameterSpec)parameterSpec;
+
+                staticPrivKey = (ECPrivateKeyParameters)
+                    ECUtil.generatePrivateKeyParameter((PrivateKey)key);
+                ephemPrivKey = (ECPrivateKeyParameters)
+                    ECUtil.generatePrivateKeyParameter(mqvParameterSpec.getEphemeralPrivateKey());
+
+                ephemPubKey = null;
+                if (mqvParameterSpec.getEphemeralPublicKey() != null)
+                {
+                    ephemPubKey = (ECPublicKeyParameters)
+                        ECUtils.generatePublicKeyParameter(mqvParameterSpec.getEphemeralPublicKey());
+                }
+                mqvParameters = mqvParameterSpec;
+                ukmParameters = mqvParameterSpec.getUserKeyingMaterial();
+            }
+
+            MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
+            this.parameters = staticPrivKey.getParameters();
+
+            // TODO Validate that all the keys are using the same parameters?
+
+            ((ECMQVBasicAgreement)agreement).init(localParams);
+        }
+        else if (parameterSpec instanceof DHUParameterSpec)
+        {
+            if (!(agreement instanceof ECDHCUnifiedAgreement))
+            {
+                throw new InvalidAlgorithmParameterException(kaAlgorithm + " key agreement cannot be used with "
+                    + getSimpleName(DHUParameterSpec.class));
+            }
+            DHUParameterSpec dheParameterSpec = (DHUParameterSpec)parameterSpec;
+            ECPrivateKeyParameters staticPrivKey;
+            ECPrivateKeyParameters ephemPrivKey;
+            ECPublicKeyParameters ephemPubKey;
+
+            staticPrivKey = (ECPrivateKeyParameters)
+                ECUtil.generatePrivateKeyParameter((PrivateKey)key);
+            ephemPrivKey = (ECPrivateKeyParameters)
+                ECUtil.generatePrivateKeyParameter(dheParameterSpec.getEphemeralPrivateKey());
+
+            ephemPubKey = null;
+            if (dheParameterSpec.getEphemeralPublicKey() != null)
+            {
+                ephemPubKey = (ECPublicKeyParameters)
+                    ECUtils.generatePublicKeyParameter(dheParameterSpec.getEphemeralPublicKey());
+            }
+            dheParameters = dheParameterSpec;
+            ukmParameters = dheParameterSpec.getUserKeyingMaterial();
+
+            ECDHUPrivateParameters localParams = new ECDHUPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
+            this.parameters = staticPrivKey.getParameters();
+
+            ((ECDHCUnifiedAgreement)agreement).init(localParams);
+        }
+        else
+        */
+        // END Android-removed: Unsupported algorithms
+        {
+            if (!(key instanceof PrivateKey))
+            {
+                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+                    + getSimpleName(ECPrivateKey.class) + " for initialisation");
+            }
+            if (kdf == null && parameterSpec instanceof UserKeyingMaterialSpec)
+            {
+                throw new InvalidAlgorithmParameterException("no KDF specified for UserKeyingMaterialSpec");
+            }
+            ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key);
+            this.parameters = privKey.getParameters();
+            ukmParameters = (parameterSpec instanceof UserKeyingMaterialSpec) ? ((UserKeyingMaterialSpec)parameterSpec).getUserKeyingMaterial() : null;
+            ((BasicAgreement)agreement).init(privKey);
+        }
+    }
+
+    private static String getSimpleName(Class clazz)
+    {
+        String fullName = clazz.getName();
+
+        return fullName.substring(fullName.lastIndexOf('.') + 1);
+    }
+    
+    protected byte[] calcSecret()
+    {
+        return Arrays.clone(result);
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class DH
+        extends KeyAgreementSpi
+    {
+        public DH()
+        {
+            super("ECDH", new ECDHBasicAgreement(), null);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class DHC
+        extends KeyAgreementSpi
+    {
+        public DHC()
+        {
+            super("ECDHC", new ECDHCBasicAgreement(), null);
+        }
+    }
+
+    public static class MQV
+        extends KeyAgreementSpi
+    {
+        public MQV()
+        {
+            super("ECMQV", new ECMQVBasicAgreement(), null);
+        }
+    }
+
+    public static class DHUC
+        extends KeyAgreementSpi
+    {
+        public DHUC()
+        {
+            super("ECCDHU", new ECDHCUnifiedAgreement(), null);
+        }
+    }
+
+    public static class DHwithSHA1KDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA1KDF()
+        {
+            super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class DHwithSHA1KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA1KDFAndSharedInfo()
+        {
+            super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class CDHwithSHA1KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public CDHwithSHA1KDFAndSharedInfo()
+        {
+            super("ECCDHwithSHA1KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class DHwithSHA224KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA224KDFAndSharedInfo()
+        {
+            super("ECDHwithSHA224KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class CDHwithSHA224KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public CDHwithSHA224KDFAndSharedInfo()
+        {
+            super("ECCDHwithSHA224KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class DHwithSHA256KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA256KDFAndSharedInfo()
+        {
+            super("ECDHwithSHA256KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class CDHwithSHA256KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public CDHwithSHA256KDFAndSharedInfo()
+        {
+            super("ECCDHwithSHA256KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class DHwithSHA384KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA384KDFAndSharedInfo()
+        {
+            super("ECDHwithSHA384KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class CDHwithSHA384KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public CDHwithSHA384KDFAndSharedInfo()
+        {
+            super("ECCDHwithSHA384KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class DHwithSHA512KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA512KDFAndSharedInfo()
+        {
+            super("ECDHwithSHA512KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class CDHwithSHA512KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public CDHwithSHA512KDFAndSharedInfo()
+        {
+            super("ECCDHwithSHA512KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class MQVwithSHA1KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA1KDFAndSharedInfo()
+        {
+            super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class MQVwithSHA224KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA224KDFAndSharedInfo()
+        {
+            super("ECMQVwithSHA224KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class MQVwithSHA256KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA256KDFAndSharedInfo()
+        {
+            super("ECMQVwithSHA256KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class MQVwithSHA384KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA384KDFAndSharedInfo()
+        {
+            super("ECMQVwithSHA384KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class MQVwithSHA512KDFAndSharedInfo
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA512KDFAndSharedInfo()
+        {
+            super("ECMQVwithSHA512KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class DHwithSHA1CKDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA1CKDF()
+        {
+            super("ECDHwithSHA1CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class DHwithSHA256CKDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA256CKDF()
+        {
+            super("ECDHwithSHA256CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class DHwithSHA384CKDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA384CKDF()
+        {
+            super("ECDHwithSHA384CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class DHwithSHA512CKDF
+        extends KeyAgreementSpi
+    {
+        public DHwithSHA512CKDF()
+        {
+            super("ECDHwithSHA512CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class MQVwithSHA1CKDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA1CKDF()
+        {
+            super("ECMQVwithSHA1CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class MQVwithSHA224CKDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA224CKDF()
+        {
+            super("ECMQVwithSHA224CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class MQVwithSHA256CKDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA256CKDF()
+        {
+            super("ECMQVwithSHA256CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class MQVwithSHA384CKDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA384CKDF()
+        {
+            super("ECMQVwithSHA384CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class MQVwithSHA512CKDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA512CKDF()
+        {
+            super("ECMQVwithSHA512CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class MQVwithSHA1KDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA1KDF()
+        {
+            super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class MQVwithSHA224KDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA224KDF()
+        {
+            super("ECMQVwithSHA224KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class MQVwithSHA256KDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA256KDF()
+        {
+            super("ECMQVwithSHA256KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class MQVwithSHA384KDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA384KDF()
+        {
+            super("ECMQVwithSHA384KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class MQVwithSHA512KDF
+        extends KeyAgreementSpi
+    {
+        public MQVwithSHA512KDF()
+        {
+            super("ECMQVwithSHA512KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class DHUwithSHA1CKDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA1CKDF()
+        {
+            super("ECCDHUwithSHA1CKDF", new ECDHCUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class DHUwithSHA224CKDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA224CKDF()
+        {
+            super("ECCDHUwithSHA224CKDF", new ECDHCUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class DHUwithSHA256CKDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA256CKDF()
+        {
+            super("ECCDHUwithSHA256CKDF", new ECDHCUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class DHUwithSHA384CKDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA384CKDF()
+        {
+            super("ECCDHUwithSHA384CKDF", new ECDHCUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class DHUwithSHA512CKDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA512CKDF()
+        {
+            super("ECCDHUwithSHA512CKDF", new ECDHCUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    public static class DHUwithSHA1KDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA1KDF()
+        {
+            super("ECCDHUwithSHA1KDF", new ECDHCUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
+        }
+    }
+
+    public static class DHUwithSHA224KDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA224KDF()
+        {
+            super("ECCDHUwithSHA224KDF", new ECDHCUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
+        }
+    }
+
+    public static class DHUwithSHA256KDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA256KDF()
+        {
+            super("ECCDHUwithSHA256KDF", new ECDHCUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
+        }
+    }
+
+    public static class DHUwithSHA384KDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA384KDF()
+        {
+            super("ECCDHUwithSHA384KDF", new ECDHCUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
+        }
+    }
+
+    public static class DHUwithSHA512KDF
+        extends KeyAgreementSpi
+    {
+        public DHUwithSHA512KDF()
+        {
+            super("ECCDHUwithSHA512KDF", new ECDHCUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
+        }
+    }
+
+    /**
+   	 * KeyAgreement according to BSI TR-03111 chapter 4.3.1
+   	 *
+   	public static class ECKAEGwithSHA1KDF
+   			extends KeyAgreementSpi
+   	{
+   		public ECKAEGwithSHA1KDF()
+   		{
+   			super("ECKAEGwithSHA1KDF", new ECDHBasicAgreement(),
+                   new KDF2BytesGenerator(DigestFactory.createSHA1()));
+   		}
+   	}
+
+    /**
+   	 * KeyAgreement according to BSI TR-03111 chapter 4.3.1
+   	 *
+   	public static class ECKAEGwithRIPEMD160KDF
+   			extends KeyAgreementSpi
+   	{
+   		public ECKAEGwithRIPEMD160KDF()
+   		{
+   			super("ECKAEGwithRIPEMD160KDF", new ECDHBasicAgreement(),
+                   new KDF2BytesGenerator(new RIPEMD160Digest()));
+   		}
+   	}
+
+    /**
+   	 * KeyAgreement according to BSI TR-03111 chapter 4.3.1
+   	 *
+   	public static class ECKAEGwithSHA224KDF
+   			extends KeyAgreementSpi
+   	{
+   		public ECKAEGwithSHA224KDF()
+   		{
+   			super("ECKAEGwithSHA224KDF", new ECDHBasicAgreement(),
+                   new KDF2BytesGenerator(DigestFactory.createSHA224()));
+   		}
+   	}
+
+	/**
+	 * KeyAgreement according to BSI TR-03111 chapter 4.3.1
+	 *
+	public static class ECKAEGwithSHA256KDF
+			extends KeyAgreementSpi
+	{
+		public ECKAEGwithSHA256KDF()
+		{
+			super("ECKAEGwithSHA256KDF", new ECDHBasicAgreement(),
+                new KDF2BytesGenerator(DigestFactory.createSHA256()));
+		}
+	}
+
+	/**
+	 * KeyAgreement according to BSI TR-03111 chapter 4.3.1
+	 *
+	public static class ECKAEGwithSHA384KDF
+			extends KeyAgreementSpi
+	{
+		public ECKAEGwithSHA384KDF()
+		{
+			super("ECKAEGwithSHA384KDF", new ECDHBasicAgreement(),
+                new KDF2BytesGenerator(DigestFactory.createSHA384()));
+		}
+	}
+
+	/**
+	 * KeyAgreement according to BSI TR-03111 chapter 4.3.1
+	 *
+	public static class ECKAEGwithSHA512KDF
+			extends KeyAgreementSpi
+	{
+		public ECKAEGwithSHA512KDF()
+		{
+			super("ECKAEGwithSHA512KDF", new ECDHBasicAgreement(),
+                new KDF2BytesGenerator(DigestFactory.createSHA512()));
+		}
+	}
+  */
+  // END Android-removed: Unsupported algorithms
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
new file mode 100644
index 0000000..5f9cfac
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
@@ -0,0 +1,369 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPublicKeyParameters;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec;
+import com.android.internal.org.bouncycastle.jce.spec.ECPrivateKeySpec;
+import com.android.internal.org.bouncycastle.jce.spec.ECPublicKeySpec;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec;
+// import org.bouncycastle.jce.spec.OpenSSHPublicKeySpec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyFactorySpi
+    extends BaseKeyFactorySpi
+    implements AsymmetricKeyInfoConverter
+{
+    String algorithm;
+    ProviderConfiguration configuration;
+
+    KeyFactorySpi(
+        String algorithm,
+        ProviderConfiguration configuration)
+    {
+        this.algorithm = algorithm;
+        this.configuration = configuration;
+    }
+
+    protected Key engineTranslateKey(
+        Key key)
+        throws InvalidKeyException
+    {
+        if (key instanceof ECPublicKey)
+        {
+            return new BCECPublicKey((ECPublicKey)key, configuration);
+        }
+        else if (key instanceof ECPrivateKey)
+        {
+            return new BCECPrivateKey((ECPrivateKey)key, configuration);
+        }
+
+        throw new InvalidKeyException("key type unknown");
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key key,
+        Class spec)
+        throws InvalidKeySpecException
+    {
+        if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+        {
+            ECPublicKey k = (ECPublicKey)key;
+            if (k.getParams() != null)
+            {
+                return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams());
+            }
+            else
+            {
+                ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+                return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+            }
+        }
+        else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+        {
+            ECPrivateKey k = (ECPrivateKey)key;
+
+            if (k.getParams() != null)
+            {
+                return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams());
+            }
+            else
+            {
+                ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+                return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+            }
+        }
+        else if (spec.isAssignableFrom(com.android.internal.org.bouncycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+        {
+            ECPublicKey k = (ECPublicKey)key;
+            if (k.getParams() != null)
+            {
+                return new com.android.internal.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false));
+            }
+            else
+            {
+                ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+                return new com.android.internal.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec);
+            }
+        }
+        else if (spec.isAssignableFrom(com.android.internal.org.bouncycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+        {
+            ECPrivateKey k = (ECPrivateKey)key;
+
+            if (k.getParams() != null)
+            {
+                return new com.android.internal.org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false));
+            }
+            else
+            {
+                ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+                return new com.android.internal.org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), implicitSpec);
+            }
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (spec.isAssignableFrom(OpenSSHPublicKeySpec.class) && key instanceof ECPublicKey)
+        {
+            if (key instanceof BCECPublicKey)
+            {
+                BCECPublicKey bcPk = (BCECPublicKey)key;
+                ECParameterSpec sc = bcPk.getParameters();
+                try
+                {
+                    return new OpenSSHPublicKeySpec(
+                        OpenSSHPublicKeyUtil.encodePublicKey(
+                            new ECPublicKeyParameters(bcPk.getQ(), new ECDomainParameters(sc.getCurve(), sc.getG(), sc.getN(), sc.getH(), sc.getSeed()))));
+                }
+                catch (IOException e)
+                {
+                    throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage());
+                }
+            }
+            else
+            {
+                throw new IllegalArgumentException("invalid key type: " + key.getClass().getName());
+            }
+        }
+        else if (spec.isAssignableFrom(OpenSSHPrivateKeySpec.class) && key instanceof ECPrivateKey)
+        {
+            if (key instanceof BCECPrivateKey)
+            {
+                try
+                {
+                    return new OpenSSHPrivateKeySpec(PrivateKeyInfo.getInstance(key.getEncoded()).parsePrivateKey().toASN1Primitive().getEncoded());
+                }
+                catch (IOException e)
+                {
+                    throw new IllegalArgumentException("cannot encoded key: " + e.getMessage());
+                }
+            }
+            else
+            {
+                throw new IllegalArgumentException("invalid key type: " + key.getClass().getName());
+            }
+
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+
+        return super.engineGetKeySpec(key, spec);
+    }
+
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof ECPrivateKeySpec)
+        {
+            return new BCECPrivateKey(algorithm, (ECPrivateKeySpec)keySpec, configuration);
+        }
+        else if (keySpec instanceof java.security.spec.ECPrivateKeySpec)
+        {
+            return new BCECPrivateKey(algorithm, (java.security.spec.ECPrivateKeySpec)keySpec, configuration);
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (keySpec instanceof OpenSSHPrivateKeySpec)
+        {
+            org.bouncycastle.asn1.sec.ECPrivateKey ecKey = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(((OpenSSHPrivateKeySpec)keySpec).getEncoded());
+
+            try
+            {
+                return new BCECPrivateKey(algorithm, new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, ecKey.getParameters()), ecKey), configuration);
+            }
+            catch (IOException e)
+            {
+                throw new InvalidKeySpecException("bad encoding: " + e.getMessage());
+            }
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+
+        return super.engineGeneratePrivate(keySpec);
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        try
+        {
+            if (keySpec instanceof ECPublicKeySpec)
+            {
+                return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration);
+            }
+            else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
+            {
+                return new BCECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec, configuration);
+            }
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            else if (keySpec instanceof OpenSSHPublicKeySpec)
+            {
+                CipherParameters params = OpenSSHPublicKeyUtil.parsePublicKey(((OpenSSHPublicKeySpec)keySpec).getEncoded());
+                if (params instanceof ECPublicKeyParameters)
+                {
+                    ECDomainParameters parameters = ((ECPublicKeyParameters)params).getParameters();
+                    return engineGeneratePublic(
+                        new ECPublicKeySpec(((ECPublicKeyParameters)params).getQ(),
+                            new ECParameterSpec(parameters.getCurve(), parameters.getG(), parameters.getN(), parameters.getH(), parameters.getSeed())
+                        ));
+                }
+                else
+                {
+                    throw new IllegalArgumentException("openssh key is not ec public key");
+                }
+            }
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeySpecException("invalid KeySpec: " + e.getMessage(), e);
+        }
+
+        return super.engineGeneratePublic(keySpec);
+    }
+
+    public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+        if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+        {
+            return new BCECPrivateKey(algorithm, keyInfo, configuration);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+        if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+        {
+            return new BCECPublicKey(algorithm, keyInfo, configuration);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class EC
+        extends KeyFactorySpi
+    {
+        public EC()
+        {
+            super("EC", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class ECDSA
+        extends KeyFactorySpi
+    {
+        public ECDSA()
+        {
+            super("ECDSA", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithm
+    /*
+    public static class ECGOST3410
+        extends KeyFactorySpi
+    {
+        public ECGOST3410()
+        {
+            super("ECGOST3410", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    public static class ECGOST3410_2012
+        extends KeyFactorySpi
+    {
+        public ECGOST3410_2012()
+        {
+            super("ECGOST3410-2012", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithm
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class ECDH
+        extends KeyFactorySpi
+    {
+        public ECDH()
+        {
+            super("ECDH", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class ECDHC
+        extends KeyFactorySpi
+    {
+        public ECDHC()
+        {
+            super("ECDHC", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class ECMQV
+        extends KeyFactorySpi
+    {
+        public ECMQV()
+        {
+            super("ECMQV", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..10ae983
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
@@ -0,0 +1,311 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Hashtable;
+import java.util.Map;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
+import com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.util.Integers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class KeyPairGeneratorSpi
+    extends java.security.KeyPairGenerator
+{
+    public KeyPairGeneratorSpi(String algorithmName)
+    {
+        super(algorithmName);
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class EC
+        extends KeyPairGeneratorSpi
+    {
+        ECKeyGenerationParameters   param;
+        ECKeyPairGenerator          engine = new ECKeyPairGenerator();
+        Object                      ecParams = null;
+        // Android-changed: Use 256-bit keys by default.
+        // 239-bit keys (the Bouncy Castle default) are less widely-supported than 256-bit ones,
+        // so we've changed the default strength to 256 for increased compatibility
+        int                         strength = 256;
+        SecureRandom                random = CryptoServicesRegistrar.getSecureRandom();
+        boolean                     initialised = false;
+        String                      algorithm;
+        ProviderConfiguration       configuration;
+
+        static private Hashtable    ecParameters;
+
+        static {
+            ecParameters = new Hashtable();
+
+            ecParameters.put(Integers.valueOf(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
+            ecParameters.put(Integers.valueOf(239), new ECGenParameterSpec("prime239v1"));
+            ecParameters.put(Integers.valueOf(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
+
+            ecParameters.put(Integers.valueOf(224), new ECGenParameterSpec("P-224"));
+            ecParameters.put(Integers.valueOf(384), new ECGenParameterSpec("P-384"));
+            ecParameters.put(Integers.valueOf(521), new ECGenParameterSpec("P-521"));
+        }
+
+        public EC()
+        {
+            super("EC");
+            this.algorithm = "EC";
+            this.configuration = BouncyCastleProvider.CONFIGURATION;
+        }
+
+        public EC(
+            String  algorithm,
+            ProviderConfiguration configuration)
+        {
+            super(algorithm);
+            this.algorithm = algorithm;
+            this.configuration = configuration;
+        }
+
+        public void initialize(
+            int             strength,
+            SecureRandom    random)
+        {
+            this.strength = strength;
+            // BEGIN Android-changed: Don't override this.random with null.
+            // Passing null just means to use a default random, which this.random is already
+            // initialized to, so just use that
+            if (random != null) {
+                this.random = random;
+            }
+            // END Android-changed: Don't override this.random with null.
+
+            ECGenParameterSpec ecParams = (ECGenParameterSpec)ecParameters.get(Integers.valueOf(strength));
+            if (ecParams == null)
+            {
+                throw new InvalidParameterException("unknown key size.");
+            }
+
+            try
+            {
+                initialize(ecParams, random);
+            }
+            catch (InvalidAlgorithmParameterException e)
+            {
+                throw new InvalidParameterException("key size not configurable.");
+            }
+        }
+
+        public void initialize(
+            AlgorithmParameterSpec  params,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            // BEGIN Android-added: Use existing SecureRandom if none is provided.
+            if (random == null) {
+                random = this.random;
+            }
+            // END Android-added: Use existing SecureRandom if none is provided.
+            if (params == null)
+            {
+                ECParameterSpec implicitCA = configuration.getEcImplicitlyCa();
+                if (implicitCA == null)
+                {
+                    throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
+                }
+
+                this.ecParams = null;
+                this.param = createKeyGenParamsBC(implicitCA, random);
+            }
+            else if (params instanceof ECParameterSpec)
+            {
+                this.ecParams = params;
+                this.param = createKeyGenParamsBC((ECParameterSpec)params, random);
+            }
+            else if (params instanceof java.security.spec.ECParameterSpec)
+            {
+                this.ecParams = params;
+                this.param = createKeyGenParamsJCE((java.security.spec.ECParameterSpec)params, random);
+            }
+            else if (params instanceof ECGenParameterSpec)
+            {
+                initializeNamedCurve(((ECGenParameterSpec)params).getName(), random);
+            }
+            else if (params instanceof ECNamedCurveGenParameterSpec)
+            {
+                initializeNamedCurve(((ECNamedCurveGenParameterSpec)params).getName(), random);
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec");
+            }
+
+            engine.init(param);
+            initialised = true;
+        }
+
+        public KeyPair generateKeyPair()
+        {
+            if (!initialised)
+            {
+                initialize(strength, new SecureRandom());
+            }
+
+            AsymmetricCipherKeyPair     pair = engine.generateKeyPair();
+            ECPublicKeyParameters       pub = (ECPublicKeyParameters)pair.getPublic();
+            ECPrivateKeyParameters      priv = (ECPrivateKeyParameters)pair.getPrivate();
+
+            if (ecParams instanceof ECParameterSpec)
+            {
+                ECParameterSpec p = (ECParameterSpec)ecParams;
+
+                BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
+                return new KeyPair(pubKey,
+                                   new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
+            }
+            else if (ecParams == null)
+            {
+               return new KeyPair(new BCECPublicKey(algorithm, pub, configuration),
+                                   new BCECPrivateKey(algorithm, priv, configuration));
+            }
+            else
+            {
+                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+
+                BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
+                
+                return new KeyPair(pubKey, new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
+            }
+        }
+
+        protected ECKeyGenerationParameters createKeyGenParamsBC(ECParameterSpec p, SecureRandom r)
+        {
+            return new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), r);
+        }
+
+        protected ECKeyGenerationParameters createKeyGenParamsJCE(java.security.spec.ECParameterSpec p, SecureRandom r)
+        {
+            ECCurve curve = EC5Util.convertCurve(p.getCurve());
+            ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
+            BigInteger n = p.getOrder();
+            BigInteger h = BigInteger.valueOf(p.getCofactor());
+            ECDomainParameters dp = new ECDomainParameters(curve, g, n, h);
+            return new ECKeyGenerationParameters(dp, r);
+        }
+
+        protected ECNamedCurveSpec createNamedCurveSpec(String curveName)
+            throws InvalidAlgorithmParameterException
+        {
+            // NOTE: Don't bother with custom curves here as the curve will be converted to JCE type shortly
+
+            X9ECParameters p = ECUtils.getDomainParametersFromName(curveName);
+            if (p == null)
+            {
+                try
+                {
+                    // Check whether it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
+                    p = ECNamedCurveTable.getByOID(new ASN1ObjectIdentifier(curveName));
+                    if (p == null)
+                    {
+                        Map extraCurves = configuration.getAdditionalECParameters();
+
+                        p = (X9ECParameters)extraCurves.get(new ASN1ObjectIdentifier(curveName));
+
+                        if (p == null)
+                        {
+                            throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
+                        }
+                    }
+                }
+                catch (IllegalArgumentException ex)
+                {
+                    throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+                }
+            }
+
+            // Work-around for JDK bug -- it won't look up named curves properly if seed is present
+            byte[] seed = null; //p.getSeed();
+
+            return new ECNamedCurveSpec(curveName, p.getCurve(), p.getG(), p.getN(), p.getH(), seed);
+        }
+
+        protected void initializeNamedCurve(String curveName, SecureRandom random)
+            throws InvalidAlgorithmParameterException
+        {
+            ECNamedCurveSpec namedCurve = createNamedCurveSpec(curveName);
+            this.ecParams = namedCurve;
+            this.param = createKeyGenParamsJCE(namedCurve, random);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class ECDSA
+        extends EC
+    {
+        public ECDSA()
+        {
+            super("ECDSA", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class ECDH
+        extends EC
+    {
+        public ECDH()
+        {
+            super("ECDH", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class ECDHC
+        extends EC
+    {
+        public ECDHC()
+        {
+            super("ECDHC", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class ECMQV
+        extends EC
+    {
+        public ECMQV()
+        {
+            super("ECMQV", BouncyCastleProvider.CONFIGURATION);
+        }
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
new file mode 100644
index 0000000..6513b05
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
@@ -0,0 +1,394 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DSAExt;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.digests.NullDigest;
+// BEGIN Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// END Android-removed: Unsupported algorithms
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.android.internal.org.bouncycastle.crypto.signers.DSAEncoding;
+import com.android.internal.org.bouncycastle.crypto.signers.ECDSASigner;
+// BEGIN Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.signers.ECNRSigner;
+// import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
+// END Android-removed: Unsupported algorithms
+import com.android.internal.org.bouncycastle.crypto.signers.PlainDSAEncoding;
+import com.android.internal.org.bouncycastle.crypto.signers.StandardDSAEncoding;
+// BEGIN Android-changed: Use Android digests
+// import org.bouncycastle.crypto.util.DigestFactory;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.DSABase;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SignatureSpi
+    extends DSABase
+{
+    SignatureSpi(Digest digest, DSAExt signer, DSAEncoding encoding)
+    {
+        super(digest, signer, encoding);
+    }
+
+    protected void engineInitVerify(PublicKey publicKey)
+        throws InvalidKeyException
+    {
+        CipherParameters param = ECUtils.generatePublicKeyParameter(publicKey);
+
+        digest.reset();
+        signer.init(false, param);
+    }
+
+    protected void engineInitSign(
+        PrivateKey privateKey)
+        throws InvalidKeyException
+    {
+        CipherParameters param = ECUtil.generatePrivateKeyParameter(privateKey);
+
+        digest.reset();
+
+        if (appRandom != null)
+        {
+            signer.init(true, new ParametersWithRandom(param, appRandom));
+        }
+        else
+        {
+            signer.init(true, param);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class ecDSA
+        extends SignatureSpi
+    {
+        public ecDSA()
+        {
+            // Android-changed: Use Android digests
+            // super(DigestFactory.createSHA1(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+            super(AndroidDigestFactory.getSHA1(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithm
+    /*
+    static public class ecDetDSA
+        extends SignatureSpi
+    {
+        public ecDetDSA()
+        {
+            super(DigestFactory.createSHA1(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1())), StandardDSAEncoding.INSTANCE);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithm
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class ecDSAnone
+        extends SignatureSpi
+    {
+        public ecDSAnone()
+        {
+            super(new NullDigest(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class ecDSA224
+        extends SignatureSpi
+    {
+        public ecDSA224()
+        {
+            // Android-changed: Use Android digests
+            // super(DigestFactory.createSHA224(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+            super(AndroidDigestFactory.getSHA224(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithm
+    /*
+    static public class ecDetDSA224
+        extends SignatureSpi
+    {
+        public ecDetDSA224()
+        {
+            super(DigestFactory.createSHA224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224())), StandardDSAEncoding.INSTANCE);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithm
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class ecDSA256
+        extends SignatureSpi
+    {
+        public ecDSA256()
+        {
+            // Android-changed: Use Android digests
+            // super(DigestFactory.createSHA256(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+            super(AndroidDigestFactory.getSHA256(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithm
+    /*
+    static public class ecDetDSA256
+        extends SignatureSpi
+    {
+        public ecDetDSA256()
+        {
+            super(DigestFactory.createSHA256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256())), StandardDSAEncoding.INSTANCE);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithm
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class ecDSA384
+        extends SignatureSpi
+    {
+        public ecDSA384()
+        {
+            // Android-changed: Use Android digests
+            // super(DigestFactory.createSHA384(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+            super(AndroidDigestFactory.getSHA384(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithm
+    /*
+    static public class ecDetDSA384
+        extends SignatureSpi
+    {
+        public ecDetDSA384()
+        {
+            super(DigestFactory.createSHA384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384())), StandardDSAEncoding.INSTANCE);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class ecDSA512
+        extends SignatureSpi
+    {
+        public ecDSA512()
+        {
+            // Android-changed: Use Android digests
+            // super(DigestFactory.createSHA512(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+            super(AndroidDigestFactory.getSHA512(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    static public class ecDetDSA512
+        extends SignatureSpi
+    {
+        public ecDetDSA512()
+        {
+            super(DigestFactory.createSHA512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512())), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecDSASha3_224
+        extends SignatureSpi
+    {
+        public ecDSASha3_224()
+        {
+            super(DigestFactory.createSHA3_224(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecDetDSASha3_224
+        extends SignatureSpi
+    {
+        public ecDetDSASha3_224()
+        {
+            super(DigestFactory.createSHA3_224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224())), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecDSASha3_256
+        extends SignatureSpi
+    {
+        public ecDSASha3_256()
+        {
+            super(DigestFactory.createSHA3_256(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecDetDSASha3_256
+        extends SignatureSpi
+    {
+        public ecDetDSASha3_256()
+        {
+            super(DigestFactory.createSHA3_256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256())), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecDSASha3_384
+        extends SignatureSpi
+    {
+        public ecDSASha3_384()
+        {
+            super(DigestFactory.createSHA3_384(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecDetDSASha3_384
+        extends SignatureSpi
+    {
+        public ecDetDSASha3_384()
+        {
+            super(DigestFactory.createSHA3_384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384())), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecDSASha3_512
+        extends SignatureSpi
+    {
+        public ecDSASha3_512()
+        {
+            super(DigestFactory.createSHA3_512(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecDetDSASha3_512
+        extends SignatureSpi
+    {
+        public ecDetDSASha3_512()
+        {
+            super(DigestFactory.createSHA3_512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512())), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecDSARipeMD160
+        extends SignatureSpi
+    {
+        public ecDSARipeMD160()
+        {
+            super(new RIPEMD160Digest(), new ECDSASigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecNR
+        extends SignatureSpi
+    {
+        public ecNR()
+        {
+            super(DigestFactory.createSHA1(), new ECNRSigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecNR224
+        extends SignatureSpi
+    {
+        public ecNR224()
+        {
+            super(DigestFactory.createSHA224(), new ECNRSigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecNR256
+        extends SignatureSpi
+    {
+        public ecNR256()
+        {
+            super(DigestFactory.createSHA256(), new ECNRSigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecNR384
+        extends SignatureSpi
+    {
+        public ecNR384()
+        {
+            super(DigestFactory.createSHA384(), new ECNRSigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecNR512
+        extends SignatureSpi
+    {
+        public ecNR512()
+        {
+            super(DigestFactory.createSHA512(), new ECNRSigner(), StandardDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecCVCDSA
+        extends SignatureSpi
+    {
+        public ecCVCDSA()
+        {
+            super(DigestFactory.createSHA1(), new ECDSASigner(), PlainDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecCVCDSA224
+        extends SignatureSpi
+    {
+        public ecCVCDSA224()
+        {
+            super(DigestFactory.createSHA224(), new ECDSASigner(), PlainDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecCVCDSA256
+        extends SignatureSpi
+    {
+        public ecCVCDSA256()
+        {
+            super(DigestFactory.createSHA256(), new ECDSASigner(), PlainDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecCVCDSA384
+        extends SignatureSpi
+    {
+        public ecCVCDSA384()
+        {
+            super(DigestFactory.createSHA384(), new ECDSASigner(), PlainDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecCVCDSA512
+        extends SignatureSpi
+    {
+        public ecCVCDSA512()
+        {
+            super(DigestFactory.createSHA512(), new ECDSASigner(), PlainDSAEncoding.INSTANCE);
+        }
+    }
+
+    static public class ecPlainDSARP160
+        extends SignatureSpi
+    {
+        public ecPlainDSARP160()
+        {
+            super(new RIPEMD160Digest(), new ECDSASigner(), PlainDSAEncoding.INSTANCE);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..8381d95
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
@@ -0,0 +1,286 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
+import com.android.internal.org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.DigestFactory;
+import com.android.internal.org.bouncycastle.jcajce.util.MessageDigestUtils;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class AlgorithmParametersSpi
+    extends java.security.AlgorithmParametersSpi
+{
+    protected boolean isASN1FormatString(String format)
+    {
+        return format == null || format.equals("ASN.1");
+    }
+
+    protected AlgorithmParameterSpec engineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == null)
+        {
+            throw new NullPointerException("argument to getParameterSpec must not be null");
+        }
+
+        return localEngineGetParameterSpec(paramSpec);
+    }
+
+    protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+        throws InvalidParameterSpecException;
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class OAEP
+        extends AlgorithmParametersSpi
+    {
+        OAEPParameterSpec currentSpec;
+    
+        /**
+         * Return the PKCS#1 ASN.1 structure RSAES-OAEP-params.
+         */
+        protected byte[] engineGetEncoded() 
+        {
+            AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+                                                            DigestFactory.getOID(currentSpec.getDigestAlgorithm()),
+                                                            DERNull.INSTANCE);
+            MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)currentSpec.getMGFParameters();
+            AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+                                                            PKCSObjectIdentifiers.id_mgf1,
+                                                            new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
+            PSource.PSpecified      pSource = (PSource.PSpecified)currentSpec.getPSource();
+            AlgorithmIdentifier pSourceAlgorithm = new AlgorithmIdentifier(
+                                                            PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(pSource.getValue()));
+            RSAESOAEPparams oaepP = new RSAESOAEPparams(hashAlgorithm, maskGenAlgorithm, pSourceAlgorithm);
+    
+            try
+            {
+                return oaepP.getEncoded(ASN1Encoding.DER);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Error encoding OAEPParameters");
+            }
+        }
+    
+        protected byte[] engineGetEncoded(
+            String format)
+        {
+            if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+            {
+                return engineGetEncoded();
+            }
+    
+            return null;
+        }
+    
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+            Class paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == OAEPParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
+            {
+                return currentSpec;
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object.");
+        }
+    
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof OAEPParameterSpec))
+            {
+                throw new InvalidParameterSpecException("OAEPParameterSpec required to initialise an OAEP algorithm parameters object");
+            }
+    
+            this.currentSpec = (OAEPParameterSpec)paramSpec;
+        }
+    
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            try
+            {
+                RSAESOAEPparams oaepP = RSAESOAEPparams.getInstance(params);
+
+                if (!oaepP.getMaskGenAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1))
+                {
+                    throw new IOException("unknown mask generation function: " + oaepP.getMaskGenAlgorithm().getAlgorithm());
+                }
+
+                currentSpec = new OAEPParameterSpec(
+                                       MessageDigestUtils.getDigestName(oaepP.getHashAlgorithm().getAlgorithm()),
+                                       OAEPParameterSpec.DEFAULT.getMGFAlgorithm(),
+                                       new MGF1ParameterSpec(MessageDigestUtils.getDigestName(AlgorithmIdentifier.getInstance(oaepP.getMaskGenAlgorithm().getParameters()).getAlgorithm())),
+                                       new PSource.PSpecified(ASN1OctetString.getInstance(oaepP.getPSourceAlgorithm().getParameters()).getOctets()));
+            }
+            catch (ClassCastException e)
+            {
+                throw new IOException("Not a valid OAEP Parameter encoding.");
+            }
+            catch (ArrayIndexOutOfBoundsException e)
+            {
+                throw new IOException("Not a valid OAEP Parameter encoding.");
+            }
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format)
+            throws IOException
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                engineInit(params);
+            }
+            else
+            {
+                throw new IOException("Unknown parameter format " + format);
+            }
+        }
+    
+        protected String engineToString()
+        {
+            return "OAEP Parameters";
+        }
+    }
+    
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PSS
+        extends AlgorithmParametersSpi
+    {  
+        PSSParameterSpec currentSpec;
+    
+        /**
+         * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
+         */
+        protected byte[] engineGetEncoded() 
+            throws IOException
+        {
+            PSSParameterSpec pssSpec = currentSpec;
+            AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+                                                DigestFactory.getOID(pssSpec.getDigestAlgorithm()),
+                                                DERNull.INSTANCE);
+            MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)pssSpec.getMGFParameters();
+            AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+                                                PKCSObjectIdentifiers.id_mgf1,
+                                                new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
+            RSASSAPSSparams pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new ASN1Integer(pssSpec.getSaltLength()), new ASN1Integer(pssSpec.getTrailerField()));
+            
+            return pssP.getEncoded("DER");
+        }
+    
+        protected byte[] engineGetEncoded(
+            String format)
+            throws IOException
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                return engineGetEncoded();
+            }
+    
+            return null;
+        }
+    
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+            Class paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == PSSParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
+            {
+                return currentSpec;
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
+        }
+    
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof PSSParameterSpec))
+            {
+                throw new InvalidParameterSpecException("PSSParameterSpec required to initialise an PSS algorithm parameters object");
+            }
+    
+            this.currentSpec = (PSSParameterSpec)paramSpec;
+        }
+    
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            try
+            {
+                RSASSAPSSparams pssP = RSASSAPSSparams.getInstance(params);
+
+                if (!pssP.getMaskGenAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1))
+                {
+                    throw new IOException("unknown mask generation function: " + pssP.getMaskGenAlgorithm().getAlgorithm());
+                }
+
+                currentSpec = new PSSParameterSpec(
+                                       MessageDigestUtils.getDigestName(pssP.getHashAlgorithm().getAlgorithm()),
+                                       PSSParameterSpec.DEFAULT.getMGFAlgorithm(),
+                                       new MGF1ParameterSpec(MessageDigestUtils.getDigestName(AlgorithmIdentifier.getInstance(pssP.getMaskGenAlgorithm().getParameters()).getAlgorithm())),
+                                       pssP.getSaltLength().intValue(),
+                                       pssP.getTrailerField().intValue());
+            }
+            catch (ClassCastException e)
+            {
+                throw new IOException("Not a valid PSS Parameter encoding.");
+            }
+            catch (ArrayIndexOutOfBoundsException e)
+            {
+                throw new IOException("Not a valid PSS Parameter encoding.");
+            }
+        }
+    
+        protected void engineInit(
+            byte[] params,
+            String format)
+            throws IOException
+        {
+            if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+            {
+                engineInit(params);
+            }
+            else
+            {
+                throw new IOException("Unknown parameter format " + format);
+            }
+        }
+    
+        protected String engineToString()
+        {
+            return "PSS Parameters";
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
new file mode 100644
index 0000000..cb0b02a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
@@ -0,0 +1,243 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.pkcs.RSAPrivateKey;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * A provider representation for a RSA private key, with CRT factors included.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCRSAPrivateCrtKey
+    extends BCRSAPrivateKey
+    implements RSAPrivateCrtKey
+{
+    static final long serialVersionUID = 7834723820638524718L;
+    
+    private BigInteger  publicExponent;
+    private BigInteger  primeP;
+    private BigInteger  primeQ;
+    private BigInteger  primeExponentP;
+    private BigInteger  primeExponentQ;
+    private BigInteger  crtCoefficient;
+
+    /**
+     * construct a private key from it's org.bouncycastle.crypto equivalent.
+     *
+     * @param key the parameters object representing the private key.
+     */
+    BCRSAPrivateCrtKey(
+        RSAPrivateCrtKeyParameters key)
+    {
+        super(key);
+
+        this.publicExponent = key.getPublicExponent();
+        this.primeP = key.getP();
+        this.primeQ = key.getQ();
+        this.primeExponentP = key.getDP();
+        this.primeExponentQ = key.getDQ();
+        this.crtCoefficient = key.getQInv();
+    }
+
+    /**
+     * construct a private key from an RSAPrivateCrtKeySpec
+     *
+     * @param spec the spec to be used in construction.
+     */
+    BCRSAPrivateCrtKey(
+        RSAPrivateCrtKeySpec spec)
+    {
+        this.modulus = spec.getModulus();
+        this.publicExponent = spec.getPublicExponent();
+        this.privateExponent = spec.getPrivateExponent();
+        this.primeP = spec.getPrimeP();
+        this.primeQ = spec.getPrimeQ();
+        this.primeExponentP = spec.getPrimeExponentP();
+        this.primeExponentQ = spec.getPrimeExponentQ();
+        this.crtCoefficient = spec.getCrtCoefficient();
+    }
+
+    /**
+     * construct a private key from another RSAPrivateCrtKey.
+     *
+     * @param key the object implementing the RSAPrivateCrtKey interface.
+     */
+    BCRSAPrivateCrtKey(
+        RSAPrivateCrtKey key)
+    {
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getPublicExponent();
+        this.privateExponent = key.getPrivateExponent();
+        this.primeP = key.getPrimeP();
+        this.primeQ = key.getPrimeQ();
+        this.primeExponentP = key.getPrimeExponentP();
+        this.primeExponentQ = key.getPrimeExponentQ();
+        this.crtCoefficient = key.getCrtCoefficient();
+    }
+
+    /**
+     * construct an RSA key from a private key info object.
+     */
+    BCRSAPrivateCrtKey(
+        PrivateKeyInfo info)
+        throws IOException
+    {
+        this(RSAPrivateKey.getInstance(info.parsePrivateKey()));
+    }
+
+    /**
+     * construct an RSA key from a ASN.1 RSA private key object.
+     */
+    BCRSAPrivateCrtKey(
+        RSAPrivateKey key)
+    {
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getPublicExponent();
+        this.privateExponent = key.getPrivateExponent();
+        this.primeP = key.getPrime1();
+        this.primeQ = key.getPrime2();
+        this.primeExponentP = key.getExponent1();
+        this.primeExponentQ = key.getExponent2();
+        this.crtCoefficient = key.getCoefficient();
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the encoding format we produce in getEncoded().
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
+    }
+
+    /**
+     * return the public exponent.
+     *
+     * @return the public exponent.
+     */
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    /**
+     * return the prime P.
+     *
+     * @return the prime P.
+     */
+    public BigInteger getPrimeP()
+    {
+        return primeP;
+    }
+
+    /**
+     * return the prime Q.
+     *
+     * @return the prime Q.
+     */
+    public BigInteger getPrimeQ()
+    {
+        return primeQ;
+    }
+
+    /**
+     * return the prime exponent for P.
+     *
+     * @return the prime exponent for P.
+     */
+    public BigInteger getPrimeExponentP()
+    {
+        return primeExponentP;
+    }
+
+    /**
+     * return the prime exponent for Q.
+     *
+     * @return the prime exponent for Q.
+     */
+    public BigInteger getPrimeExponentQ()
+    {
+        return primeExponentQ;
+    }
+
+    /**
+     * return the CRT coefficient.
+     *
+     * @return the CRT coefficient.
+     */
+    public BigInteger getCrtCoefficient()
+    {
+        return crtCoefficient;
+    }
+
+    public int hashCode()
+    {
+        return this.getModulus().hashCode()
+               ^ this.getPublicExponent().hashCode()
+               ^ this.getPrivateExponent().hashCode();
+    }
+
+    public boolean equals(Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (!(o instanceof RSAPrivateCrtKey))
+        {
+            return false;
+        }
+
+        RSAPrivateCrtKey key = (RSAPrivateCrtKey)o;
+
+        return this.getModulus().equals(key.getModulus())
+         && this.getPublicExponent().equals(key.getPublicExponent())
+         && this.getPrivateExponent().equals(key.getPrivateExponent())
+         && this.getPrimeP().equals(key.getPrimeP())
+         && this.getPrimeQ().equals(key.getPrimeQ())
+         && this.getPrimeExponentP().equals(key.getPrimeExponentP())
+         && this.getPrimeExponentQ().equals(key.getPrimeExponentQ())
+         && this.getCrtCoefficient().equals(key.getCrtCoefficient());
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = Strings.lineSeparator();
+
+        buf.append("RSA Private CRT Key [").append(
+                    RSAUtil.generateKeyFingerprint(this.getModulus())).append("]")
+            .append(",[")
+            .append(RSAUtil.generateExponentFingerprint(this.getPublicExponent()))
+            .append("]")
+            .append(nl);
+        buf.append("             modulus: ").append(this.getModulus().toString(16)).append(nl);
+        buf.append("     public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+        
+        return buf.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
new file mode 100644
index 0000000..c707826
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
@@ -0,0 +1,162 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.RSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.crypto.params.RSAKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import com.android.internal.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCRSAPrivateKey
+    implements RSAPrivateKey, PKCS12BagAttributeCarrier
+{
+    static final long serialVersionUID = 5110188922551353628L;
+
+    private static BigInteger ZERO = BigInteger.valueOf(0);
+
+    protected BigInteger modulus;
+    protected BigInteger privateExponent;
+
+    private transient PKCS12BagAttributeCarrierImpl   attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected BCRSAPrivateKey()
+    {
+    }
+
+    BCRSAPrivateKey(
+        RSAKeyParameters key)
+    {
+        this.modulus = key.getModulus();
+        this.privateExponent = key.getExponent();
+    }
+
+    BCRSAPrivateKey(
+        RSAPrivateKeySpec spec)
+    {
+        this.modulus = spec.getModulus();
+        this.privateExponent = spec.getPrivateExponent();
+    }
+
+    BCRSAPrivateKey(
+        RSAPrivateKey key)
+    {
+        this.modulus = key.getModulus();
+        this.privateExponent = key.getPrivateExponent();
+    }
+
+    BCRSAPrivateKey(com.android.internal.org.bouncycastle.asn1.pkcs.RSAPrivateKey key)
+    {
+        this.modulus = key.getModulus();
+        this.privateExponent = key.getPrivateExponent();
+    }
+
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getPrivateExponent()
+    {
+        return privateExponent;
+    }
+
+    public String getAlgorithm()
+    {
+        return "RSA";
+    }
+
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    public byte[] getEncoded()
+    {
+        return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new com.android.internal.org.bouncycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof RSAPrivateKey))
+        {
+            return false;
+        }
+
+        if (o == this)
+        {
+            return true;
+        }
+
+        RSAPrivateKey key = (RSAPrivateKey)o;
+
+        return getModulus().equals(key.getModulus())
+            && getPrivateExponent().equals(key.getPrivateExponent());
+    }
+
+    public int hashCode()
+    {
+        return getModulus().hashCode() ^ getPrivateExponent().hashCode();
+    }
+
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        ASN1ObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    private void readObject(
+        ObjectInputStream   in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+    }
+
+    private void writeObject(
+        ObjectOutputStream  out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = Strings.lineSeparator();
+
+        buf.append("RSA Private Key [").append(
+                    RSAUtil.generateKeyFingerprint(this.getModulus())).append("],[]").append(nl);
+        buf.append("            modulus: ").append(this.getModulus().toString(16)).append(nl);
+
+        return buf.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
new file mode 100644
index 0000000..149202e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
@@ -0,0 +1,180 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.RSAPublicKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.crypto.params.RSAKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCRSAPublicKey
+    implements RSAPublicKey
+{
+    private static final AlgorithmIdentifier DEFAULT_ALGORITHM_IDENTIFIER = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
+
+    static final long serialVersionUID = 2675817738516720772L;
+
+    private BigInteger modulus;
+    private BigInteger publicExponent;
+    private transient AlgorithmIdentifier algorithmIdentifier;
+
+    BCRSAPublicKey(
+        RSAKeyParameters key)
+    {
+        this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getExponent();
+    }
+
+    BCRSAPublicKey(
+        RSAPublicKeySpec spec)
+    {
+        this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+        this.modulus = spec.getModulus();
+        this.publicExponent = spec.getPublicExponent();
+    }
+
+    BCRSAPublicKey(
+        RSAPublicKey key)
+    {
+        this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getPublicExponent();
+    }
+
+    BCRSAPublicKey(
+        SubjectPublicKeyInfo info)
+    {
+        populateFromPublicKeyInfo(info);
+    }
+
+    private void populateFromPublicKeyInfo(SubjectPublicKeyInfo info)
+    {
+        try
+        {
+            com.android.internal.org.bouncycastle.asn1.pkcs.RSAPublicKey  pubKey = com.android.internal.org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(info.parsePublicKey());
+
+            this.algorithmIdentifier = info.getAlgorithm();
+            this.modulus = pubKey.getModulus();
+            this.publicExponent = pubKey.getPublicExponent();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("invalid info structure in RSA public key");
+        }
+    }
+
+    /**
+     * return the modulus.
+     *
+     * @return the modulus.
+     */
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    /**
+     * return the public exponent.
+     *
+     * @return the public exponent.
+     */
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    public String getAlgorithm()
+    {
+        return "RSA";
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(algorithmIdentifier, new com.android.internal.org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent()));
+    }
+
+    public int hashCode()
+    {
+        return this.getModulus().hashCode() ^ this.getPublicExponent().hashCode();
+    }
+
+    public boolean equals(Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (!(o instanceof RSAPublicKey))
+        {
+            return false;
+        }
+
+        RSAPublicKey key = (RSAPublicKey)o;
+
+        return getModulus().equals(key.getModulus())
+            && getPublicExponent().equals(key.getPublicExponent());
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = Strings.lineSeparator();
+
+        buf.append("RSA Public Key [").append(RSAUtil.generateKeyFingerprint(this.getModulus())).append("]")
+            .append(",[")
+            .append(RSAUtil.generateExponentFingerprint(this.getPublicExponent()))
+            .append("]")
+            .append(nl);
+        buf.append("        modulus: ").append(this.getModulus().toString(16)).append(nl);
+        buf.append("public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+        
+        return buf.toString();
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        try
+        {
+            algorithmIdentifier = AlgorithmIdentifier.getInstance(in.readObject());
+        }
+        catch (Exception e)
+        {
+            algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+        }
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        if (!algorithmIdentifier.equals(DEFAULT_ALGORITHM_IDENTIFIER))
+        {
+            out.writeObject(algorithmIdentifier.getEncoded());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
new file mode 100644
index 0000000..8a9a86c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -0,0 +1,627 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.AsymmetricBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+// Android-removed: Unsupported algorithm
+// import org.bouncycastle.crypto.encodings.ISO9796d1Encoding;
+import com.android.internal.org.bouncycastle.crypto.encodings.OAEPEncoding;
+import com.android.internal.org.bouncycastle.crypto.encodings.PKCS1Encoding;
+import com.android.internal.org.bouncycastle.crypto.engines.RSABlindedEngine;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.BadBlockException;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.DigestFactory;
+// Android-changed: Use default provider for JCA algorithms instead of BC
+// Was: import org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CipherSpi
+    extends BaseCipherSpi
+{
+    // Android-changed: Use default provider for JCA algorithms instead of BC
+    // Was: private final JcaJceHelper helper = new BCJcaJceHelper();
+    private final JcaJceHelper helper = new DefaultJcaJceHelper();
+
+    private AsymmetricBlockCipher   cipher;
+    private AlgorithmParameterSpec  paramSpec;
+    private AlgorithmParameters     engineParams;
+    private boolean                 publicKeyOnly = false;
+    private boolean                 privateKeyOnly = false;
+    private ErasableOutputStream    bOut = new ErasableOutputStream();
+
+    public CipherSpi(
+        AsymmetricBlockCipher engine)
+    {
+        cipher = engine;
+    }
+
+    public CipherSpi(
+        OAEPParameterSpec pSpec)
+    {
+        try
+        {
+            initFromSpec(pSpec);
+        }
+        catch (NoSuchPaddingException e)
+        {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+
+    public CipherSpi(
+        boolean publicKeyOnly,
+        boolean privateKeyOnly,
+        AsymmetricBlockCipher engine)
+    {
+        this.publicKeyOnly = publicKeyOnly;
+        this.privateKeyOnly = privateKeyOnly;
+        cipher = engine;
+    }
+     
+    private void initFromSpec(
+        OAEPParameterSpec pSpec)
+        throws NoSuchPaddingException
+    {
+        MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)pSpec.getMGFParameters();
+        Digest digest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
+        
+        if (digest == null)
+        {
+            throw new NoSuchPaddingException("no match on OAEP constructor for digest algorithm: "+ mgfParams.getDigestAlgorithm());
+        }
+
+        cipher = new OAEPEncoding(new RSABlindedEngine(), digest, ((PSource.PSpecified)pSpec.getPSource()).getValue());
+        paramSpec = pSpec;
+    }
+    
+    protected int engineGetBlockSize() 
+    {
+        try
+        {
+            return cipher.getInputBlockSize();
+        }
+        catch (NullPointerException e)
+        {
+            throw new IllegalStateException("RSA Cipher not initialised");
+        }
+    }
+
+    protected int engineGetKeySize(
+        Key key)
+    {
+        if (key instanceof RSAPrivateKey)
+        {
+            RSAPrivateKey k = (RSAPrivateKey)key;
+
+            return k.getModulus().bitLength();
+        }
+        else if (key instanceof RSAPublicKey)
+        {
+            RSAPublicKey k = (RSAPublicKey)key;
+
+            return k.getModulus().bitLength();
+        }
+
+        throw new IllegalArgumentException("not an RSA key!");
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen) 
+    {
+        try
+        {
+            return cipher.getOutputBlockSize();
+        }
+        catch (NullPointerException e)
+        {
+            throw new IllegalStateException("RSA Cipher not initialised");
+        }
+    }
+
+    protected AlgorithmParameters engineGetParameters()
+    {
+        if (engineParams == null)
+        {
+            if (paramSpec != null)
+            {
+                try
+                {
+                    engineParams = helper.createAlgorithmParameters("OAEP");
+                    engineParams.init(paramSpec);
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
+        }
+
+        return engineParams;
+    }
+
+    protected void engineSetMode(
+        String mode)
+        throws NoSuchAlgorithmException
+    {
+        String md = Strings.toUpperCase(mode);
+        
+        if (md.equals("NONE") || md.equals("ECB"))
+        {
+            return;
+        }
+        
+        if (md.equals("1"))
+        {
+            privateKeyOnly = true;
+            publicKeyOnly = false;
+            return;
+        }
+        else if (md.equals("2"))
+        {
+            privateKeyOnly = false;
+            publicKeyOnly = true;
+            return;
+        }
+        
+        throw new NoSuchAlgorithmException("can't support mode " + mode);
+    }
+
+    protected void engineSetPadding(
+        String padding)
+        throws NoSuchPaddingException
+    {
+        String pad = Strings.toUpperCase(padding);
+
+        if (pad.equals("NOPADDING"))
+        {
+            cipher = new RSABlindedEngine();
+        }
+        else if (pad.equals("PKCS1PADDING"))
+        {
+            cipher = new PKCS1Encoding(new RSABlindedEngine());
+        }
+        // BEGIN Android-removed: Unsupported algorithm
+        // else if (pad.equals("ISO9796-1PADDING"))
+        // {
+        //     cipher = new ISO9796d1Encoding(new RSABlindedEngine());
+        // }
+        // END Android-removed: Unsupported algorithm
+        else if (pad.equals("OAEPWITHMD5ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("MD5", "MGF1", new MGF1ParameterSpec("MD5"), PSource.PSpecified.DEFAULT));
+        }
+        else if (pad.equals("OAEPPADDING"))
+        {
+            initFromSpec(OAEPParameterSpec.DEFAULT);
+        }
+        else if (pad.equals("OAEPWITHSHA1ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-1ANDMGF1PADDING"))
+        {
+            initFromSpec(OAEPParameterSpec.DEFAULT);
+        }
+        else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-224ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), PSource.PSpecified.DEFAULT));
+        }
+        else if (pad.equals("OAEPWITHSHA256ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-256ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
+        }
+        else if (pad.equals("OAEPWITHSHA384ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-384ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
+        }
+        else if (pad.equals("OAEPWITHSHA512ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-512ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (pad.equals("OAEPWITHSHA3-224ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA3-224", "MGF1", new MGF1ParameterSpec("SHA3-224"), PSource.PSpecified.DEFAULT));
+        }
+        else if (pad.equals("OAEPWITHSHA3-256ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA3-256", "MGF1", new MGF1ParameterSpec("SHA3-256"), PSource.PSpecified.DEFAULT));
+        }
+        else if (pad.equals("OAEPWITHSHA3-384ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA3-384", "MGF1", new MGF1ParameterSpec("SHA3-384"), PSource.PSpecified.DEFAULT));
+        }
+        else if (pad.equals("OAEPWITHSHA3-512ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA3-512", "MGF1", new MGF1ParameterSpec("SHA3-512"), PSource.PSpecified.DEFAULT));
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+        else
+        {
+            throw new NoSuchPaddingException(padding + " unavailable with RSA.");
+        }
+    }
+
+    protected void engineInit(
+        int                     opmode,
+        Key key,
+        AlgorithmParameterSpec params,
+        SecureRandom random)
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters param;
+
+        if (params == null || params instanceof OAEPParameterSpec)
+        {
+            if (key instanceof RSAPublicKey)
+            {
+                if (privateKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+                {
+                    throw new InvalidKeyException(
+                                "mode 1 requires RSAPrivateKey");
+                }
+
+                param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)key);
+            }
+            else if (key instanceof RSAPrivateKey)
+            {
+                if (publicKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+                {
+                    throw new InvalidKeyException(
+                                "mode 2 requires RSAPublicKey");
+                }
+
+                param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)key);
+            }
+            else
+            {
+                throw new InvalidKeyException("unknown key type passed to RSA");
+            }
+            
+            if (params != null)
+            {
+                OAEPParameterSpec spec = (OAEPParameterSpec)params;
+                
+                paramSpec = params;
+                
+                if (!spec.getMGFAlgorithm().equalsIgnoreCase("MGF1") && !spec.getMGFAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1.getId()))
+                {
+                    throw new InvalidAlgorithmParameterException("unknown mask generation function specified");
+                }
+                
+                if (!(spec.getMGFParameters() instanceof MGF1ParameterSpec))
+                {
+                    throw new InvalidAlgorithmParameterException("unkown MGF parameters");
+                }
+    
+                Digest digest = DigestFactory.getDigest(spec.getDigestAlgorithm());
+
+                if (digest == null)
+                {
+                    throw new InvalidAlgorithmParameterException("no match on digest algorithm: "+ spec.getDigestAlgorithm());
+                }
+
+                MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)spec.getMGFParameters();
+                Digest mgfDigest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
+                
+                if (mgfDigest == null)
+                {
+                    throw new InvalidAlgorithmParameterException("no match on MGF digest algorithm: "+ mgfParams.getDigestAlgorithm());
+                }
+
+                cipher = new OAEPEncoding(new RSABlindedEngine(), digest, mgfDigest, ((PSource.PSpecified)spec.getPSource()).getValue());
+            }
+        }
+        else
+        {
+            throw new InvalidAlgorithmParameterException("unknown parameter type: " + params.getClass().getName());
+        }
+
+        if (!(cipher instanceof RSABlindedEngine))
+        {
+            if (random != null)
+            {
+                param = new ParametersWithRandom(param, random);
+            }
+            else
+            {
+                param = new ParametersWithRandom(param, CryptoServicesRegistrar.getSecureRandom());
+            }
+        }
+
+        bOut.reset();
+
+        switch (opmode)
+        {
+        case Cipher.ENCRYPT_MODE:
+        case Cipher.WRAP_MODE:
+            cipher.init(true, param);
+            break;
+        case Cipher.DECRYPT_MODE:
+        case Cipher.UNWRAP_MODE:
+            cipher.init(false, param);
+            break;
+        default:
+            throw new InvalidParameterException("unknown opmode " + opmode + " passed to RSA");
+        }
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key key,
+        AlgorithmParameters params,
+        SecureRandom random)
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec paramSpec = null;
+
+        if (params != null)
+        {
+            try
+            {
+                paramSpec = params.getParameterSpec(OAEPParameterSpec.class);
+            }
+            catch (InvalidParameterSpecException e)
+            {
+                throw new InvalidAlgorithmParameterException("cannot recognise parameters: " + e.toString(), e);
+            }
+        }
+
+        engineParams = params;
+        engineInit(opmode, key, paramSpec, random);
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key key,
+        SecureRandom random)
+    throws InvalidKeyException
+    {
+        try
+        {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            // this shouldn't happen
+            throw new InvalidKeyException("Eeeek! " + e.toString(), e);
+        }
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        bOut.write(input, inputOffset, inputLen);
+
+        if (cipher instanceof RSABlindedEngine)
+        {
+            if (bOut.size() > cipher.getInputBlockSize() + 1)
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+        else
+        {
+            if (bOut.size() > cipher.getInputBlockSize())
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+
+        return null;
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+    {
+        bOut.write(input, inputOffset, inputLen);
+
+        if (cipher instanceof RSABlindedEngine)
+        {
+            if (bOut.size() > cipher.getInputBlockSize() + 1)
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+        else
+        {
+            if (bOut.size() > cipher.getInputBlockSize())
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+
+        return 0;
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        if (input != null)
+        {
+            bOut.write(input, inputOffset, inputLen);
+        }
+
+        if (cipher instanceof RSABlindedEngine)
+        {
+            if (bOut.size() > cipher.getInputBlockSize() + 1)
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+        else
+        {
+            if (bOut.size() > cipher.getInputBlockSize())
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+
+        return getOutput();
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+        throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+    {
+        if (outputOffset + engineGetOutputSize(inputLen) > output.length)
+        {
+            throw new ShortBufferException("output buffer too short for input.");
+        }
+
+        if (input != null)
+        {
+            bOut.write(input, inputOffset, inputLen);
+        }
+
+        if (cipher instanceof RSABlindedEngine)
+        {
+            if (bOut.size() > cipher.getInputBlockSize() + 1)
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+        else
+        {
+            if (bOut.size() > cipher.getInputBlockSize())
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+
+        byte[]  out = getOutput();
+
+        for (int i = 0; i != out.length; i++)
+        {
+            output[outputOffset + i] = out[i];
+        }
+
+        return out.length;
+    }
+
+    private byte[] getOutput()
+        throws BadPaddingException
+    {
+        try
+        {
+            return cipher.processBlock(bOut.getBuf(), 0, bOut.size());
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new BadBlockException("unable to decrypt block", e);
+        }
+        catch (ArrayIndexOutOfBoundsException e)
+        {
+            throw new BadBlockException("unable to decrypt block", e);
+        }
+        finally
+        {
+            bOut.erase();
+        }
+    }
+
+    /**
+     * classes that inherit from us.
+     * @hide This class is not part of the Android public SDK API
+     */
+
+    static public class NoPadding
+        extends CipherSpi
+    {
+        public NoPadding()
+        {
+            super(new RSABlindedEngine());
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    static public class PKCS1v1_5Padding
+        extends CipherSpi
+    {
+        public PKCS1v1_5Padding()
+        {
+            super(new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class PKCS1v1_5Padding_PrivateOnly
+        extends CipherSpi
+    {
+        public PKCS1v1_5Padding_PrivateOnly()
+        {
+            super(false, true, new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class PKCS1v1_5Padding_PublicOnly
+        extends CipherSpi
+    {
+        public PKCS1v1_5Padding_PublicOnly()
+        {
+            super(true, false, new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class OAEPPadding
+        extends CipherSpi
+    {
+        public OAEPPadding()
+        {
+            super(OAEPParameterSpec.DEFAULT);
+        }
+    }
+    
+    static public class ISO9796d1Padding
+        extends CipherSpi
+    {
+        public ISO9796d1Padding()
+        {
+            super(new ISO9796d1Encoding(new RSABlindedEngine()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
new file mode 100644
index 0000000..3ec528d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
@@ -0,0 +1,453 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.DigestInfo;
+import com.android.internal.org.bouncycastle.crypto.AsymmetricBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.digests.MD2Digest;
+// import org.bouncycastle.crypto.digests.MD4Digest;
+// import org.bouncycastle.crypto.digests.NullDigest;
+// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD256Digest;
+import com.android.internal.org.bouncycastle.crypto.encodings.PKCS1Encoding;
+import com.android.internal.org.bouncycastle.crypto.engines.RSABlindedEngine;
+// Android-changed: Use Android digests
+// import org.bouncycastle.crypto.util.DigestFactory;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DigestSignatureSpi
+    extends SignatureSpi
+{
+    private Digest digest;
+    private AsymmetricBlockCipher cipher;
+    private AlgorithmIdentifier algId;
+
+    // care - this constructor is actually used by outside organisations
+    protected DigestSignatureSpi(
+        Digest digest,
+        AsymmetricBlockCipher cipher)
+    {
+        this.digest = digest;
+        this.cipher = cipher;
+        this.algId = null;
+    }
+
+    // care - this constructor is actually used by outside organisations
+    protected DigestSignatureSpi(
+        ASN1ObjectIdentifier objId,
+        Digest digest,
+        AsymmetricBlockCipher cipher)
+    {
+        this.digest = digest;
+        this.cipher = cipher;
+        this.algId = new AlgorithmIdentifier(objId, DERNull.INSTANCE);
+    }
+
+    protected void engineInitVerify(
+        PublicKey publicKey)
+        throws InvalidKeyException
+    {
+        if (!(publicKey instanceof RSAPublicKey))
+        {
+            throw new InvalidKeyException("Supplied key (" + getType(publicKey) + ") is not a RSAPublicKey instance");
+        }
+
+        CipherParameters param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+        digest.reset();
+        cipher.init(false, param);
+    }
+
+    protected void engineInitSign(
+        PrivateKey privateKey)
+        throws InvalidKeyException
+    {
+        if (!(privateKey instanceof RSAPrivateKey))
+        {
+            throw new InvalidKeyException("Supplied key (" + getType(privateKey) + ") is not a RSAPrivateKey instance");
+        }
+
+        CipherParameters param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+        digest.reset();
+
+        cipher.init(true, param);
+    }
+
+    private String getType(
+        Object o)
+    {
+        if (o == null)
+        {
+            return null;
+        }
+        
+        return o.getClass().getName();
+    }
+    
+    protected void engineUpdate(
+        byte    b)
+        throws SignatureException
+    {
+        digest.update(b);
+    }
+
+    protected void engineUpdate(
+        byte[]  b,
+        int     off,
+        int     len) 
+        throws SignatureException
+    {
+        digest.update(b, off, len);
+    }
+
+    protected byte[] engineSign()
+        throws SignatureException
+    {
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        digest.doFinal(hash, 0);
+
+        try
+        {
+            byte[]  bytes = derEncode(hash);
+
+            return cipher.processBlock(bytes, 0, bytes.length);
+        }
+        catch (ArrayIndexOutOfBoundsException e)
+        {
+            throw new SignatureException("key too small for signature type");
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException(e.toString());
+        }
+    }
+
+    protected boolean engineVerify(
+        byte[]  sigBytes) 
+        throws SignatureException
+    {
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        digest.doFinal(hash, 0);
+
+        byte[]      sig;
+        byte[]      expected;
+
+        try
+        {
+            sig = cipher.processBlock(sigBytes, 0, sigBytes.length);
+
+            expected = derEncode(hash);
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+
+        if (sig.length == expected.length)
+        {
+            return Arrays.constantTimeAreEqual(sig, expected);
+        }
+        else if (sig.length == expected.length - 2)  // NULL left out
+        {
+            expected[1] -= 2;      // adjust lengths
+            expected[3] -= 2;
+
+            int sigOffset = 4 + expected[3];
+            int expectedOffset = sigOffset + 2;
+            int nonEqual = 0;
+
+            for (int i = 0; i < expected.length - expectedOffset; i++)
+            {
+                nonEqual |= (sig[sigOffset + i] ^ expected[expectedOffset + i]);
+            }
+
+            for (int i = 0; i < sigOffset; i++)
+            {
+                nonEqual |= (sig[i] ^ expected[i]);  // check header less NULL
+            }
+
+            return nonEqual == 0;
+        }
+        else
+        {
+            Arrays.constantTimeAreEqual(expected, expected);  // keep time "steady".
+
+            return false;
+        }
+    }
+
+    protected void engineSetParameter(
+        AlgorithmParameterSpec params)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated replaced with #engineSetParameter(java.security.spec.AlgorithmParameterSpec)
+     */
+    protected void engineSetParameter(
+        String param,
+        Object value)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated
+     */
+    protected Object engineGetParameter(
+        String param)
+    {
+        return null;
+    }
+
+    protected AlgorithmParameters engineGetParameters()
+    {
+        return null;
+    }
+
+    private byte[] derEncode(
+        byte[]  hash)
+        throws IOException
+    {
+        if (algId == null)
+        {
+            // For raw RSA, the DigestInfo must be prepared externally
+            return hash;
+        }
+
+        DigestInfo dInfo = new DigestInfo(algId, hash);
+
+        return dInfo.getEncoded(ASN1Encoding.DER);
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class SHA1
+        extends DigestSignatureSpi
+    {
+        public SHA1()
+        {
+            // Android-changed: Use Android digests
+            // super(OIWObjectIdentifiers.idSHA1, DigestFactory.createSHA1(), new PKCS1Encoding(new RSABlindedEngine()));
+            super(OIWObjectIdentifiers.idSHA1, AndroidDigestFactory.getSHA1(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class SHA224
+        extends DigestSignatureSpi
+    {
+        public SHA224()
+        {
+            // Android-changed: Use Android digests
+            // super(NISTObjectIdentifiers.id_sha224, DigestFactory.createSHA224(), new PKCS1Encoding(new RSABlindedEngine()));
+            super(NISTObjectIdentifiers.id_sha224, AndroidDigestFactory.getSHA224(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class SHA256
+        extends DigestSignatureSpi
+    {
+        public SHA256()
+        {
+            // Android-changed: Use Android digests
+            // super(NISTObjectIdentifiers.id_sha256, DigestFactory.createSHA256(), new PKCS1Encoding(new RSABlindedEngine()));
+            super(NISTObjectIdentifiers.id_sha256, AndroidDigestFactory.getSHA256(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class SHA384
+        extends DigestSignatureSpi
+    {
+        public SHA384()
+        {
+            // Android-changed: Use Android digests
+            // super(NISTObjectIdentifiers.id_sha384, DigestFactory.createSHA384(), new PKCS1Encoding(new RSABlindedEngine()));
+            super(NISTObjectIdentifiers.id_sha384, AndroidDigestFactory.getSHA384(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class SHA512
+        extends DigestSignatureSpi
+    {
+        public SHA512()
+        {
+            // Android-changed: Use Android digests
+            // super(NISTObjectIdentifiers.id_sha512, DigestFactory.createSHA512(), new PKCS1Encoding(new RSABlindedEngine()));
+            super(NISTObjectIdentifiers.id_sha512, AndroidDigestFactory.getSHA512(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    static public class SHA512_224
+        extends DigestSignatureSpi
+    {
+        public SHA512_224()
+        {
+            super(NISTObjectIdentifiers.id_sha512_224, DigestFactory.createSHA512_224(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class SHA512_256
+        extends DigestSignatureSpi
+    {
+        public SHA512_256()
+        {
+            super(NISTObjectIdentifiers.id_sha512_256, DigestFactory.createSHA512_256(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class SHA3_224
+        extends DigestSignatureSpi
+    {
+        public SHA3_224()
+        {
+            super(NISTObjectIdentifiers.id_sha3_224, DigestFactory.createSHA3_224(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class SHA3_256
+        extends DigestSignatureSpi
+    {
+        public SHA3_256()
+        {
+            super(NISTObjectIdentifiers.id_sha3_256, DigestFactory.createSHA3_256(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class SHA3_384
+        extends DigestSignatureSpi
+    {
+        public SHA3_384()
+        {
+            super(NISTObjectIdentifiers.id_sha3_384, DigestFactory.createSHA3_384(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class SHA3_512
+        extends DigestSignatureSpi
+    {
+        public SHA3_512()
+        {
+            super(NISTObjectIdentifiers.id_sha3_512, DigestFactory.createSHA3_512(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class MD2
+        extends DigestSignatureSpi
+    {
+        public MD2()
+        {
+            super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class MD4
+        extends DigestSignatureSpi
+    {
+        public MD4()
+        {
+            super(PKCSObjectIdentifiers.md4, new MD4Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class MD5
+        extends DigestSignatureSpi
+    {
+        public MD5()
+        {
+            // Android-changed: Use Android digests
+            // super(PKCSObjectIdentifiers.md5, DigestFactory.createMD5(), new PKCS1Encoding(new RSABlindedEngine()));
+            super(PKCSObjectIdentifiers.md5, AndroidDigestFactory.getMD5(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    static public class RIPEMD160
+        extends DigestSignatureSpi
+    {
+        public RIPEMD160()
+        {
+            super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class RIPEMD128
+        extends DigestSignatureSpi
+    {
+        public RIPEMD128()
+        {
+            super(TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class RIPEMD256
+        extends DigestSignatureSpi
+    {
+        public RIPEMD256()
+        {
+            super(TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+
+    static public class noneRSA
+        extends DigestSignatureSpi
+    {
+        public noneRSA()
+        {
+            super(new NullDigest(), new PKCS1Encoding(new RSABlindedEngine()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
new file mode 100644
index 0000000..890876f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
@@ -0,0 +1,257 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.pkcs.RSAPrivateKey;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
+// import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec;
+// import org.bouncycastle.jce.spec.OpenSSHPublicKeySpec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyFactorySpi
+    extends BaseKeyFactorySpi
+{
+    public KeyFactorySpi()
+    {
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key key,
+        Class spec)
+        throws InvalidKeySpecException
+    {
+        if (spec.isAssignableFrom(RSAPublicKeySpec.class) && key instanceof RSAPublicKey)
+        {
+            RSAPublicKey k = (RSAPublicKey)key;
+
+            return new RSAPublicKeySpec(k.getModulus(), k.getPublicExponent());
+        }
+        else if (spec.isAssignableFrom(RSAPrivateKeySpec.class) && key instanceof java.security.interfaces.RSAPrivateKey)
+        {
+            java.security.interfaces.RSAPrivateKey k = (java.security.interfaces.RSAPrivateKey)key;
+
+            return new RSAPrivateKeySpec(k.getModulus(), k.getPrivateExponent());
+        }
+        else if (spec.isAssignableFrom(RSAPrivateCrtKeySpec.class) && key instanceof RSAPrivateCrtKey)
+        {
+            RSAPrivateCrtKey k = (RSAPrivateCrtKey)key;
+
+            return new RSAPrivateCrtKeySpec(
+                k.getModulus(), k.getPublicExponent(),
+                k.getPrivateExponent(),
+                k.getPrimeP(), k.getPrimeQ(),
+                k.getPrimeExponentP(), k.getPrimeExponentQ(),
+                k.getCrtCoefficient());
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (spec.isAssignableFrom(OpenSSHPublicKeySpec.class) && key instanceof RSAPublicKey)
+        {
+            try
+            {
+                return new OpenSSHPublicKeySpec(
+                    OpenSSHPublicKeyUtil.encodePublicKey(
+                        new RSAKeyParameters(
+                            false,
+                            ((RSAPublicKey)key).getModulus(),
+                            ((RSAPublicKey)key).getPublicExponent())
+                    )
+                );
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage());
+            }
+        }
+        else if (spec.isAssignableFrom(OpenSSHPrivateKeySpec.class) && key instanceof RSAPrivateCrtKey)
+        {
+            try
+            {
+                return new OpenSSHPrivateKeySpec(OpenSSHPrivateKeyUtil.encodePrivateKey(new RSAPrivateCrtKeyParameters(
+                    ((RSAPrivateCrtKey)key).getModulus(),
+                    ((RSAPrivateCrtKey)key).getPublicExponent(),
+                    ((RSAPrivateCrtKey)key).getPrivateExponent(),
+                    ((RSAPrivateCrtKey)key).getPrimeP(),
+                    ((RSAPrivateCrtKey)key).getPrimeQ(),
+                    ((RSAPrivateCrtKey)key).getPrimeExponentP(),
+                    ((RSAPrivateCrtKey)key).getPrimeExponentQ(),
+                    ((RSAPrivateCrtKey)key).getCrtCoefficient()
+                )));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage());
+            }
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+
+        return super.engineGetKeySpec(key, spec);
+    }
+
+    protected Key engineTranslateKey(
+        Key key)
+        throws InvalidKeyException
+    {
+        if (key instanceof RSAPublicKey)
+        {
+            return new BCRSAPublicKey((RSAPublicKey)key);
+        }
+        else if (key instanceof RSAPrivateCrtKey)
+        {
+            return new BCRSAPrivateCrtKey((RSAPrivateCrtKey)key);
+        }
+        else if (key instanceof java.security.interfaces.RSAPrivateKey)
+        {
+            return new BCRSAPrivateKey((java.security.interfaces.RSAPrivateKey)key);
+        }
+
+        throw new InvalidKeyException("key type unknown");
+    }
+
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof PKCS8EncodedKeySpec)
+        {
+            try
+            {
+                return generatePrivate(PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+            }
+            catch (Exception e)
+            {
+                //
+                // in case it's just a RSAPrivateKey object... -- openSSL produces these
+                //
+                try
+                {
+                    return new BCRSAPrivateCrtKey(
+                        RSAPrivateKey.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+                }
+                catch (Exception ex)
+                {
+                    throw new ExtendedInvalidKeySpecException("unable to process key spec: " + e.toString(), e);
+                }
+            }
+        }
+        else if (keySpec instanceof RSAPrivateCrtKeySpec)
+        {
+            return new BCRSAPrivateCrtKey((RSAPrivateCrtKeySpec)keySpec);
+        }
+        else if (keySpec instanceof RSAPrivateKeySpec)
+        {
+            return new BCRSAPrivateKey((RSAPrivateKeySpec)keySpec);
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (keySpec instanceof OpenSSHPrivateKeySpec)
+        {
+            CipherParameters parameters = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(((OpenSSHPrivateKeySpec)keySpec).getEncoded());
+
+            if (parameters instanceof RSAPrivateCrtKeyParameters)
+            {
+                return new BCRSAPrivateCrtKey((RSAPrivateCrtKeyParameters)parameters);
+            }
+
+            throw new InvalidKeySpecException("open SSH public key is not RSA private key");
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+
+        throw new InvalidKeySpecException("unknown KeySpec type: " + keySpec.getClass().getName());
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof RSAPublicKeySpec)
+        {
+            return new BCRSAPublicKey((RSAPublicKeySpec)keySpec);
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (keySpec instanceof OpenSSHPublicKeySpec)
+        {
+
+            CipherParameters parameters = OpenSSHPublicKeyUtil.parsePublicKey(((OpenSSHPublicKeySpec)keySpec).getEncoded());
+            if (parameters instanceof RSAKeyParameters)
+            {
+                return new BCRSAPublicKey((RSAKeyParameters)parameters);
+            }
+
+            throw new InvalidKeySpecException("Open SSH public key is not RSA public key");
+
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+
+        return super.engineGeneratePublic(keySpec);
+    }
+
+    public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+        if (RSAUtil.isRsaOid(algOid))
+        {
+            RSAPrivateKey rsaPrivKey = RSAPrivateKey.getInstance(keyInfo.parsePrivateKey());
+
+            if (rsaPrivKey.getCoefficient().intValue() == 0)
+            {
+                return new BCRSAPrivateKey(rsaPrivKey);
+            }
+            else
+            {
+                return new BCRSAPrivateCrtKey(keyInfo);
+            }
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+        if (RSAUtil.isRsaOid(algOid))
+        {
+            return new BCRSAPublicKey(keyInfo);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..6b9cbee
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
@@ -0,0 +1,87 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.RSAKeyGenParameterSpec;
+
+import com.android.internal.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PrimeCertaintyCalculator;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyPairGeneratorSpi
+    extends java.security.KeyPairGenerator
+{
+    public KeyPairGeneratorSpi(
+        String algorithmName)
+    {
+        super(algorithmName);
+    }
+
+    final static BigInteger defaultPublicExponent = BigInteger.valueOf(0x10001);
+
+    RSAKeyGenerationParameters param;
+    RSAKeyPairGenerator engine;
+
+    public KeyPairGeneratorSpi()
+    {
+        super("RSA");
+
+        engine = new RSAKeyPairGenerator();
+        param = new RSAKeyGenerationParameters(defaultPublicExponent,
+            CryptoServicesRegistrar.getSecureRandom(), 2048, PrimeCertaintyCalculator.getDefaultCertainty(2048));
+        engine.init(param);
+    }
+
+    public void initialize(
+        int strength,
+        SecureRandom random)
+    {
+        param = new RSAKeyGenerationParameters(defaultPublicExponent,
+            // Android-changed: Replace null random with default implementation.
+            // random, strength, PrimeCertaintyCalculator.getDefaultCertainty(strength));
+            (random != null) ? random : new SecureRandom(), strength, PrimeCertaintyCalculator.getDefaultCertainty(strength));
+
+        engine.init(param);
+    }
+
+    public void initialize(
+        AlgorithmParameterSpec params,
+        SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(params instanceof RSAKeyGenParameterSpec))
+        {
+            throw new InvalidAlgorithmParameterException("parameter object not a RSAKeyGenParameterSpec");
+        }
+        RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params;
+
+        param = new RSAKeyGenerationParameters(
+            rsaParams.getPublicExponent(),
+            // Android-changed: Replace null random with default implementation.
+            // random, rsaParams.getKeysize(), PrimeCertaintyCalculator.getDefaultCertainty(2048));
+            (random != null) ? random : new SecureRandom(), rsaParams.getKeysize(), PrimeCertaintyCalculator.getDefaultCertainty(2048));
+
+        engine.init(param);
+    }
+
+    public KeyPair generateKeyPair()
+    {
+        AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+        RSAKeyParameters pub = (RSAKeyParameters)pair.getPublic();
+        RSAPrivateCrtKeyParameters priv = (RSAPrivateCrtKeyParameters)pair.getPrivate();
+
+        return new KeyPair(new BCRSAPublicKey(pub),
+            new BCRSAPrivateCrtKey(priv));
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java
new file mode 100644
index 0000000..2b4b83d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java
@@ -0,0 +1,80 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.RSAKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import com.android.internal.org.bouncycastle.util.Fingerprint;
+
+/**
+ * utility class for converting java.security RSA objects into their
+ * org.bouncycastle.crypto counterparts.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class RSAUtil
+{
+    public static final ASN1ObjectIdentifier[] rsaOids =
+    {
+        PKCSObjectIdentifiers.rsaEncryption,
+        X509ObjectIdentifiers.id_ea_rsa,
+        PKCSObjectIdentifiers.id_RSAES_OAEP,
+        PKCSObjectIdentifiers.id_RSASSA_PSS
+    };
+
+    public static boolean isRsaOid(
+        ASN1ObjectIdentifier algOid)
+    {
+        for (int i = 0; i != rsaOids.length; i++)
+        {
+            if (algOid.equals(rsaOids[i]))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    static RSAKeyParameters generatePublicKeyParameter(
+        RSAPublicKey key)
+    {
+        return new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent());
+
+    }
+
+    static RSAKeyParameters generatePrivateKeyParameter(
+        RSAPrivateKey key)
+    {
+        if (key instanceof RSAPrivateCrtKey)
+        {
+            RSAPrivateCrtKey k = (RSAPrivateCrtKey)key;
+
+            return new RSAPrivateCrtKeyParameters(k.getModulus(),
+                k.getPublicExponent(), k.getPrivateExponent(),
+                k.getPrimeP(), k.getPrimeQ(), k.getPrimeExponentP(), k.getPrimeExponentQ(), k.getCrtCoefficient());
+        }
+        else
+        {
+            RSAPrivateKey k = key;
+
+            return new RSAKeyParameters(true, k.getModulus(), k.getPrivateExponent());
+        }
+    }
+
+    static String generateKeyFingerprint(BigInteger modulus)
+    {
+        return new Fingerprint(modulus.toByteArray()).toString();
+    }
+
+    static String generateExponentFingerprint(BigInteger exponent)
+    {
+        return new Fingerprint(exponent.toByteArray(), 32).toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
new file mode 100644
index 0000000..b89cd73
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
@@ -0,0 +1,355 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.DerivationFunction;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
+// import org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.DESParameters;
+import com.android.internal.org.bouncycastle.crypto.params.KDFParameters;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Integers;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class BaseAgreementSpi
+    extends KeyAgreementSpi
+{
+    private static final Map<String, ASN1ObjectIdentifier> defaultOids = new HashMap<String, ASN1ObjectIdentifier>();
+    private static final Map<String, Integer> keySizes = new HashMap<String, Integer>();
+    private static final Map<String, String> nameTable = new HashMap<String, String>();
+
+    private static final Hashtable oids = new Hashtable();
+    private static final Hashtable des = new Hashtable();
+
+    static
+    {
+        Integer i64 = Integers.valueOf(64);
+        Integer i128 = Integers.valueOf(128);
+        Integer i192 = Integers.valueOf(192);
+        Integer i256 = Integers.valueOf(256);
+
+        keySizes.put("DES", i64);
+        keySizes.put("DESEDE", i192);
+        keySizes.put("BLOWFISH", i128);
+        keySizes.put("AES", i256);
+
+        keySizes.put(NISTObjectIdentifiers.id_aes128_ECB.getId(), i128);
+        keySizes.put(NISTObjectIdentifiers.id_aes192_ECB.getId(), i192);
+        keySizes.put(NISTObjectIdentifiers.id_aes256_ECB.getId(), i256);
+        keySizes.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
+        keySizes.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
+        keySizes.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), i256);
+        keySizes.put(NISTObjectIdentifiers.id_aes128_CFB.getId(), i128);
+        keySizes.put(NISTObjectIdentifiers.id_aes192_CFB.getId(), i192);
+        keySizes.put(NISTObjectIdentifiers.id_aes256_CFB.getId(), i256);
+        keySizes.put(NISTObjectIdentifiers.id_aes128_OFB.getId(), i128);
+        keySizes.put(NISTObjectIdentifiers.id_aes192_OFB.getId(), i192);
+        keySizes.put(NISTObjectIdentifiers.id_aes256_OFB.getId(), i256);
+        keySizes.put(NISTObjectIdentifiers.id_aes128_wrap.getId(), i128);
+        keySizes.put(NISTObjectIdentifiers.id_aes192_wrap.getId(), i192);
+        keySizes.put(NISTObjectIdentifiers.id_aes256_wrap.getId(), i256);
+        keySizes.put(NISTObjectIdentifiers.id_aes128_CCM.getId(), i128);
+        keySizes.put(NISTObjectIdentifiers.id_aes192_CCM.getId(), i192);
+        keySizes.put(NISTObjectIdentifiers.id_aes256_CCM.getId(), i256);
+        keySizes.put(NISTObjectIdentifiers.id_aes128_GCM.getId(), i128);
+        keySizes.put(NISTObjectIdentifiers.id_aes192_GCM.getId(), i192);
+        keySizes.put(NISTObjectIdentifiers.id_aes256_GCM.getId(), i256);
+        keySizes.put(NTTObjectIdentifiers.id_camellia128_wrap.getId(), i128);
+        keySizes.put(NTTObjectIdentifiers.id_camellia192_wrap.getId(), i192);
+        keySizes.put(NTTObjectIdentifiers.id_camellia256_wrap.getId(), i256);
+        keySizes.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap.getId(), i128);
+
+        keySizes.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), i192);
+        keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), i192);
+        keySizes.put(OIWObjectIdentifiers.desCBC.getId(), i64);
+
+        // Android-removed: Unsupported algorithms
+        // keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb.getId(), i256);
+        // keySizes.put(CryptoProObjectIdentifiers.id_Gost28147_89_None_KeyWrap.getId(), i256);
+        // keySizes.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_KeyWrap.getId(), i256);
+
+        keySizes.put(PKCSObjectIdentifiers.id_hmacWithSHA1.getId(), Integers.valueOf(160));
+        keySizes.put(PKCSObjectIdentifiers.id_hmacWithSHA256.getId(), i256);
+        keySizes.put(PKCSObjectIdentifiers.id_hmacWithSHA384.getId(), Integers.valueOf(384));
+        keySizes.put(PKCSObjectIdentifiers.id_hmacWithSHA512.getId(), Integers.valueOf(512));
+
+        defaultOids.put("DESEDE", PKCSObjectIdentifiers.des_EDE3_CBC);
+        defaultOids.put("AES", NISTObjectIdentifiers.id_aes256_CBC);
+        defaultOids.put("CAMELLIA", NTTObjectIdentifiers.id_camellia256_cbc);
+        defaultOids.put("SEED", KISAObjectIdentifiers.id_seedCBC);
+        defaultOids.put("DES", OIWObjectIdentifiers.desCBC);
+
+        nameTable.put(MiscObjectIdentifiers.cast5CBC.getId(), "CAST5");
+        nameTable.put(MiscObjectIdentifiers.as_sys_sec_alg_ideaCBC.getId(), "IDEA");
+        nameTable.put(MiscObjectIdentifiers.cryptlib_algorithm_blowfish_ECB.getId(), "Blowfish");
+        nameTable.put(MiscObjectIdentifiers.cryptlib_algorithm_blowfish_CBC.getId(), "Blowfish");
+        nameTable.put(MiscObjectIdentifiers.cryptlib_algorithm_blowfish_CFB.getId(), "Blowfish");
+        nameTable.put(MiscObjectIdentifiers.cryptlib_algorithm_blowfish_OFB.getId(), "Blowfish");
+        nameTable.put(OIWObjectIdentifiers.desECB.getId(), "DES");
+        nameTable.put(OIWObjectIdentifiers.desCBC.getId(), "DES");
+        nameTable.put(OIWObjectIdentifiers.desCFB.getId(), "DES");
+        nameTable.put(OIWObjectIdentifiers.desOFB.getId(), "DES");
+        nameTable.put(OIWObjectIdentifiers.desEDE.getId(), "DESede");
+        nameTable.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), "DESede");
+        nameTable.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), "DESede");
+        nameTable.put(PKCSObjectIdentifiers.id_alg_CMSRC2wrap.getId(), "RC2");
+        nameTable.put(PKCSObjectIdentifiers.id_hmacWithSHA1.getId(), "HmacSHA1");
+        nameTable.put(PKCSObjectIdentifiers.id_hmacWithSHA224.getId(), "HmacSHA224");
+        nameTable.put(PKCSObjectIdentifiers.id_hmacWithSHA256.getId(), "HmacSHA256");
+        nameTable.put(PKCSObjectIdentifiers.id_hmacWithSHA384.getId(), "HmacSHA384");
+        nameTable.put(PKCSObjectIdentifiers.id_hmacWithSHA512.getId(), "HmacSHA512");
+        nameTable.put(NTTObjectIdentifiers.id_camellia128_cbc.getId(), "Camellia");
+        nameTable.put(NTTObjectIdentifiers.id_camellia192_cbc.getId(), "Camellia");
+        nameTable.put(NTTObjectIdentifiers.id_camellia256_cbc.getId(), "Camellia");
+        nameTable.put(NTTObjectIdentifiers.id_camellia128_wrap.getId(), "Camellia");
+        nameTable.put(NTTObjectIdentifiers.id_camellia192_wrap.getId(), "Camellia");
+        nameTable.put(NTTObjectIdentifiers.id_camellia256_wrap.getId(), "Camellia");
+        nameTable.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap.getId(), "SEED");
+        nameTable.put(KISAObjectIdentifiers.id_seedCBC.getId(), "SEED");
+        nameTable.put(KISAObjectIdentifiers.id_seedMAC.getId(), "SEED");
+        // Android-removed: Unsupported algorithm
+        // nameTable.put(CryptoProObjectIdentifiers.gostR28147_gcfb.getId(), "GOST28147");
+
+        nameTable.put(NISTObjectIdentifiers.id_aes128_wrap.getId(), "AES");
+        nameTable.put(NISTObjectIdentifiers.id_aes128_CCM.getId(), "AES");
+        nameTable.put(NISTObjectIdentifiers.id_aes128_CCM.getId(), "AES");
+
+        oids.put("DESEDE", PKCSObjectIdentifiers.des_EDE3_CBC);
+        oids.put("AES", NISTObjectIdentifiers.id_aes256_CBC);
+        oids.put("DES", OIWObjectIdentifiers.desCBC);
+
+        des.put("DES", "DES");
+        des.put("DESEDE", "DES");
+        des.put(OIWObjectIdentifiers.desCBC.getId(), "DES");
+        des.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), "DES");
+        des.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), "DES");
+    }
+
+    protected final String kaAlgorithm;
+    protected final DerivationFunction kdf;
+
+    protected byte[]     ukmParameters;
+
+    public BaseAgreementSpi(String kaAlgorithm, DerivationFunction kdf)
+    {
+        this.kaAlgorithm = kaAlgorithm;
+        this.kdf = kdf;
+    }
+
+    protected static String getAlgorithm(String algDetails)
+    {
+        if (algDetails.indexOf('[') > 0)
+        {
+            return algDetails.substring(0, algDetails.indexOf('['));
+        }
+
+        if (algDetails.startsWith(NISTObjectIdentifiers.aes.getId()))
+        {
+            return "AES";
+        }
+        // BEGIN Android-removed: Unsupported algorithm
+        // if (algDetails.startsWith(GNUObjectIdentifiers.Serpent.getId()))
+        // {
+        //     return "Serpent";
+        // }
+        // END Android-removed: Unsupported algorithms
+
+        String name = (String)nameTable.get(Strings.toUpperCase(algDetails));
+
+        if (name != null)
+        {
+            return name;
+        }
+
+        return algDetails;
+    }
+
+    protected static int getKeySize(String algDetails)
+    {
+        if (algDetails.indexOf('[') > 0)
+        {
+            return Integer.parseInt(algDetails.substring(algDetails.indexOf('[') + 1, algDetails.indexOf(']')));
+        }
+
+        String algKey = Strings.toUpperCase(algDetails);
+        if (!keySizes.containsKey(algKey))
+        {
+            return -1;
+        }
+
+        return ((Integer)keySizes.get(algKey)).intValue();
+    }
+
+    protected static byte[] trimZeroes(byte[] secret)
+    {
+        if (secret[0] != 0)
+        {
+            return secret;
+        }
+        else
+        {
+            int ind = 0;
+            while (ind < secret.length && secret[ind] == 0)
+            {
+                ind++;
+            }
+
+            byte[] rv = new byte[secret.length - ind];
+
+            System.arraycopy(secret, ind, rv, 0, rv.length);
+
+            return rv;
+        }
+    }
+
+    protected byte[] engineGenerateSecret()
+        throws IllegalStateException
+    {
+        if (kdf != null)
+        {
+            byte[] secret = calcSecret();
+            try
+            {
+                return getSharedSecretBytes(secret, null, secret.length * 8);
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new IllegalStateException(e.getMessage());
+            }
+        }
+
+        return calcSecret();
+    }
+
+    protected int engineGenerateSecret(
+        byte[]  sharedSecret,
+        int     offset)
+        throws IllegalStateException, ShortBufferException
+    {
+        byte[] secret = engineGenerateSecret();
+
+        if (sharedSecret.length - offset < secret.length)
+        {
+            throw new ShortBufferException(kaAlgorithm + " key agreement: need " + secret.length + " bytes");
+        }
+
+        System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+
+        return secret.length;
+    }
+
+    protected SecretKey engineGenerateSecret(
+        String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        String algKey = Strings.toUpperCase(algorithm);
+        String oidAlgorithm = algorithm;
+
+        if (oids.containsKey(algKey))
+        {
+            oidAlgorithm = ((ASN1ObjectIdentifier)oids.get(algKey)).getId();
+        }
+
+        int    keySize = getKeySize(oidAlgorithm);
+
+        byte[] secret = getSharedSecretBytes(calcSecret(), oidAlgorithm, keySize);
+
+        String algName = getAlgorithm(algorithm);
+
+        if (des.containsKey(algName))
+        {
+            DESParameters.setOddParity(secret);
+        }
+
+        return new SecretKeySpec(secret, algName);
+    }
+
+    private byte[] getSharedSecretBytes(byte[] secret, String oidAlgorithm, int keySize)
+        throws NoSuchAlgorithmException
+    {
+        if (kdf != null)
+        {
+            if (keySize < 0)
+            {
+                throw new NoSuchAlgorithmException("unknown algorithm encountered: " + oidAlgorithm);
+            }
+            byte[] keyBytes = new byte[keySize / 8];
+
+            // BEGIN Android-removed: Unsupported algorithm
+            /*
+            if (kdf instanceof DHKEKGenerator)
+            {
+                if (oidAlgorithm == null)
+                {
+                    throw new NoSuchAlgorithmException("algorithm OID is null");
+                }
+                ASN1ObjectIdentifier oid;
+                try
+                {
+                    oid = new ASN1ObjectIdentifier(oidAlgorithm);
+                }
+                catch (IllegalArgumentException e)
+                {
+                    throw new NoSuchAlgorithmException("no OID for algorithm: " + oidAlgorithm);
+                }
+                DHKDFParameters params = new DHKDFParameters(oid, keySize, secret, ukmParameters);
+
+                kdf.init(params);
+            }
+            else
+            */
+            // END Android-removed: Unsupported algorithm
+            {
+                KDFParameters params = new KDFParameters(secret, ukmParameters);
+
+                kdf.init(params);
+            }
+
+            kdf.generateBytes(keyBytes, 0, keyBytes.length);
+
+            Arrays.clear(secret);
+
+            return keyBytes;
+        }
+        else
+        {
+            if (keySize > 0)
+            {
+                byte[] keyBytes = new byte[keySize / 8];
+
+                System.arraycopy(secret, 0, keyBytes, 0, keyBytes.length);
+
+                Arrays.clear(secret);
+
+                return keyBytes;
+            }
+
+            return secret;
+        }
+    }
+
+    protected abstract byte[] calcSecret();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAlgorithmParameterGeneratorSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAlgorithmParameterGeneratorSpi.java
new file mode 100644
index 0000000..1f2e670
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.security.AlgorithmParameterGeneratorSpi;
+import java.security.AlgorithmParameters;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+import com.android.internal.org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class BaseAlgorithmParameterGeneratorSpi
+    extends AlgorithmParameterGeneratorSpi
+{
+    private final JcaJceHelper helper = new BCJcaJceHelper();
+
+    public BaseAlgorithmParameterGeneratorSpi()
+    {
+    }
+
+    protected final AlgorithmParameters createParametersInstance(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return helper.createAlgorithmParameters(algorithm);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
new file mode 100644
index 0000000..f9d0692
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
@@ -0,0 +1,258 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+// Android-removed: Unsupported algorithms
+// import javax.crypto.spec.RC2ParameterSpec;
+// import javax.crypto.spec.RC5ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.Wrapper;
+import com.android.internal.org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class BaseCipherSpi
+    extends CipherSpi
+{
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        IvParameterSpec.class,
+                                        PBEParameterSpec.class,
+                                        // Android-removed: Unsupported algorithms
+                                        // RC2ParameterSpec.class,
+                                        // RC5ParameterSpec.class
+                                    };
+
+    private final JcaJceHelper helper = new BCJcaJceHelper();
+
+    protected AlgorithmParameters     engineParams = null;
+
+    protected Wrapper                 wrapEngine = null;
+
+    private int                       ivSize;
+    private byte[]                    iv;
+
+    protected BaseCipherSpi()
+    {
+    }
+
+    protected int engineGetBlockSize()
+    {
+        return 0;
+    }
+
+    protected byte[] engineGetIV()
+    {
+        return null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key)
+    {
+        return key.getEncoded().length;
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen)
+    {
+        return -1;
+    }
+
+    protected AlgorithmParameters engineGetParameters()
+    {
+        return null;
+    }
+
+    protected final AlgorithmParameters createParametersInstance(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return helper.createAlgorithmParameters(algorithm);
+    }
+
+    protected void engineSetMode(
+        String  mode)
+        throws NoSuchAlgorithmException
+    {
+        throw new NoSuchAlgorithmException("can't support mode " + mode);
+    }
+
+    protected void engineSetPadding(
+        String  padding)
+    throws NoSuchPaddingException
+    {
+        throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+    }
+
+    protected byte[] engineWrap(
+        Key     key)
+    throws IllegalBlockSizeException, InvalidKeyException
+    {
+        byte[] encoded = key.getEncoded();
+        if (encoded == null)
+        {
+            throw new InvalidKeyException("Cannot wrap key, null encoding.");
+        }
+
+        try
+        {
+            if (wrapEngine == null)
+            {
+                return engineDoFinal(encoded, 0, encoded.length);
+            }
+            else
+            {
+                return wrapEngine.wrap(encoded, 0, encoded.length);
+            }
+        }
+        catch (BadPaddingException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+    }
+
+    protected Key engineUnwrap(
+        byte[]  wrappedKey,
+        String  wrappedKeyAlgorithm,
+        int     wrappedKeyType)
+    throws InvalidKeyException
+    {
+        byte[] encoded;
+        try
+        {
+            if (wrapEngine == null)
+            {
+                encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+            }
+            else
+            {
+                encoded = wrapEngine.unwrap(wrappedKey, 0, wrappedKey.length);
+            }
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+        catch (final BadPaddingException e)
+        {
+            throw new InvalidKeyException("unable to unwrap")
+            {
+                public synchronized Throwable getCause()
+                {
+                    return e;
+                }
+            };
+        }
+        catch (IllegalBlockSizeException e2)
+        {
+            throw new InvalidKeyException(e2.getMessage());
+        }
+
+        if (wrappedKeyType == Cipher.SECRET_KEY)
+        {
+            return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+        }
+        else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
+        {
+            /*
+                 * The caller doesn't know the algorithm as it is part of
+                 * the encrypted data.
+                 */
+            try
+            {
+                PrivateKeyInfo       in = PrivateKeyInfo.getInstance(encoded);
+
+                PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
+
+                if (privKey != null)
+                {
+                    return privKey;
+                }
+                else
+                {
+                    throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
+                }
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeyException("Invalid key encoding.");
+            }
+        }
+        else
+        {
+            try
+            {
+                KeyFactory kf = helper.createKeyFactory(wrappedKeyAlgorithm);
+
+                if (wrappedKeyType == Cipher.PUBLIC_KEY)
+                {
+                    return kf.generatePublic(new X509EncodedKeySpec(encoded));
+                }
+                else if (wrappedKeyType == Cipher.PRIVATE_KEY)
+                {
+                    return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+                }
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new InvalidKeyException("Unknown key type " + e.getMessage());
+            }
+            catch (InvalidKeySpecException e)
+            {
+                throw new InvalidKeyException("Unknown key type " + e.getMessage());
+            }
+            catch (NoSuchProviderException e)
+            {
+                throw new InvalidKeyException("Unknown key type " + e.getMessage());
+            }
+
+            throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+        }
+    }
+
+    protected static final class ErasableOutputStream
+        extends ByteArrayOutputStream
+    {
+        public ErasableOutputStream()
+        {
+        }
+
+        public byte[] getBuf()
+        {
+            return buf;
+        }
+
+        public void erase()
+        {
+            Arrays.fill(this.buf, (byte)0);
+            reset();
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
new file mode 100644
index 0000000..3bebeb5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
@@ -0,0 +1,81 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class BaseKeyFactorySpi
+    extends java.security.KeyFactorySpi
+    implements AsymmetricKeyInfoConverter
+{
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof PKCS8EncodedKeySpec)
+        {
+            try
+            {
+                return generatePrivate(PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeySpecException("encoded key spec not recognized: " + e.getMessage());
+            }
+        }
+        else
+        {
+            throw new InvalidKeySpecException("key spec not recognized");
+        }
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof X509EncodedKeySpec)
+        {
+            try
+            {
+                return generatePublic(SubjectPublicKeyInfo.getInstance(((X509EncodedKeySpec)keySpec).getEncoded()));
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeySpecException("encoded key spec not recognized: " + e.getMessage());
+            }
+        }
+        else
+        {
+            throw new InvalidKeySpecException("key spec not recognized");
+        }
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key key,
+        Class spec)
+        throws InvalidKeySpecException
+    {
+        if (spec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
+        {
+            return new PKCS8EncodedKeySpec(key.getEncoded());
+        }
+        else if (spec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
+        {
+            return new X509EncodedKeySpec(key.getEncoded());
+        }
+
+        throw new InvalidKeySpecException("not implemented yet " + key + " " + spec);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java
new file mode 100644
index 0000000..d6e9994
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java
@@ -0,0 +1,57 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import com.android.internal.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.dh.BCDHPublicKey;
+
+/**
+ * utility class for converting jce/jca DH objects
+ * objects into their org.bouncycastle.crypto counterparts.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHUtil
+{
+    static public AsymmetricKeyParameter generatePublicKeyParameter(
+        PublicKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof BCDHPublicKey)
+        {
+            return ((BCDHPublicKey)key).engineGetKeyParameters();
+        }
+        if (key instanceof DHPublicKey)
+        {
+            DHPublicKey    k = (DHPublicKey)key;
+
+            return new DHPublicKeyParameters(k.getY(),
+                new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+        }
+
+        throw new InvalidKeyException("can't identify DH public key.");
+    }
+
+    static public AsymmetricKeyParameter generatePrivateKeyParameter(
+        PrivateKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DHPrivateKey)
+        {
+            DHPrivateKey    k = (DHPrivateKey)key;
+
+            return new DHPrivateKeyParameters(k.getX(),
+                new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+        }
+                        
+        throw new InvalidKeyException("can't identify DH private key.");
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java
new file mode 100644
index 0000000..a3ca457
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java
@@ -0,0 +1,114 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.math.BigInteger;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.spec.AlgorithmParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.DSAExt;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.signers.DSAEncoding;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class DSABase
+    extends SignatureSpi
+    implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+    protected Digest        digest;
+    protected DSAExt        signer;
+    protected DSAEncoding   encoding;
+
+    protected DSABase(
+        Digest                  digest,
+        DSAExt                  signer,
+        DSAEncoding             encoding)
+    {
+        this.digest = digest;
+        this.signer = signer;
+        this.encoding = encoding;
+    }
+
+    protected void engineUpdate(
+        byte    b)
+        throws SignatureException
+    {
+        digest.update(b);
+    }
+
+    protected void engineUpdate(
+        byte[]  b,
+        int     off,
+        int     len) 
+        throws SignatureException
+    {
+        digest.update(b, off, len);
+    }
+
+    protected byte[] engineSign()
+        throws SignatureException
+    {
+        byte[] hash = new byte[digest.getDigestSize()];
+        digest.doFinal(hash, 0);
+
+        try
+        {
+            BigInteger[] sig = signer.generateSignature(hash);
+
+            return encoding.encode(signer.getOrder(), sig[0], sig[1]);
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException(e.toString());
+        }
+    }
+
+    protected boolean engineVerify(
+        byte[]  sigBytes) 
+        throws SignatureException
+    {
+        byte[] hash = new byte[digest.getDigestSize()];
+        digest.doFinal(hash, 0);
+
+        BigInteger[] sig;
+        try
+        {
+            sig = encoding.decode(signer.getOrder(), sigBytes);
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException("error decoding signature bytes.");
+        }
+
+        return signer.verifySignature(hash, sig[0], sig[1]);
+    }
+
+    protected void engineSetParameter(
+        AlgorithmParameterSpec params)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated replaced with "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)"
+     */
+    protected void engineSetParameter(
+        String  param,
+        Object  value)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated
+     */
+    protected Object engineGetParameter(
+        String      param)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java
new file mode 100644
index 0000000..a1d4040
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java
@@ -0,0 +1,18 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+/**
+ * @deprecated No longer used
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface DSAEncoder
+{
+    byte[] encode(BigInteger r, BigInteger s)
+        throws IOException;
+
+    BigInteger[] decode(byte[] sig)
+        throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java
new file mode 100644
index 0000000..1031b7a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java
@@ -0,0 +1,342 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.math.BigInteger;
+import java.security.spec.ECField;
+import java.security.spec.ECFieldF2m;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import com.android.internal.org.bouncycastle.asn1.x9.X962Parameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.crypto.ec.CustomNamedCurves;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+import com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import com.android.internal.org.bouncycastle.math.ec.ECAlgorithms;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.field.FiniteField;
+import com.android.internal.org.bouncycastle.math.field.Polynomial;
+import com.android.internal.org.bouncycastle.math.field.PolynomialExtensionField;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class EC5Util
+{
+    private static Map customCurves = new HashMap();
+
+    static
+    {
+        Enumeration e = CustomNamedCurves.getNames();
+        while (e.hasMoreElements())
+        {
+            String name = (String)e.nextElement();
+
+            X9ECParameters curveParams = ECNamedCurveTable.getByName(name);
+            if (curveParams != null)  // there may not be a regular curve, may just be a custom curve.
+            {
+                customCurves.put(curveParams.getCurve(), CustomNamedCurves.getByName(name).getCurve());
+            }
+        }
+
+        // BEGIN Android-removed: Unsupported curves
+        /*
+        X9ECParameters x9_25519 = CustomNamedCurves.getByName("Curve25519");
+        ECCurve c_25519 = x9_25519.getCurve();
+
+        customCurves.put(new ECCurve.Fp(
+            c_25519.getField().getCharacteristic(),
+            c_25519.getA().toBigInteger(),
+            c_25519.getB().toBigInteger(),
+            c_25519.getOrder(),
+            c_25519.getCofactor()
+            ), c_25519);
+        */
+        // END Android-removed: Unsupported curves
+    }
+
+    public static ECCurve getCurve(
+        ProviderConfiguration configuration,
+        X962Parameters params)
+    {
+        ECCurve curve;
+        Set acceptableCurves = configuration.getAcceptableNamedCurves();
+
+        if (params.isNamedCurve())
+        {
+            ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+
+            if (acceptableCurves.isEmpty() || acceptableCurves.contains(oid))
+            {
+                X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+                if (ecP == null)
+                {
+                    ecP = (X9ECParameters)configuration.getAdditionalECParameters().get(oid);
+                }
+
+                curve = ecP.getCurve();
+            }
+            else
+            {
+                throw new IllegalStateException("named curve not acceptable");
+            }
+        }
+        else if (params.isImplicitlyCA())
+        {
+            curve = configuration.getEcImplicitlyCa().getCurve();
+        }
+        else if (acceptableCurves.isEmpty())
+        {
+            X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+
+            curve = ecP.getCurve();
+        }
+        else
+        {
+            throw new IllegalStateException("encoded parameters not acceptable");
+        }
+
+        return curve;
+    }
+
+    public static ECDomainParameters getDomainParameters(
+        ProviderConfiguration configuration,
+        java.security.spec.ECParameterSpec params)
+    {
+        ECDomainParameters domainParameters;
+
+        if (params == null)
+        {
+            com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa();
+
+            domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed());
+        }
+        else
+        {
+            domainParameters = ECUtil.getDomainParameters(configuration, convertSpec(params, false));
+        }
+
+        return domainParameters;
+    }
+
+    public static ECParameterSpec convertToSpec(
+        X962Parameters params, ECCurve curve)
+    {
+        ECParameterSpec ecSpec;
+        EllipticCurve ellipticCurve;
+
+        if (params.isNamedCurve())
+        {
+            ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+            X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+            if (ecP == null)
+            {
+                Map additionalECParameters = BouncyCastleProvider.CONFIGURATION.getAdditionalECParameters();
+                if (!additionalECParameters.isEmpty())
+                {
+                    ecP = (X9ECParameters)additionalECParameters.get(oid);
+                }
+            }
+
+            ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+            ecSpec = new ECNamedCurveSpec(
+                ECUtil.getCurveName(oid),
+                ellipticCurve,
+                convertPoint(ecP.getG()),
+                ecP.getN(),
+                ecP.getH());
+        }
+        else if (params.isImplicitlyCA())
+        {
+            ecSpec = null;
+        }
+        else
+        {
+            X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+
+            ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+            if (ecP.getH() != null)
+            {
+                ecSpec = new ECParameterSpec(
+                    ellipticCurve,
+                    convertPoint(ecP.getG()),
+                    ecP.getN(),
+                    ecP.getH().intValue());
+            }
+            else
+            {
+                ecSpec = new ECParameterSpec(
+                    ellipticCurve,
+                    convertPoint(ecP.getG()),
+                    ecP.getN(),
+                    1);      // TODO: not strictly correct... need to fix the test data...
+            }
+        }
+
+        return ecSpec;
+    }
+
+    public static ECParameterSpec convertToSpec(
+        X9ECParameters domainParameters)
+    {
+        return new ECParameterSpec(
+            convertCurve(domainParameters.getCurve(), null),  // JDK 1.5 has trouble with this if it's not null...
+            EC5Util.convertPoint(domainParameters.getG()),
+            domainParameters.getN(),
+            domainParameters.getH().intValue());
+    }
+
+    public static ECParameterSpec convertToSpec(
+        ECDomainParameters domainParameters)
+    {
+        return new ECParameterSpec(
+            convertCurve(domainParameters.getCurve(), null),  // JDK 1.5 has trouble with this if it's not null...
+            EC5Util.convertPoint(domainParameters.getG()),
+            domainParameters.getN(),
+            domainParameters.getH().intValue());
+    }
+
+    public static EllipticCurve convertCurve(
+        ECCurve curve, 
+        byte[]  seed)
+    {
+        ECField field = convertField(curve.getField());
+        BigInteger a = curve.getA().toBigInteger(), b = curve.getB().toBigInteger();
+
+        // TODO: the Sun EC implementation doesn't currently handle the seed properly
+        // so at the moment it's set to null. Should probably look at making this configurable
+        return new EllipticCurve(field, a, b, null);
+    }
+
+    public static ECCurve convertCurve(
+        EllipticCurve ec)
+    {
+        ECField field = ec.getField();
+        BigInteger a = ec.getA();
+        BigInteger b = ec.getB();
+
+        if (field instanceof ECFieldFp)
+        {
+            ECCurve.Fp curve = new ECCurve.Fp(((ECFieldFp)field).getP(), a, b);
+
+            if (customCurves.containsKey(curve))
+            {
+                return (ECCurve)customCurves.get(curve);
+            }
+
+            return curve;
+        }
+        else
+        {
+            ECFieldF2m fieldF2m = (ECFieldF2m)field;
+            int m = fieldF2m.getM();
+            int ks[] = ECUtil.convertMidTerms(fieldF2m.getMidTermsOfReductionPolynomial());
+            return new ECCurve.F2m(m, ks[0], ks[1], ks[2], a, b); 
+        }
+    }
+
+    public static ECField convertField(FiniteField field)
+    {
+        if (ECAlgorithms.isFpField(field))
+        {
+            return new ECFieldFp(field.getCharacteristic());
+        }
+        else //if (ECAlgorithms.isF2mField(curveField))
+        {
+            Polynomial poly = ((PolynomialExtensionField)field).getMinimalPolynomial();
+            int[] exponents = poly.getExponentsPresent();
+            int[] ks = Arrays.reverse(Arrays.copyOfRange(exponents, 1, exponents.length - 1));
+            return new ECFieldF2m(poly.getDegree(), ks);
+        }
+    }
+
+    public static ECParameterSpec convertSpec(
+        EllipticCurve ellipticCurve,
+        com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec spec)
+    {
+        if (spec instanceof ECNamedCurveParameterSpec)
+        {
+            return new ECNamedCurveSpec(
+                ((ECNamedCurveParameterSpec)spec).getName(),
+                ellipticCurve,
+                convertPoint(spec.getG()),
+                spec.getN(),
+                spec.getH());
+        }
+        else
+        {
+            return new ECParameterSpec(
+                ellipticCurve,
+                convertPoint(spec.getG()),
+                spec.getN(),
+                spec.getH().intValue());
+        }
+    }
+
+    public static com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec convertSpec(
+        ECParameterSpec ecSpec,
+        boolean withCompression)
+    {
+        ECCurve curve = convertCurve(ecSpec.getCurve());
+
+        if (ecSpec instanceof ECNamedCurveSpec)
+        {
+            return new com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec(
+                ((ECNamedCurveSpec)ecSpec).getName(),
+                curve,
+                convertPoint(curve, ecSpec.getGenerator(), withCompression),
+                ecSpec.getOrder(),
+                BigInteger.valueOf(ecSpec.getCofactor()),
+                ecSpec.getCurve().getSeed());
+        }
+        else
+        {
+            return new com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec(
+                curve,
+                convertPoint(curve, ecSpec.getGenerator(), withCompression),
+                ecSpec.getOrder(),
+                BigInteger.valueOf(ecSpec.getCofactor()),
+                ecSpec.getCurve().getSeed());
+        }
+    }
+
+    public static com.android.internal.org.bouncycastle.math.ec.ECPoint convertPoint(
+        ECParameterSpec ecSpec,
+        ECPoint point,
+        boolean withCompression)
+    {
+        return convertPoint(convertCurve(ecSpec.getCurve()), point, withCompression);
+    }
+
+    public static com.android.internal.org.bouncycastle.math.ec.ECPoint convertPoint(
+        ECCurve curve,
+        ECPoint point,
+        boolean withCompression)
+    {
+        return curve.createPoint(point.getAffineX(), point.getAffineY());
+    }
+
+    public static ECPoint convertPoint(com.android.internal.org.bouncycastle.math.ec.ECPoint point)
+    {
+        point = point.normalize();
+
+        return new ECPoint(
+            point.getAffineXCoord().toBigInteger(),
+            point.getAffineYCoord().toBigInteger());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java
new file mode 100644
index 0000000..12ce967
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java
@@ -0,0 +1,429 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Enumeration;
+import java.util.Map;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import com.android.internal.org.bouncycastle.asn1.x9.X962Parameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.crypto.ec.CustomNamedCurves;
+import com.android.internal.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECNamedDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import com.android.internal.org.bouncycastle.jce.interfaces.ECPrivateKey;
+import com.android.internal.org.bouncycastle.jce.interfaces.ECPublicKey;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+import com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Fingerprint;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * utility class for converting jce/jca ECDSA, ECDH, and ECDHC
+ * objects into their org.bouncycastle.crypto counterparts.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECUtil
+{
+    /**
+     * Returns a sorted array of middle terms of the reduction polynomial.
+     * @param k The unsorted array of middle terms of the reduction polynomial
+     * of length 1 or 3.
+     * @return the sorted array of middle terms of the reduction polynomial.
+     * This array always has length 3.
+     */
+    static int[] convertMidTerms(
+        int[] k)
+    {
+        int[] res = new int[3];
+        
+        if (k.length == 1)
+        {
+            res[0] = k[0];
+        }
+        else
+        {
+            if (k.length != 3)
+            {
+                throw new IllegalArgumentException("Only Trinomials and pentanomials supported");
+            }
+
+            if (k[0] < k[1] && k[0] < k[2])
+            {
+                res[0] = k[0];
+                if (k[1] < k[2])
+                {
+                    res[1] = k[1];
+                    res[2] = k[2];
+                }
+                else
+                {
+                    res[1] = k[2];
+                    res[2] = k[1];
+                }
+            }
+            else if (k[1] < k[2])
+            {
+                res[0] = k[1];
+                if (k[0] < k[2])
+                {
+                    res[1] = k[0];
+                    res[2] = k[2];
+                }
+                else
+                {
+                    res[1] = k[2];
+                    res[2] = k[0];
+                }
+            }
+            else
+            {
+                res[0] = k[2];
+                if (k[0] < k[1])
+                {
+                    res[1] = k[0];
+                    res[2] = k[1];
+                }
+                else
+                {
+                    res[1] = k[1];
+                    res[2] = k[0];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static ECDomainParameters getDomainParameters(
+        ProviderConfiguration configuration,
+        com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec params)
+    {
+        ECDomainParameters domainParameters;
+
+        if (params instanceof ECNamedCurveParameterSpec)
+        {
+            ECNamedCurveParameterSpec nParams = (ECNamedCurveParameterSpec)params;
+            ASN1ObjectIdentifier nameOid = ECUtil.getNamedCurveOid(nParams.getName());
+
+            domainParameters = new ECNamedDomainParameters(nameOid, nParams.getCurve(), nParams.getG(), nParams.getN(), nParams.getH(), nParams.getSeed());
+        }
+        else if (params == null)
+        {
+            com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa();
+
+            domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed());
+        }
+        else
+        {
+            domainParameters = new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH(), params.getSeed());
+        }
+
+        return domainParameters;
+    }
+
+    public static ECDomainParameters getDomainParameters(
+        ProviderConfiguration configuration,
+        X962Parameters params)
+    {
+        ECDomainParameters domainParameters;
+
+        if (params.isNamedCurve())
+        {
+            ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+            X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+            if (ecP == null)
+            {
+                Map extraCurves = configuration.getAdditionalECParameters();
+
+                ecP = (X9ECParameters)extraCurves.get(oid);
+            }
+            domainParameters = new ECNamedDomainParameters(oid, ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed());
+        }
+        else if (params.isImplicitlyCA())
+        {
+            com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa();
+
+            domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed());
+        }
+        else
+        {
+            X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+
+            domainParameters = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed());
+        }
+
+        return domainParameters;
+    }
+
+    public static AsymmetricKeyParameter generatePublicKeyParameter(
+        PublicKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof ECPublicKey)
+        {
+            ECPublicKey    k = (ECPublicKey)key;
+            ECParameterSpec s = k.getParameters();
+
+            return new ECPublicKeyParameters(
+                            k.getQ(),
+                            new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+        }
+        else if (key instanceof java.security.interfaces.ECPublicKey)
+        {
+            java.security.interfaces.ECPublicKey pubKey = (java.security.interfaces.ECPublicKey)key;
+            ECParameterSpec s = EC5Util.convertSpec(pubKey.getParams(), false);
+            return new ECPublicKeyParameters(
+                EC5Util.convertPoint(pubKey.getParams(), pubKey.getW(), false),
+                            new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+        }
+        else
+        {
+            // see if we can build a key from key.getEncoded()
+            try
+            {
+                byte[] bytes = key.getEncoded();
+
+                if (bytes == null)
+                {
+                    throw new InvalidKeyException("no encoding for EC public key");
+                }
+
+                PublicKey publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+                if (publicKey instanceof java.security.interfaces.ECPublicKey)
+                {
+                    return ECUtil.generatePublicKeyParameter(publicKey);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeyException("cannot identify EC public key: " + e.toString());
+            }
+        }
+
+        throw new InvalidKeyException("cannot identify EC public key.");
+    }
+
+    public static AsymmetricKeyParameter generatePrivateKeyParameter(
+        PrivateKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof ECPrivateKey)
+        {
+            ECPrivateKey  k = (ECPrivateKey)key;
+            ECParameterSpec s = k.getParameters();
+
+            if (s == null)
+            {
+                s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+            }
+
+            if (k.getParameters() instanceof ECNamedCurveParameterSpec)
+            {
+                String name = ((ECNamedCurveParameterSpec)k.getParameters()).getName();
+                return new ECPrivateKeyParameters(
+                    k.getD(),
+                    new ECNamedDomainParameters(ECNamedCurveTable.getOID(name),
+                        s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+            }
+            else
+            {
+                return new ECPrivateKeyParameters(
+                    k.getD(),
+                    new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+            }
+        }
+        else if (key instanceof java.security.interfaces.ECPrivateKey)
+        {
+            java.security.interfaces.ECPrivateKey privKey = (java.security.interfaces.ECPrivateKey)key;
+            ECParameterSpec s = EC5Util.convertSpec(privKey.getParams(), false);
+            return new ECPrivateKeyParameters(
+                            privKey.getS(),
+                            new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+        }
+        else
+        {
+            // see if we can build a key from key.getEncoded()
+            try
+            {
+                byte[] bytes = key.getEncoded();
+
+                if (bytes == null)
+                {
+                    throw new InvalidKeyException("no encoding for EC private key");
+                }
+
+                PrivateKey privateKey = BouncyCastleProvider.getPrivateKey(PrivateKeyInfo.getInstance(bytes));
+
+                if (privateKey instanceof java.security.interfaces.ECPrivateKey)
+                {
+                    return ECUtil.generatePrivateKeyParameter(privateKey);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeyException("cannot identify EC private key: " + e.toString());
+            }
+        }
+
+        throw new InvalidKeyException("can't identify EC private key.");
+    }
+
+    public static int getOrderBitLength(ProviderConfiguration configuration, BigInteger order, BigInteger privateValue)
+    {
+        if (order == null)     // implicitly CA
+        {
+            ECParameterSpec implicitCA = configuration.getEcImplicitlyCa();
+
+            if (implicitCA == null)
+            {
+                return privateValue.bitLength();   // a guess but better than an exception!
+            }
+
+            return implicitCA.getN().bitLength();
+        }
+        else
+        {
+            return order.bitLength();
+        }
+    }
+
+    public static ASN1ObjectIdentifier getNamedCurveOid(
+        String curveName)
+    {
+        String name = curveName;
+
+        int spacePos = name.indexOf(' ');
+        if (spacePos > 0)
+        {
+            name = name.substring(spacePos + 1);
+        }
+
+        try
+        {
+            if (name.charAt(0) >= '0' && name.charAt(0) <= '2')
+            {
+                return new ASN1ObjectIdentifier(name);
+            }
+        }
+        catch (IllegalArgumentException ex)
+        {
+        }
+
+        return ECNamedCurveTable.getOID(name);
+    }
+
+    public static ASN1ObjectIdentifier getNamedCurveOid(
+        ECParameterSpec ecParameterSpec)
+    {
+        for (Enumeration names = ECNamedCurveTable.getNames(); names.hasMoreElements();)
+        {
+            String name = (String)names.nextElement();
+
+            X9ECParameters params = ECNamedCurveTable.getByName(name);
+
+            if (params.getN().equals(ecParameterSpec.getN())
+                && params.getH().equals(ecParameterSpec.getH())
+                && params.getCurve().equals(ecParameterSpec.getCurve())
+                && params.getG().equals(ecParameterSpec.getG()))
+            {
+                return com.android.internal.org.bouncycastle.asn1.x9.ECNamedCurveTable.getOID(name);
+            }
+        }
+
+        return null;
+    }
+
+    public static X9ECParameters getNamedCurveByOid(
+        ASN1ObjectIdentifier oid)
+    {
+        X9ECParameters params = CustomNamedCurves.getByOID(oid);
+
+        if (params == null)
+        {
+            params = ECNamedCurveTable.getByOID(oid);
+        }
+
+        return params;
+    }
+
+    public static X9ECParameters getNamedCurveByName(
+        String curveName)
+    {
+        X9ECParameters params = CustomNamedCurves.getByName(curveName);
+
+        if (params == null)
+        {
+            params = ECNamedCurveTable.getByName(curveName);
+        }
+
+        return params;
+    }
+
+    public static String getCurveName(
+        ASN1ObjectIdentifier oid)
+    {
+        return ECNamedCurveTable.getName(oid);
+    }
+
+    public static String privateKeyToString(String algorithm, BigInteger d, com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec spec)
+    {
+        StringBuffer buf = new StringBuffer();
+        String nl = Strings.lineSeparator();
+
+        com.android.internal.org.bouncycastle.math.ec.ECPoint q = calculateQ(d, spec);
+
+        buf.append(algorithm);
+        buf.append(" Private Key [").append(ECUtil.generateKeyFingerprint(q, spec)).append("]").append(nl);
+        buf.append("            X: ").append(q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
+        buf.append("            Y: ").append(q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
+
+        return buf.toString();
+    }
+
+    private static com.android.internal.org.bouncycastle.math.ec.ECPoint calculateQ(BigInteger d, com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec spec)
+    {
+        return spec.getG().multiply(d).normalize();
+    }
+
+    public static String publicKeyToString(String algorithm, com.android.internal.org.bouncycastle.math.ec.ECPoint q, com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec spec)
+    {
+        StringBuffer buf = new StringBuffer();
+        String nl = Strings.lineSeparator();
+
+        buf.append(algorithm);
+        buf.append(" Public Key [").append(ECUtil.generateKeyFingerprint(q, spec)).append("]").append(nl);
+        buf.append("            X: ").append(q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
+        buf.append("            Y: ").append(q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
+
+        return buf.toString();
+    }
+
+    public static String generateKeyFingerprint(ECPoint publicPoint, com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec spec)
+    {
+        ECCurve curve = spec.getCurve();
+        ECPoint g = spec.getG();
+
+        if (curve != null)
+        {
+            return new Fingerprint(Arrays.concatenate(publicPoint.getEncoded(false), curve.getA().getEncoded(), curve.getB().getEncoded(), g.getEncoded(false))).toString();
+        }
+
+        return new Fingerprint(publicPoint.getEncoded(false)).toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java
new file mode 100644
index 0000000..7461e6c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java
@@ -0,0 +1,25 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.security.spec.InvalidKeySpecException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ExtendedInvalidKeySpecException
+    extends InvalidKeySpecException
+{
+    private Throwable cause;
+
+    public ExtendedInvalidKeySpecException(String msg, Throwable cause)
+    {
+        super(msg);
+
+        this.cause = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/KeyUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/KeyUtil.java
new file mode 100644
index 0000000..f4d56bb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/KeyUtil.java
@@ -0,0 +1,76 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyUtil
+{
+    public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, ASN1Encodable keyData)
+    {
+        try
+        {
+            return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, byte[] keyData)
+    {
+        try
+        {
+            return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    public static byte[] getEncodedSubjectPublicKeyInfo(SubjectPublicKeyInfo info)
+    {
+         try
+         {
+             return info.getEncoded(ASN1Encoding.DER);
+         }
+         catch (Exception e)
+         {
+             return null;
+         }
+    }
+
+    public static byte[] getEncodedPrivateKeyInfo(AlgorithmIdentifier algId, ASN1Encodable privKey)
+    {
+         try
+         {
+             PrivateKeyInfo info = new PrivateKeyInfo(algId, privKey.toASN1Primitive());
+
+             return getEncodedPrivateKeyInfo(info);
+         }
+         catch (Exception e)
+         {
+             return null;
+         }
+    }
+
+    public static byte[] getEncodedPrivateKeyInfo(PrivateKeyInfo info)
+    {
+         try
+         {
+             return info.getEncoded(ASN1Encoding.DER);
+         }
+         catch (Exception e)
+         {
+             return null;
+         }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
new file mode 100644
index 0000000..e57c6f8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
@@ -0,0 +1,128 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OutputStream;
+import com.android.internal.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS12BagAttributeCarrierImpl
+    implements PKCS12BagAttributeCarrier
+{
+    private Hashtable pkcs12Attributes;
+    private Vector pkcs12Ordering;
+
+    PKCS12BagAttributeCarrierImpl(Hashtable attributes, Vector ordering)
+    {
+        this.pkcs12Attributes = attributes;
+        this.pkcs12Ordering = ordering;
+    }
+
+    public PKCS12BagAttributeCarrierImpl()
+    {
+        this(new Hashtable(), new Vector());
+    }
+
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable        attribute)
+    {
+        if (pkcs12Attributes.containsKey(oid))
+        {                           // preserve original ordering
+            pkcs12Attributes.put(oid, attribute);
+        }
+        else
+        {
+            pkcs12Attributes.put(oid, attribute);
+            pkcs12Ordering.addElement(oid);
+        }
+    }
+
+    public ASN1Encodable getBagAttribute(
+        ASN1ObjectIdentifier oid)
+    {
+        return (ASN1Encodable)pkcs12Attributes.get(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return pkcs12Ordering.elements();
+    }
+
+    int size()
+    {
+        return pkcs12Ordering.size();
+    }
+
+    Hashtable getAttributes()
+    {
+        return pkcs12Attributes;
+    }
+
+    Vector getOrdering()
+    {
+        return pkcs12Ordering;
+    }
+
+    public void writeObject(ObjectOutputStream out)
+        throws IOException
+    {
+        if (pkcs12Ordering.size() == 0)
+        {
+            out.writeObject(new Hashtable());
+            out.writeObject(new Vector());
+        }
+        else
+        {
+            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+            ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+            Enumeration             e = this.getBagAttributeKeys();
+
+            while (e.hasMoreElements())
+            {
+                ASN1ObjectIdentifier    oid = (ASN1ObjectIdentifier)e.nextElement();
+
+                aOut.writeObject(oid);
+                aOut.writeObject((ASN1Encodable)pkcs12Attributes.get(oid));
+            }
+
+            out.writeObject(bOut.toByteArray());
+        }
+    }
+
+    public void readObject(ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        Object obj = in.readObject();
+
+        if (obj instanceof Hashtable)
+        {
+            this.pkcs12Attributes = (Hashtable)obj;
+            this.pkcs12Ordering = (Vector)in.readObject();
+        }
+        else
+        {
+            ASN1InputStream aIn = new ASN1InputStream((byte[])obj);
+
+            ASN1ObjectIdentifier    oid;
+
+            while ((oid = (ASN1ObjectIdentifier)aIn.readObject()) != null)
+            {
+                this.setBagAttribute(oid, aIn.readObject());
+            }
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/PrimeCertaintyCalculator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/PrimeCertaintyCalculator.java
new file mode 100644
index 0000000..16d6c8c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/util/PrimeCertaintyCalculator.java
@@ -0,0 +1,25 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PrimeCertaintyCalculator
+{
+    private PrimeCertaintyCalculator()
+    {
+
+    }
+
+    /**
+     * Return the current wisdom on prime certainty requirements.
+     *
+     * @param keySizeInBits size of the key being generated.
+     * @return a certainty value.
+     */
+    public static int getDefaultCertainty(int keySizeInBits)
+    {
+        // Based on FIPS 186-4 Table C.1
+        return keySizeInBits <= 1024 ? 80 : (96 + 16 * ((keySizeInBits - 1) / 1024));
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
new file mode 100644
index 0000000..1de0527
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
@@ -0,0 +1,460 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+// Android-added: Use PushbackInputStream
+import java.io.PushbackInputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.SignedData;
+import com.android.internal.org.bouncycastle.asn1.x509.Certificate;
+import com.android.internal.org.bouncycastle.asn1.x509.CertificateList;
+import com.android.internal.org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.util.io.Streams;
+
+/**
+ * class for dealing with X509 certificates.
+ * <p>
+ * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
+ * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
+ * objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CertificateFactory
+    extends CertificateFactorySpi
+{
+    private final JcaJceHelper bcHelper = new BCJcaJceHelper();
+
+    private static final PEMUtil PEM_CERT_PARSER = new PEMUtil("CERTIFICATE");
+    private static final PEMUtil PEM_CRL_PARSER = new PEMUtil("CRL");
+    private static final PEMUtil PEM_PKCS7_PARSER = new PEMUtil("PKCS7");
+
+    private ASN1Set sData = null;
+    private int                sDataObjectCount = 0;
+    private InputStream currentStream = null;
+    
+    private ASN1Set sCrlData = null;
+    private int                sCrlDataObjectCount = 0;
+    private InputStream currentCrlStream = null;
+
+    private java.security.cert.Certificate readDERCertificate(
+        ASN1InputStream dIn)
+        throws IOException, CertificateParsingException
+    {
+        return getCertificate(ASN1Sequence.getInstance(dIn.readObject()));
+    }
+
+    private java.security.cert.Certificate readPEMCertificate(
+        InputStream in)
+        throws IOException, CertificateParsingException
+    {
+        return getCertificate(PEM_CERT_PARSER.readPEMObject(in));
+    }
+
+    private java.security.cert.Certificate getCertificate(ASN1Sequence seq)
+        throws CertificateParsingException
+    {
+        if (seq == null)
+        {
+            return null;
+        }
+        
+        if (seq.size() > 1
+                && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+        {
+            if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+            {
+                sData = SignedData.getInstance(ASN1Sequence.getInstance(
+                    (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates();
+
+                return getCertificate();
+            }
+        }
+
+        return new X509CertificateObject(bcHelper,
+                            Certificate.getInstance(seq));
+    }
+
+    private java.security.cert.Certificate getCertificate()
+        throws CertificateParsingException
+    {
+        if (sData != null)
+        {
+            while (sDataObjectCount < sData.size())
+            {
+                Object obj = sData.getObjectAt(sDataObjectCount++);
+
+                if (obj instanceof ASN1Sequence)
+                {
+                   return new X509CertificateObject(bcHelper,
+                                    Certificate.getInstance(obj));
+                }
+            }
+        }
+
+        return null;
+    }
+
+
+    protected CRL createCRL(CertificateList c)
+        throws CRLException
+    {
+        return new X509CRLObject(bcHelper, c);
+    }
+    
+    private CRL readPEMCRL(
+        InputStream in)
+        throws IOException, CRLException
+    {
+        return getCRL(PEM_CRL_PARSER.readPEMObject(in));
+    }
+
+    private CRL readDERCRL(
+        ASN1InputStream aIn)
+        throws IOException, CRLException
+    {
+        return getCRL(ASN1Sequence.getInstance(aIn.readObject()));
+    }
+
+    private CRL getCRL(ASN1Sequence seq)
+        throws CRLException
+    {
+        if (seq == null)
+        {
+            return null;
+        }
+        
+        if (seq.size() > 1
+                && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+        {
+            if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+            {
+                sCrlData = SignedData.getInstance(ASN1Sequence.getInstance(
+                    (ASN1TaggedObject)seq.getObjectAt(1), true)).getCRLs();
+
+                return getCRL();
+            }
+        }
+
+        return createCRL(
+                     CertificateList.getInstance(seq));
+    }
+
+    private CRL getCRL()
+        throws CRLException
+    {
+        if (sCrlData == null || sCrlDataObjectCount >= sCrlData.size())
+        {
+            return null;
+        }
+
+        return createCRL(
+                            CertificateList.getInstance(
+                                sCrlData.getObjectAt(sCrlDataObjectCount++)));
+    }
+
+    /**
+     * Generates a certificate object and initializes it with the data
+     * read from the input stream inStream.
+     */
+    public java.security.cert.Certificate engineGenerateCertificate(
+        InputStream in)
+        throws CertificateException
+    {
+        if (currentStream == null)
+        {
+            currentStream = in;
+            sData = null;
+            sDataObjectCount = 0;
+        }
+        else if (currentStream != in) // reset if input stream has changed
+        {
+            currentStream = in;
+            sData = null;
+            sDataObjectCount = 0;
+        }
+
+        try
+        {
+            if (sData != null)
+            {
+                if (sDataObjectCount != sData.size())
+                {
+                    return getCertificate();
+                }
+                else
+                {
+                    sData = null;
+                    sDataObjectCount = 0;
+                    return null;
+                }
+            }
+
+            InputStream pis;
+
+            if (in.markSupported())
+            {
+                pis = in;
+            }
+            else
+            {
+                // Android-changed: Use PushbackInputStream instead of ByteArrayInputStream.
+                // we want {@code in.available()} to return the number of available bytes if
+                // there is trailing data (otherwise it breaks
+                // libcore.java.security.cert.X509CertificateTest#test_Provider
+                // ). Which is not possible if we read the whole stream at this point.
+                // // pis = new ByteArrayInputStream(Streams.readAll(in));
+                pis = new PushbackInputStream(in);
+            }
+
+            // BEGIN Android-changed: Use PushbackInputStream
+            // pis.mark(1);
+            if (in.markSupported()) {
+                pis.mark(1);
+            }
+            // END Android-changed: Use PushbackInputStream
+
+            int tag = pis.read();
+
+            if (tag == -1)
+            {
+                return null;
+            }
+
+            // BEGIN Android-changed: Use PushbackInputStream
+            // pis.reset
+            if (in.markSupported()) {
+                pis.reset();
+            }
+            else
+            {
+                ((PushbackInputStream) pis).unread(tag);
+            }
+            // END Android-changed: Use PushbackInputStream
+
+            if (tag != 0x30)  // assume ascii PEM encoded.
+            {
+                return readPEMCertificate(pis);
+            }
+            else
+            {
+                return readDERCertificate(new ASN1InputStream(pis));
+            }
+        }
+        catch (Exception e)
+        {
+            throw new ExCertificateException("parsing issue: " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Returns a (possibly empty) collection view of the certificates
+     * read from the given input stream inStream.
+     */
+    public Collection engineGenerateCertificates(
+        InputStream inStream)
+        throws CertificateException
+    {
+        java.security.cert.Certificate     cert;
+        // Android-removed: Don't read entire stream immediately.
+        // we want {@code in.available()} to return the number of available bytes if
+        // there is trailing data (otherwise it breaks
+        // libcore.java.security.cert.X509CertificateTest#test_Provider
+        // ). Which is not possible if we read the whole stream at this point.
+        // BufferedInputStream in = new BufferedInputStream(inStream);
+        List certs = new ArrayList();
+
+        // Android-changed: Read from original stream
+        // while ((cert = engineGenerateCertificate(in)) != null)
+        while ((cert = engineGenerateCertificate(inStream)) != null)
+        {
+            certs.add(cert);
+        }
+
+        return certs;
+    }
+
+    /**
+     * Generates a certificate revocation list (CRL) object and initializes
+     * it with the data read from the input stream inStream.
+     */
+    public CRL engineGenerateCRL(
+        InputStream in)
+        throws CRLException
+    {
+        if (currentCrlStream == null)
+        {
+            currentCrlStream = in;
+            sCrlData = null;
+            sCrlDataObjectCount = 0;
+        }
+        else if (currentCrlStream != in) // reset if input stream has changed
+        {
+            currentCrlStream = in;
+            sCrlData = null;
+            sCrlDataObjectCount = 0;
+        }
+
+        try
+        {
+            if (sCrlData != null)
+            {
+                if (sCrlDataObjectCount != sCrlData.size())
+                {
+                    return getCRL();
+                }
+                else
+                {
+                    sCrlData = null;
+                    sCrlDataObjectCount = 0;
+                    return null;
+                }
+            }
+
+            InputStream pis;
+
+            if (in.markSupported())
+            {
+                pis = in;
+            }
+            else
+            {
+                pis = new ByteArrayInputStream(Streams.readAll(in));
+            }
+
+            pis.mark(1);
+            int tag = pis.read();
+
+            if (tag == -1)
+            {
+                return null;
+            }
+
+            pis.reset();
+            if (tag != 0x30)  // assume ascii PEM encoded.
+            {
+                return readPEMCRL(pis);
+            }
+            else
+            {       // lazy evaluate to help processing of large CRLs
+                return readDERCRL(new ASN1InputStream(pis, true));
+            }
+        }
+        catch (CRLException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+
+    /**
+     * Returns a (possibly empty) collection view of the CRLs read from
+     * the given input stream inStream.
+     *
+     * The inStream may contain a sequence of DER-encoded CRLs, or
+     * a PKCS#7 CRL set.  This is a PKCS#7 SignedData object, with the
+     * only signficant field being crls.  In particular the signature
+     * and the contents are ignored.
+     */
+    public Collection engineGenerateCRLs(
+        InputStream inStream)
+        throws CRLException
+    {
+        CRL crl;
+        List crls = new ArrayList();
+        BufferedInputStream in = new BufferedInputStream(inStream);
+
+        while ((crl = engineGenerateCRL(in)) != null)
+        {
+            crls.add(crl);
+        }
+
+        return crls;
+    }
+
+    public Iterator engineGetCertPathEncodings()
+    {
+        return PKIXCertPath.certPathEncodings.iterator();
+    }
+
+    public CertPath engineGenerateCertPath(
+        InputStream inStream)
+        throws CertificateException
+    {
+        return engineGenerateCertPath(inStream, "PkiPath");
+    }
+
+    public CertPath engineGenerateCertPath(
+        InputStream inStream,
+        String encoding)
+        throws CertificateException
+    {
+        return new PKIXCertPath(inStream, encoding);
+    }
+
+    public CertPath engineGenerateCertPath(
+        List certificates)
+        throws CertificateException
+    {
+        Iterator iter = certificates.iterator();
+        Object obj;
+        while (iter.hasNext())
+        {
+            obj = iter.next();
+            if (obj != null)
+            {
+                if (!(obj instanceof X509Certificate))
+                {
+                    throw new CertificateException("list contains non X509Certificate object while creating CertPath\n" + obj.toString());
+                }
+            }
+        }
+        return new PKIXCertPath(certificates);
+    }
+
+    private class ExCertificateException
+        extends CertificateException
+    {
+        private Throwable cause;
+
+        public ExCertificateException(Throwable cause)
+        {
+            this.cause = cause;
+        }
+
+        public ExCertificateException(String msg, Throwable cause)
+        {
+            super(msg);
+
+            this.cause = cause;
+        }
+
+        public Throwable getCause()
+        {
+            return cause;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/ExtCRLException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/ExtCRLException.java
new file mode 100644
index 0000000..011494a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/ExtCRLException.java
@@ -0,0 +1,21 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.security.cert.CRLException;
+
+class ExtCRLException
+    extends CRLException
+{
+    Throwable cause;
+
+    ExtCRLException(String message, Throwable cause)
+    {
+        super(message);
+        this.cause = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/KeyFactory.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/KeyFactory.java
new file mode 100644
index 0000000..7191d4e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/KeyFactory.java
@@ -0,0 +1,99 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class KeyFactory
+    extends KeyFactorySpi
+{
+
+    protected PrivateKey engineGeneratePrivate(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof PKCS8EncodedKeySpec)
+        {
+            try
+            {
+                PrivateKeyInfo info = PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded());
+                PrivateKey     key = BouncyCastleProvider.getPrivateKey(info);
+
+                if (key != null)
+                {
+                    return key;
+                }
+
+                throw new InvalidKeySpecException("no factory found for OID: " + info.getPrivateKeyAlgorithm().getAlgorithm());
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeySpecException(e.toString());
+            }
+        }
+
+        throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+    }
+
+    protected PublicKey engineGeneratePublic(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof X509EncodedKeySpec)
+        {
+            try
+            {
+                SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(((X509EncodedKeySpec)keySpec).getEncoded());
+                PublicKey            key = BouncyCastleProvider.getPublicKey(info);
+
+                if (key != null)
+                {
+                    return key;
+                }
+
+                throw new InvalidKeySpecException("no factory found for OID: " + info.getAlgorithm().getAlgorithm());
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeySpecException(e.toString());
+            }
+        }
+
+        throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+    }
+
+    protected KeySpec engineGetKeySpec(Key key, Class keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
+        {
+            return new PKCS8EncodedKeySpec(key.getEncoded());
+        }
+        else if (keySpec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
+        {
+            return new X509EncodedKeySpec(key.getEncoded());
+        }
+
+        throw new InvalidKeySpecException("not implemented yet " + key + " " + keySpec);
+    }
+
+    protected Key engineTranslateKey(Key key)
+        throws InvalidKeyException
+    {
+        throw new InvalidKeyException("not implemented yet " + key);
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
new file mode 100644
index 0000000..1729a2d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
@@ -0,0 +1,109 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.util.encoders.Base64;
+
+class PEMUtil
+{
+    private final String _header1;
+    private final String _header2;
+    private final String _header3;
+    private final String _footer1;
+    private final String _footer2;
+    private final String _footer3;
+
+    PEMUtil(
+        String type)
+    {
+        _header1 = "-----BEGIN " + type + "-----";
+        _header2 = "-----BEGIN X509 " + type + "-----";
+        _header3 = "-----BEGIN PKCS7-----";
+        _footer1 = "-----END " + type + "-----";
+        _footer2 = "-----END X509 " + type + "-----";
+        _footer3 = "-----END PKCS7-----";
+    }
+
+    private String readLine(
+        InputStream in)
+        throws IOException
+    {
+        int             c;
+        StringBuffer l = new StringBuffer();
+
+        do
+        {
+            while (((c = in.read()) != '\r') && c != '\n' && (c >= 0))
+            {
+                l.append((char)c);
+            }
+        }
+        while (c >= 0 && l.length() == 0);
+
+        if (c < 0)
+        {
+            return null;
+        }
+
+        // make sure we parse to end of line.
+        if (c == '\r')
+        {
+            // a '\n' may follow
+            in.mark(1);
+            if (((c = in.read()) == '\n'))
+            {
+                in.mark(1);
+            }
+
+            if (c > 0)
+            {
+                in.reset();
+            }
+        }
+
+        return l.toString();
+    }
+
+    ASN1Sequence readPEMObject(
+        InputStream in)
+        throws IOException
+    {
+        String line;
+        StringBuffer pemBuf = new StringBuffer();
+
+        while ((line = readLine(in)) != null)
+        {
+            if (line.startsWith(_header1) || line.startsWith(_header2) || line.startsWith(_header3))
+            {
+                break;
+            }
+        }
+
+        while ((line = readLine(in)) != null)
+        {
+            if (line.startsWith(_footer1) || line.startsWith(_footer2) || line.startsWith(_footer3))
+            {
+                break;
+            }
+
+            pemBuf.append(line);
+        }
+
+        if (pemBuf.length() != 0)
+        {
+            try
+            {
+                return ASN1Sequence.getInstance(Base64.decode(pemBuf.toString()));
+            }
+            catch (Exception e)
+            {
+                throw new IOException("malformed PEM data encountered");
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
new file mode 100644
index 0000000..6200e0a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
@@ -0,0 +1,382 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.security.NoSuchProviderException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERSet;
+import com.android.internal.org.bouncycastle.asn1.pkcs.ContentInfo;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.SignedData;
+import com.android.internal.org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.util.io.pem.PemObject;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.util.io.pem.PemWriter;
+
+/**
+ * CertPath implementation for X.509 certificates.
+ * @hide This class is not part of the Android public SDK API
+ */
+public  class PKIXCertPath
+    extends CertPath
+{
+    private final JcaJceHelper helper = new BCJcaJceHelper();
+
+    static final List certPathEncodings;
+
+    static
+    {
+        List encodings = new ArrayList();
+        encodings.add("PkiPath");
+        // Android-removed: Unsupported algorithms
+        // encodings.add("PEM");
+        encodings.add("PKCS7");
+        certPathEncodings = Collections.unmodifiableList(encodings);
+    }
+
+    private List certificates;
+
+    /**
+     * @param certs
+     */
+    private List sortCerts(
+        List certs)
+    {
+        if (certs.size() < 2)
+        {
+            return certs;
+        }
+        
+        X500Principal issuer = ((X509Certificate)certs.get(0)).getIssuerX500Principal();
+        boolean         okay = true;
+        
+        for (int i = 1; i != certs.size(); i++) 
+        {
+            X509Certificate cert = (X509Certificate)certs.get(i);
+            
+            if (issuer.equals(cert.getSubjectX500Principal()))
+            {
+                issuer = ((X509Certificate)certs.get(i)).getIssuerX500Principal();
+            }
+            else
+            {
+                okay = false;
+                break;
+            }
+        }
+        
+        if (okay)
+        {
+            return certs;
+        }
+        
+        // find end-entity cert
+        List retList = new ArrayList(certs.size());
+        List orig = new ArrayList(certs);
+
+        for (int i = 0; i < certs.size(); i++)
+        {
+            X509Certificate cert = (X509Certificate)certs.get(i);
+            boolean         found = false;
+            
+            X500Principal subject = cert.getSubjectX500Principal();
+            
+            for (int j = 0; j != certs.size(); j++)
+            {
+                X509Certificate c = (X509Certificate)certs.get(j);
+                if (c.getIssuerX500Principal().equals(subject))
+                {
+                    found = true;
+                    break;
+                }
+            }
+            
+            if (!found)
+            {
+                retList.add(cert);
+                certs.remove(i);
+            }
+        }
+        
+        // can only have one end entity cert - something's wrong, give up.
+        if (retList.size() > 1)
+        {
+            return orig;
+        }
+
+        for (int i = 0; i != retList.size(); i++)
+        {
+            issuer = ((X509Certificate)retList.get(i)).getIssuerX500Principal();
+            
+            for (int j = 0; j < certs.size(); j++)
+            {
+                X509Certificate c = (X509Certificate)certs.get(j);
+                if (issuer.equals(c.getSubjectX500Principal()))
+                {
+                    retList.add(c);
+                    certs.remove(j);
+                    break;
+                }
+            }
+        }
+        
+        // make sure all certificates are accounted for.
+        if (certs.size() > 0)
+        {
+            return orig;
+        }
+        
+        return retList;
+    }
+
+    PKIXCertPath(List certificates)
+    {
+        super("X.509");
+        this.certificates = sortCerts(new ArrayList(certificates));
+    }
+
+    /**
+     * Creates a CertPath of the specified type.
+     * This constructor is protected because most users should use
+     * a CertificateFactory to create CertPaths.
+     **/
+    PKIXCertPath(
+        InputStream inStream,
+        String encoding)
+        throws CertificateException
+    {
+        super("X.509");
+        try
+        {
+            if (encoding.equalsIgnoreCase("PkiPath"))
+            {
+                ASN1InputStream derInStream = new ASN1InputStream(inStream);
+                ASN1Primitive derObject = derInStream.readObject();
+                if (!(derObject instanceof ASN1Sequence))
+                {
+                    throw new CertificateException("input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
+                }
+                Enumeration e = ((ASN1Sequence)derObject).getObjects();
+                certificates = new ArrayList();
+                CertificateFactory certFactory = helper.createCertificateFactory("X.509");
+                while (e.hasMoreElements())
+                {
+                    ASN1Encodable element = (ASN1Encodable)e.nextElement();
+                    byte[] encoded = element.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+                    certificates.add(0, certFactory.generateCertificate(
+                        new ByteArrayInputStream(encoded)));
+                }
+            }
+            else if (encoding.equalsIgnoreCase("PKCS7") || encoding.equalsIgnoreCase("PEM"))
+            {
+                inStream = new BufferedInputStream(inStream);
+                certificates = new ArrayList();
+                CertificateFactory certFactory= helper.createCertificateFactory("X.509");
+                Certificate cert;
+                while ((cert = certFactory.generateCertificate(inStream)) != null)
+                {
+                    certificates.add(cert);
+                }
+            }
+            else
+            {
+                throw new CertificateException("unsupported encoding: " + encoding);
+            }
+        }
+        catch (IOException ex)
+        {
+            throw new CertificateException("IOException throw while decoding CertPath:\n" + ex.toString());
+        }
+        catch (NoSuchProviderException ex)
+        {
+            throw new CertificateException("BouncyCastle provider not found while trying to get a CertificateFactory:\n" + ex.toString());
+        }
+
+        this.certificates = sortCerts(certificates);
+    }
+    
+    /**
+     * Returns an iteration of the encodings supported by this
+     * certification path, with the default encoding
+     * first. Attempts to modify the returned Iterator via its
+     * remove method result in an UnsupportedOperationException.
+     *
+     * @return an Iterator over the names of the supported encodings (as Strings)
+     **/
+    public Iterator getEncodings()
+    {
+        return certPathEncodings.iterator();
+    }
+
+    /**
+     * Returns the encoded form of this certification path, using
+     * the default encoding.
+     *
+     * @return the encoded bytes
+     * @exception java.security.cert.CertificateEncodingException if an encoding error occurs
+     **/
+    public byte[] getEncoded()
+        throws CertificateEncodingException
+    {
+        Iterator iter = getEncodings();
+        if (iter.hasNext())
+        {
+            Object enc = iter.next();
+            if (enc instanceof String)
+            {
+            return getEncoded((String)enc);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the encoded form of this certification path, using
+     * the specified encoding.
+     *
+     * @param encoding the name of the encoding to use
+     * @return the encoded bytes
+     * @exception java.security.cert.CertificateEncodingException if an encoding error
+     * occurs or the encoding requested is not supported
+     *
+     **/
+    public byte[] getEncoded(String encoding)
+        throws CertificateEncodingException
+    {
+        if (encoding.equalsIgnoreCase("PkiPath"))
+        {
+            ASN1EncodableVector v = new ASN1EncodableVector();
+
+            ListIterator iter = certificates.listIterator(certificates.size());
+            while (iter.hasPrevious())
+            {
+                v.add(toASN1Object((X509Certificate)iter.previous()));
+            }
+
+            return toDEREncoded(new DERSequence(v));
+        }
+        else if (encoding.equalsIgnoreCase("PKCS7"))
+        {
+            ContentInfo encInfo = new ContentInfo(PKCSObjectIdentifiers.data, null);
+
+            ASN1EncodableVector v = new ASN1EncodableVector();
+            for (int i = 0; i != certificates.size(); i++)
+            {
+                v.add(toASN1Object((X509Certificate)certificates.get(i)));
+            }
+            
+            SignedData sd = new SignedData(
+                                     new ASN1Integer(1),
+                                     new DERSet(),
+                                     encInfo, 
+                                     new DERSet(v),
+                                     null, 
+                                     new DERSet());
+
+            return toDEREncoded(new ContentInfo(
+                    PKCSObjectIdentifiers.signedData, sd));
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (encoding.equalsIgnoreCase("PEM"))
+        {
+            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+            PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut));
+
+            try
+            {
+                for (int i = 0; i != certificates.size(); i++)
+                {
+                    pWrt.writeObject(new PemObject("CERTIFICATE", ((X509Certificate)certificates.get(i)).getEncoded()));
+                }
+            
+                pWrt.close();
+            }
+            catch (Exception e)
+            {
+                throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
+            }
+
+            return bOut.toByteArray();
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+        else
+        {
+            throw new CertificateEncodingException("unsupported encoding: " + encoding);
+        }
+    }
+
+    /**
+     * Returns the list of certificates in this certification
+     * path. The List returned must be immutable and thread-safe. 
+     *
+     * @return an immutable List of Certificates (may be empty, but not null)
+     **/
+    public List getCertificates()
+    {
+        return Collections.unmodifiableList(new ArrayList(certificates));
+    }
+
+    /**
+     * Return a DERObject containing the encoded certificate.
+     *
+     * @param cert the X509Certificate object to be encoded
+     *
+     * @return the DERObject
+     **/
+    private ASN1Primitive toASN1Object(
+        X509Certificate cert)
+        throws CertificateEncodingException
+    {
+        try
+        {
+            return new ASN1InputStream(cert.getEncoded()).readObject();
+        }
+        catch (Exception e)
+        {
+            throw new CertificateEncodingException("Exception while encoding certificate: " + e.toString());
+        }
+    }
+    
+    private byte[] toDEREncoded(ASN1Encodable obj)
+        throws CertificateEncodingException
+    {
+        try
+        {
+            return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException("Exception thrown: " + e);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
new file mode 100644
index 0000000..d9417f6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
@@ -0,0 +1,319 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.util.ASN1Dump;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x509.CRLReason;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.Extensions;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralNames;
+import com.android.internal.org.bouncycastle.asn1.x509.TBSCertList;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ * 
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+class X509CRLEntryObject extends X509CRLEntry
+{
+    private TBSCertList.CRLEntry c;
+
+    private X500Name certificateIssuer;
+    private int           hashValue;
+    private boolean       isHashValueSet;
+
+    protected X509CRLEntryObject(TBSCertList.CRLEntry c)
+    {
+        this.c = c;
+        this.certificateIssuer = null;
+    }
+
+    /**
+     * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code>
+     * is <code>false</code> {@link #getCertificateIssuer()} will always
+     * return <code>null</code>, <code>previousCertificateIssuer</code> is
+     * ignored. If this <code>isIndirect</code> is specified and this CRLEntry
+     * has no certificate issuer CRL entry extension
+     * <code>previousCertificateIssuer</code> is returned by
+     * {@link #getCertificateIssuer()}.
+     * 
+     * @param c
+     *            TBSCertList.CRLEntry object.
+     * @param isIndirect
+     *            <code>true</code> if the corresponding CRL is a indirect
+     *            CRL.
+     * @param previousCertificateIssuer
+     *            Certificate issuer of the previous CRLEntry.
+     */
+    protected X509CRLEntryObject(
+        TBSCertList.CRLEntry c,
+        boolean isIndirect,
+        X500Name previousCertificateIssuer)
+    {
+        this.c = c;
+        this.certificateIssuer = loadCertificateIssuer(isIndirect, previousCertificateIssuer);
+    }
+
+    /**
+     * Will return true if any extensions are present and marked as critical as
+     * we currently don't handle any extensions!
+     */
+    public boolean hasUnsupportedCriticalExtension()
+    {
+        Set extns = getCriticalExtensionOIDs();
+
+        return extns != null && !extns.isEmpty();
+    }
+
+    private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer)
+    {
+        if (!isIndirect)
+        {
+            return null;
+        }
+
+        Extension ext = getExtension(Extension.certificateIssuer);
+        if (ext == null)
+        {
+            return previousCertificateIssuer;
+        }
+
+        try
+        {
+            GeneralName[] names = GeneralNames.getInstance(ext.getParsedValue()).getNames();
+            for (int i = 0; i < names.length; i++)
+            {
+                if (names[i].getTagNo() == GeneralName.directoryName)
+                {
+                    return X500Name.getInstance(names[i].getName());
+                }
+            }
+            return null;
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    public X500Principal getCertificateIssuer()
+    {
+        if (certificateIssuer == null)
+        {
+            return null;
+        }
+        try
+        {
+            return new X500Principal(certificateIssuer.getEncoded());
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+
+    private Set getExtensionOIDs(boolean critical)
+    {
+        Extensions extensions = c.getExtensions();
+
+        if (extensions != null)
+        {
+            Set set = new HashSet();
+            Enumeration e = extensions.oids();
+
+            while (e.hasMoreElements())
+            {
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+                Extension ext = extensions.getExtension(oid);
+
+                if (critical == ext.isCritical())
+                {
+                    set.add(oid.getId());
+                }
+            }
+
+            return set;
+        }
+
+        return null;
+    }
+
+    public Set getCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(true);
+    }
+
+    public Set getNonCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(false);
+    }
+
+    private Extension getExtension(ASN1ObjectIdentifier oid)
+    {
+        Extensions exts = c.getExtensions();
+
+        if (exts != null)
+        {
+            return exts.getExtension(oid);
+        }
+
+        return null;
+    }
+
+    public byte[] getExtensionValue(String oid)
+    {
+        Extension ext = getExtension(new ASN1ObjectIdentifier(oid));
+
+        if (ext != null)
+        {
+            try
+            {
+                return ext.getExtnValue().getEncoded();
+            }
+            catch (Exception e)
+            {
+                throw new IllegalStateException("Exception encoding: " + e.toString());
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Cache the hashCode value - calculating it with the standard method.
+     * @return  calculated hashCode.
+     */
+    public int hashCode()
+    {
+        if (!isHashValueSet)
+        {
+            hashValue = super.hashCode();
+            isHashValueSet = true;
+        }
+
+        return hashValue;
+    }
+
+    public boolean equals(Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (o instanceof X509CRLEntryObject)
+        {
+            X509CRLEntryObject other = (X509CRLEntryObject)o;
+
+            return this.c.equals(other.c);
+        }
+
+        return super.equals(this);
+    }
+
+    public byte[] getEncoded()
+        throws CRLException
+    {
+        try
+        {
+            return c.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+
+    public BigInteger getSerialNumber()
+    {
+        return c.getUserCertificate().getValue();
+    }
+
+    public Date getRevocationDate()
+    {
+        return c.getRevocationDate().getDate();
+    }
+
+    public boolean hasExtensions()
+    {
+        return c.getExtensions() != null;
+    }
+
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        String nl = Strings.lineSeparator();
+
+        buf.append("      userCertificate: ").append(this.getSerialNumber()).append(nl);
+        buf.append("       revocationDate: ").append(this.getRevocationDate()).append(nl);
+        buf.append("       certificateIssuer: ").append(this.getCertificateIssuer()).append(nl);
+
+        Extensions extensions = c.getExtensions();
+
+        if (extensions != null)
+        {
+            Enumeration e = extensions.oids();
+            if (e.hasMoreElements())
+            {
+                buf.append("   crlEntryExtensions:").append(nl);
+
+                while (e.hasMoreElements())
+                {
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    Extension ext = extensions.getExtension(oid);
+                    if (ext.getExtnValue() != null)
+                    {
+                        byte[]                  octs = ext.getExtnValue().getOctets();
+                        ASN1InputStream dIn = new ASN1InputStream(octs);
+                        buf.append("                       critical(").append(ext.isCritical()).append(") ");
+                        try
+                        {
+                            if (oid.equals(Extension.reasonCode))
+                            {
+                                buf.append(CRLReason.getInstance(ASN1Enumerated.getInstance(dIn.readObject()))).append(nl);
+                            }
+                            else if (oid.equals(Extension.certificateIssuer))
+                            {
+                                buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl);
+                            }
+                            else 
+                            {
+                                buf.append(oid.getId());
+                                buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            buf.append(oid.getId());
+                            buf.append(" value = ").append("*****").append(nl);
+                        }
+                    }
+                    else
+                    {
+                        buf.append(nl);
+                    }
+                }
+            }
+        }
+
+        return buf.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
new file mode 100644
index 0000000..d72a120
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
@@ -0,0 +1,682 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.util.ASN1Dump;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x509.CRLDistPoint;
+import com.android.internal.org.bouncycastle.asn1.x509.CRLNumber;
+import com.android.internal.org.bouncycastle.asn1.x509.CertificateList;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.Extensions;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralNames;
+import com.android.internal.org.bouncycastle.asn1.x509.IssuingDistributionPoint;
+import com.android.internal.org.bouncycastle.asn1.x509.TBSCertList;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.jce.X509Principal;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+class X509CRLObject
+    extends X509CRL
+{
+    private JcaJceHelper bcHelper;
+    private CertificateList c;
+    private String sigAlgName;
+    private byte[] sigAlgParams;
+    private boolean isIndirect;
+    private boolean isHashCodeSet = false;
+    private int     hashCodeValue;
+
+    static boolean isIndirectCRL(X509CRL crl)
+        throws CRLException
+    {
+        try
+        {
+            byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
+            return idp != null
+                && IssuingDistributionPoint.getInstance(ASN1OctetString.getInstance(idp).getOctets()).isIndirectCRL();
+        }
+        catch (Exception e)
+        {
+            throw new ExtCRLException(
+                    "Exception reading IssuingDistributionPoint", e);
+        }
+    }
+
+    protected X509CRLObject(
+        JcaJceHelper bcHelper,
+        CertificateList c)
+        throws CRLException
+    {
+        this.bcHelper = bcHelper;
+        this.c = c;
+        
+        try
+        {
+            this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+            
+            if (c.getSignatureAlgorithm().getParameters() != null)
+            {
+                this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
+            }
+            else
+            {
+                this.sigAlgParams = null;
+            }
+
+            this.isIndirect = isIndirectCRL(this);
+        }
+        catch (Exception e)
+        {
+            throw new CRLException("CRL contents invalid: " + e);
+        }
+    }
+
+    /**
+     * Will return true if any extensions are present and marked
+     * as critical as we currently dont handle any extensions!
+     */
+    public boolean hasUnsupportedCriticalExtension()
+    {
+        Set extns = getCriticalExtensionOIDs();
+
+        if (extns == null)
+        {
+            return false;
+        }
+
+        extns.remove(Extension.issuingDistributionPoint.getId());
+        extns.remove(Extension.deltaCRLIndicator.getId());
+
+        return !extns.isEmpty();
+    }
+
+    private Set getExtensionOIDs(boolean critical)
+    {
+        if (this.getVersion() == 2)
+        {
+            Extensions extensions = c.getTBSCertList().getExtensions();
+
+            if (extensions != null)
+            {
+                Set set = new HashSet();
+                Enumeration e = extensions.oids();
+
+                while (e.hasMoreElements())
+                {
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    Extension ext = extensions.getExtension(oid);
+
+                    if (critical == ext.isCritical())
+                    {
+                        set.add(oid.getId());
+                    }
+                }
+
+                return set;
+            }
+        }
+
+        return null;
+    }
+
+    public Set getCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(true);
+    }
+
+    public Set getNonCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(false);
+    }
+
+    public byte[] getExtensionValue(String oid)
+    {
+        Extensions exts = c.getTBSCertList().getExtensions();
+
+        if (exts != null)
+        {
+            Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+            if (ext != null)
+            {
+                try
+                {
+                    return ext.getExtnValue().getEncoded();
+                }
+                catch (Exception e)
+                {
+                    throw new IllegalStateException("error parsing " + e.toString());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public byte[] getEncoded()
+        throws CRLException
+    {
+        try
+        {
+            return c.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+
+    public void verify(PublicKey key)
+        throws CRLException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        Signature sig;
+
+        try
+        {
+            sig = bcHelper.createSignature(getSigAlgName());
+        }
+        catch (Exception e)
+        {
+            sig = Signature.getInstance(getSigAlgName());
+        }
+
+        doVerify(key, sig);
+    }
+
+    public void verify(PublicKey key, String sigProvider)
+        throws CRLException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        Signature sig;
+
+        if (sigProvider != null)
+        {
+            sig = Signature.getInstance(getSigAlgName(), sigProvider);
+        }
+        else
+        {
+            sig = Signature.getInstance(getSigAlgName());
+        }
+
+        doVerify(key, sig);
+    }
+
+    public void verify(PublicKey key, Provider sigProvider)
+        throws CRLException, NoSuchAlgorithmException,
+        InvalidKeyException, SignatureException
+    {
+        Signature sig;
+
+        if (sigProvider != null)
+        {
+            sig = Signature.getInstance(getSigAlgName(), sigProvider);
+        }
+        else
+        {
+            sig = Signature.getInstance(getSigAlgName());
+        }
+
+        doVerify(key, sig);
+    }
+
+    private void doVerify(PublicKey key, Signature sig)
+        throws CRLException, NoSuchAlgorithmException,
+        InvalidKeyException, SignatureException
+    {
+        if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
+        {
+            throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
+        }
+
+        if (sigAlgParams != null)
+        {
+            try
+            {
+                // needs to be called before initVerify().
+                X509SignatureUtil.setSignatureParameters(sig, ASN1Primitive.fromByteArray(sigAlgParams));
+            }
+            catch (IOException e)
+            {
+                throw new SignatureException("cannot decode signature parameters: " + e.getMessage());
+            }
+        }
+
+        sig.initVerify(key);
+        sig.update(this.getTBSCertList());
+
+        if (!sig.verify(this.getSignature()))
+        {
+            throw new SignatureException("CRL does not verify with supplied public key.");
+        }
+    }
+
+    public int getVersion()
+    {
+        return c.getVersionNumber();
+    }
+
+    public Principal getIssuerDN()
+    {
+        return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
+    }
+
+    public X500Principal getIssuerX500Principal()
+    {
+        try
+        {
+            return new X500Principal(c.getIssuer().getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("can't encode issuer DN");
+        }
+    }
+
+    public Date getThisUpdate()
+    {
+        return c.getThisUpdate().getDate();
+    }
+
+    public Date getNextUpdate()
+    {
+        if (c.getNextUpdate() != null)
+        {
+            return c.getNextUpdate().getDate();
+        }
+
+        return null;
+    }
+ 
+    private Set loadCRLEntries()
+    {
+        Set entrySet = new HashSet();
+        Enumeration certs = c.getRevokedCertificateEnumeration();
+
+        X500Name previousCertificateIssuer = null; // the issuer
+        while (certs.hasMoreElements())
+        {
+            TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+            X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+            entrySet.add(crlEntry);
+            if (isIndirect && entry.hasExtensions())
+            {
+                Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+                if (currentCaName != null)
+                {
+                    previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+                }
+            }
+        }
+
+        return entrySet;
+    }
+
+    public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
+    {
+        Enumeration certs = c.getRevokedCertificateEnumeration();
+
+        X500Name previousCertificateIssuer = null; // the issuer
+        while (certs.hasMoreElements())
+        {
+            TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+
+            if (serialNumber.equals(entry.getUserCertificate().getValue()))
+            {
+                return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+            }
+
+            if (isIndirect && entry.hasExtensions())
+            {
+                Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+                if (currentCaName != null)
+                {
+                    previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public Set getRevokedCertificates()
+    {
+        Set entrySet = loadCRLEntries();
+
+        if (!entrySet.isEmpty())
+        {
+            return Collections.unmodifiableSet(entrySet);
+        }
+
+        return null;
+    }
+
+    public byte[] getTBSCertList()
+        throws CRLException
+    {
+        try
+        {
+            return c.getTBSCertList().getEncoded("DER");
+        }
+        catch (IOException e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+
+    public byte[] getSignature()
+    {
+        return c.getSignature().getOctets();
+    }
+
+    public String getSigAlgName()
+    {
+        return sigAlgName;
+    }
+
+    public String getSigAlgOID()
+    {
+        return c.getSignatureAlgorithm().getAlgorithm().getId();
+    }
+
+    public byte[] getSigAlgParams()
+    {
+        if (sigAlgParams != null)
+        {
+            byte[] tmp = new byte[sigAlgParams.length];
+            
+            System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
+            
+            return tmp;
+        }
+        
+        return null;
+    }
+
+    /**
+     * Returns a string representation of this CRL.
+     *
+     * @return a string representation of this CRL.
+     */
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        String nl = Strings.lineSeparator();
+
+        buf.append("              Version: ").append(this.getVersion()).append(
+            nl);
+        buf.append("             IssuerDN: ").append(this.getIssuerDN())
+            .append(nl);
+        buf.append("          This update: ").append(this.getThisUpdate())
+            .append(nl);
+        buf.append("          Next update: ").append(this.getNextUpdate())
+            .append(nl);
+        buf.append("  Signature Algorithm: ").append(this.getSigAlgName())
+            .append(nl);
+
+        byte[] sig = this.getSignature();
+
+        buf.append("            Signature: ").append(
+            new String(Hex.encode(sig, 0, 20))).append(nl);
+        for (int i = 20; i < sig.length; i += 20)
+        {
+            if (i < sig.length - 20)
+            {
+                buf.append("                       ").append(
+                    new String(Hex.encode(sig, i, 20))).append(nl);
+            }
+            else
+            {
+                buf.append("                       ").append(
+                    new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+            }
+        }
+
+        Extensions extensions = c.getTBSCertList().getExtensions();
+
+        if (extensions != null)
+        {
+            Enumeration e = extensions.oids();
+
+            if (e.hasMoreElements())
+            {
+                buf.append("           Extensions: ").append(nl);
+            }
+
+            while (e.hasMoreElements())
+            {
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+                Extension ext = extensions.getExtension(oid);
+
+                if (ext.getExtnValue() != null)
+                {
+                    byte[] octs = ext.getExtnValue().getOctets();
+                    ASN1InputStream dIn = new ASN1InputStream(octs);
+                    buf.append("                       critical(").append(
+                        ext.isCritical()).append(") ");
+                    try
+                    {
+                        if (oid.equals(Extension.cRLNumber))
+                        {
+                            buf.append(
+                                new CRLNumber(ASN1Integer.getInstance(
+                                    dIn.readObject()).getPositiveValue()))
+                                .append(nl);
+                        }
+                        else if (oid.equals(Extension.deltaCRLIndicator))
+                        {
+                            buf.append(
+                                "Base CRL: "
+                                    + new CRLNumber(ASN1Integer.getInstance(
+                                        dIn.readObject()).getPositiveValue()))
+                                .append(nl);
+                        }
+                        else if (oid
+                            .equals(Extension.issuingDistributionPoint))
+                        {
+                            buf.append(
+                               IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
+                        }
+                        else if (oid
+                            .equals(Extension.cRLDistributionPoints))
+                        {
+                            buf.append(
+                                CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(Extension.freshestCRL))
+                        {
+                            buf.append(
+                                CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+                        }
+                        else
+                        {
+                            buf.append(oid.getId());
+                            buf.append(" value = ").append(
+                                ASN1Dump.dumpAsString(dIn.readObject()))
+                                .append(nl);
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        buf.append(oid.getId());
+                        buf.append(" value = ").append("*****").append(nl);
+                    }
+                }
+                else
+                {
+                    buf.append(nl);
+                }
+            }
+        }
+        Set set = getRevokedCertificates();
+        if (set != null)
+        {
+            Iterator it = set.iterator();
+            while (it.hasNext())
+            {
+                buf.append(it.next());
+                buf.append(nl);
+            }
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Checks whether the given certificate is on this CRL.
+     *
+     * @param cert the certificate to check for.
+     * @return true if the given certificate is on this CRL,
+     * false otherwise.
+     */
+    public boolean isRevoked(Certificate cert)
+    {
+        if (!cert.getType().equals("X.509"))
+        {
+            throw new IllegalArgumentException("X.509 CRL used with non X.509 Cert");
+        }
+
+        Enumeration certs = c.getRevokedCertificateEnumeration();
+
+        X500Name caName = c.getIssuer();
+
+        if (certs.hasMoreElements())
+        {
+            BigInteger serial = ((X509Certificate)cert).getSerialNumber();
+
+            while (certs.hasMoreElements())
+            {
+                TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement());
+
+                if (isIndirect && entry.hasExtensions())
+                {
+                    Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+                    if (currentCaName != null)
+                    {
+                        caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+                    }
+                }
+
+                if (entry.getUserCertificate().getValue().equals(serial))
+                {
+                    X500Name issuer;
+
+                    if (cert instanceof  X509Certificate)
+                    {
+                        issuer = X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded());
+                    }
+                    else
+                    {
+                        try
+                        {
+                            issuer = com.android.internal.org.bouncycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
+                        }
+                        catch (CertificateEncodingException e)
+                        {
+                            throw new IllegalArgumentException("Cannot process certificate: " + e.getMessage());
+                        }
+                    }
+
+                    if (!caName.equals(issuer))
+                    {
+                        return false;
+                    }
+
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public boolean equals(Object other)
+    {
+        if (this == other)
+        {
+            return true;
+        }
+
+        if (!(other instanceof X509CRL))
+        {
+            return false;
+        }
+
+        if (other instanceof X509CRLObject)
+        {
+            X509CRLObject crlObject = (X509CRLObject)other;
+
+            if (isHashCodeSet)
+            {
+                boolean otherIsHashCodeSet = crlObject.isHashCodeSet;
+                if (otherIsHashCodeSet)
+                {
+                    if (crlObject.hashCodeValue != hashCodeValue)
+                    {
+                        return false;
+                    }
+                }
+            }
+
+            return this.c.equals(crlObject.c);
+        }
+
+        return super.equals(other);
+    }
+
+    public int hashCode()
+    {
+        if (!isHashCodeSet)
+        {
+            isHashCodeSet = true;
+            hashCodeValue = super.hashCode();
+        }
+
+        return hashCodeValue;
+    }
+}
+
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
new file mode 100644
index 0000000..857a839
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
@@ -0,0 +1,924 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1BitString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OutputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1String;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.misc.NetscapeCertType;
+import com.android.internal.org.bouncycastle.asn1.misc.NetscapeRevocationURL;
+import com.android.internal.org.bouncycastle.asn1.misc.VerisignCzagExtension;
+import com.android.internal.org.bouncycastle.asn1.util.ASN1Dump;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x500.style.RFC4519Style;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.BasicConstraints;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.Extensions;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.asn1.x509.KeyUsage;
+// BEGIN Android-added: Unknown reason
+import com.android.internal.org.bouncycastle.asn1.x509.X509Name;
+// END Android-added: Unknown reason
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.jce.X509Principal;
+import com.android.internal.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.util.Integers;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+class X509CertificateObject
+    extends X509Certificate
+    implements PKCS12BagAttributeCarrier
+{
+    private JcaJceHelper bcHelper;
+    private com.android.internal.org.bouncycastle.asn1.x509.Certificate    c;
+    private BasicConstraints            basicConstraints;
+    private boolean[]                   keyUsage;
+    private boolean                     hashValueSet;
+    private int                         hashValue;
+
+    private PKCS12BagAttributeCarrier   attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    public X509CertificateObject(
+        JcaJceHelper bcHelper,
+        com.android.internal.org.bouncycastle.asn1.x509.Certificate    c)
+        throws CertificateParsingException
+    {
+        this.bcHelper = bcHelper;
+        this.c = c;
+
+        try
+        {
+            byte[]  bytes = this.getExtensionBytes("2.5.29.19");
+
+            if (bytes != null)
+            {
+                basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
+            }
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+        }
+
+        try
+        {
+            byte[] bytes = this.getExtensionBytes("2.5.29.15");
+            if (bytes != null)
+            {
+                ASN1BitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
+
+                bytes = bits.getBytes();
+                int length = (bytes.length * 8) - bits.getPadBits();
+
+                keyUsage = new boolean[(length < 9) ? 9 : length];
+
+                for (int i = 0; i != length; i++)
+                {
+                    keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+                }
+            }
+            else
+            {
+                keyUsage = null;
+            }
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+        }
+    }
+
+    public void checkValidity()
+        throws CertificateExpiredException, CertificateNotYetValidException
+    {
+        this.checkValidity(new Date());
+    }
+
+    public void checkValidity(
+        Date    date)
+        throws CertificateExpiredException, CertificateNotYetValidException
+    {
+        if (date.getTime() > this.getNotAfter().getTime())  // for other VM compatibility
+        {
+            throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
+        }
+
+        if (date.getTime() < this.getNotBefore().getTime())
+        {
+            throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
+        }
+    }
+
+    public int getVersion()
+    {
+        return c.getVersionNumber();
+    }
+
+    public BigInteger getSerialNumber()
+    {
+        return c.getSerialNumber().getValue();
+    }
+
+    public Principal getIssuerDN()
+    {
+        try
+        {
+            return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+
+    public X500Principal getIssuerX500Principal()
+    {
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+
+            aOut.writeObject(c.getIssuer());
+
+            return new X500Principal(bOut.toByteArray());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("can't encode issuer DN");
+        }
+    }
+
+    public Principal getSubjectDN()
+    {
+        return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
+    }
+
+    public X500Principal getSubjectX500Principal()
+    {
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+
+            aOut.writeObject(c.getSubject());
+
+            return new X500Principal(bOut.toByteArray());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("can't encode issuer DN");
+        }
+    }
+
+    public Date getNotBefore()
+    {
+        return c.getStartDate().getDate();
+    }
+
+    public Date getNotAfter()
+    {
+        return c.getEndDate().getDate();
+    }
+
+    public byte[] getTBSCertificate()
+        throws CertificateEncodingException
+    {
+        try
+        {
+            return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException(e.toString());
+        }
+    }
+
+    public byte[] getSignature()
+    {
+        return c.getSignature().getOctets();
+    }
+
+    /**
+     * return a more "meaningful" representation for the signature algorithm used in
+     * the certificate.
+     */
+    public String getSigAlgName()
+    {
+        return X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+    }
+
+    /**
+     * return the object identifier for the signature.
+     */
+    public String getSigAlgOID()
+    {
+        return c.getSignatureAlgorithm().getAlgorithm().getId();
+    }
+
+    /**
+     * return the signature parameters, or null if there aren't any.
+     */
+    public byte[] getSigAlgParams()
+    {
+        if (c.getSignatureAlgorithm().getParameters() != null)
+        {
+            try
+            {
+                return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+            }
+            catch (IOException e)
+            {
+                return null;
+            }
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    public boolean[] getIssuerUniqueID()
+    {
+        DERBitString    id = c.getTBSCertificate().getIssuerUniqueId();
+
+        if (id != null)
+        {
+            byte[]          bytes = id.getBytes();
+            boolean[]       boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+            for (int i = 0; i != boolId.length; i++)
+            {
+                boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+            }
+
+            return boolId;
+        }
+            
+        return null;
+    }
+
+    public boolean[] getSubjectUniqueID()
+    {
+        DERBitString    id = c.getTBSCertificate().getSubjectUniqueId();
+
+        if (id != null)
+        {
+            byte[]          bytes = id.getBytes();
+            boolean[]       boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+            for (int i = 0; i != boolId.length; i++)
+            {
+                boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+            }
+
+            return boolId;
+        }
+            
+        return null;
+    }
+
+    public boolean[] getKeyUsage()
+    {
+        return keyUsage;
+    }
+
+    public List getExtendedKeyUsage() 
+        throws CertificateParsingException
+    {
+        byte[]  bytes = this.getExtensionBytes("2.5.29.37");
+
+        if (bytes != null)
+        {
+            try
+            {
+                ASN1InputStream dIn = new ASN1InputStream(bytes);
+                ASN1Sequence    seq = (ASN1Sequence)dIn.readObject();
+                List            list = new ArrayList();
+
+                for (int i = 0; i != seq.size(); i++)
+                {
+                    list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId());
+                }
+                
+                return Collections.unmodifiableList(list);
+            }
+            catch (Exception e)
+            {
+                throw new CertificateParsingException("error processing extended key usage extension");
+            }
+        }
+
+        return null;
+    }
+    
+    public int getBasicConstraints()
+    {
+        if (basicConstraints != null)
+        {
+            if (basicConstraints.isCA())
+            {
+                if (basicConstraints.getPathLenConstraint() == null)
+                {
+                    return Integer.MAX_VALUE;
+                }
+                else
+                {
+                    return basicConstraints.getPathLenConstraint().intValue();
+                }
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        return -1;
+    }
+
+    public Collection getSubjectAlternativeNames()
+        throws CertificateParsingException
+    {
+        return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId()));
+    }
+
+    public Collection getIssuerAlternativeNames()
+        throws CertificateParsingException
+    {
+        return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId()));
+    }
+
+    public Set getCriticalExtensionOIDs() 
+    {
+        if (this.getVersion() == 3)
+        {
+            Set             set = new HashSet();
+            Extensions  extensions = c.getTBSCertificate().getExtensions();
+
+            if (extensions != null)
+            {
+                Enumeration     e = extensions.oids();
+
+                while (e.hasMoreElements())
+                {
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    Extension       ext = extensions.getExtension(oid);
+
+                    if (ext.isCritical())
+                    {
+                        set.add(oid.getId());
+                    }
+                }
+
+                return set;
+            }
+        }
+
+        return null;
+    }
+
+    private byte[] getExtensionBytes(String oid)
+    {
+        Extensions exts = c.getTBSCertificate().getExtensions();
+
+        if (exts != null)
+        {
+            Extension   ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+            if (ext != null)
+            {
+                return ext.getExtnValue().getOctets();
+            }
+        }
+
+        return null;
+    }
+
+    public byte[] getExtensionValue(String oid) 
+    {
+        Extensions exts = c.getTBSCertificate().getExtensions();
+
+        if (exts != null)
+        {
+            Extension   ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+            if (ext != null)
+            {
+                try
+                {
+                    return ext.getExtnValue().getEncoded();
+                }
+                catch (Exception e)
+                {
+                    throw new IllegalStateException("error parsing " + e.toString());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public Set getNonCriticalExtensionOIDs() 
+    {
+        if (this.getVersion() == 3)
+        {
+            Set             set = new HashSet();
+            Extensions  extensions = c.getTBSCertificate().getExtensions();
+
+            if (extensions != null)
+            {
+                Enumeration     e = extensions.oids();
+
+                while (e.hasMoreElements())
+                {
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    Extension       ext = extensions.getExtension(oid);
+
+                    if (!ext.isCritical())
+                    {
+                        set.add(oid.getId());
+                    }
+                }
+
+                return set;
+            }
+        }
+
+        return null;
+    }
+
+    public boolean hasUnsupportedCriticalExtension()
+    {
+        if (this.getVersion() == 3)
+        {
+            Extensions  extensions = c.getTBSCertificate().getExtensions();
+
+            if (extensions != null)
+            {
+                Enumeration     e = extensions.oids();
+
+                while (e.hasMoreElements())
+                {
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+                    if (oid.equals(Extension.keyUsage)
+                     || oid.equals(Extension.certificatePolicies)
+                     || oid.equals(Extension.policyMappings)
+                     || oid.equals(Extension.inhibitAnyPolicy)
+                     || oid.equals(Extension.cRLDistributionPoints)
+                     || oid.equals(Extension.issuingDistributionPoint)
+                     || oid.equals(Extension.deltaCRLIndicator)
+                     || oid.equals(Extension.policyConstraints)
+                     || oid.equals(Extension.basicConstraints)
+                     || oid.equals(Extension.subjectAlternativeName)
+                     || oid.equals(Extension.nameConstraints))
+                    {
+                        continue;
+                    }
+
+                    Extension       ext = extensions.getExtension(oid);
+
+                    if (ext.isCritical())
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public PublicKey getPublicKey()
+    {
+        try
+        {
+            return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
+        }
+        catch (IOException e)
+        {
+            return null;   // should never happen...
+        }
+    }
+
+    // Android-added: Cache the encoded certificate
+    private byte[] encoded;
+    public byte[] getEncoded()
+        throws CertificateEncodingException
+    {
+        try
+        {
+            // BEGIN Android-changed: Cache the encoded certificate
+            if (encoded == null) {
+                encoded = c.getEncoded(ASN1Encoding.DER);
+            }
+            return encoded;
+            // END Android-changed: Cache the encoded certificate
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException(e.toString());
+        }
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (o instanceof X509CertificateObject)
+        {
+            X509CertificateObject other = (X509CertificateObject)o;
+
+            if (this.hashValueSet && other.hashValueSet)
+            {
+                if (this.hashValue != other.hashValue)
+                {
+                    return false;
+                }
+            }
+
+            return this.c.equals(other.c);
+        }
+
+        return super.equals(o);
+    }
+
+    public synchronized int hashCode()
+    {
+        if (!hashValueSet)
+        {
+            hashValue = super.hashCode();
+            hashValueSet = true;
+        }
+
+        return hashValue;
+    }
+
+    /**
+     * Returns the original hash code for Certificates pre-JDK 1.8.
+     *
+     * @return the pre-JDK 1.8 hashcode calculation.
+     */
+    public int originalHashCode()
+    {
+        try
+        {
+            int hashCode = 0;
+            byte[] certData = this.getEncoded();
+            for (int i = 1; i < certData.length; i++)
+            {
+                 hashCode += certData[i] * i;
+            }
+            return hashCode;
+        }
+        catch (CertificateEncodingException e)
+        {
+            return 0;
+        }
+    }
+
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable        attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        ASN1ObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = Strings.lineSeparator();
+
+        buf.append("  [0]         Version: ").append(this.getVersion()).append(nl);
+        buf.append("         SerialNumber: ").append(this.getSerialNumber()).append(nl);
+        buf.append("             IssuerDN: ").append(this.getIssuerDN()).append(nl);
+        buf.append("           Start Date: ").append(this.getNotBefore()).append(nl);
+        buf.append("           Final Date: ").append(this.getNotAfter()).append(nl);
+        buf.append("            SubjectDN: ").append(this.getSubjectDN()).append(nl);
+        buf.append("           Public Key: ").append(this.getPublicKey()).append(nl);
+        buf.append("  Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
+
+        byte[]  sig = this.getSignature();
+
+        buf.append("            Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
+        for (int i = 20; i < sig.length; i += 20)
+        {
+            if (i < sig.length - 20)
+            {
+                buf.append("                       ").append(new String(Hex.encode(sig, i, 20))).append(nl);
+            }
+            else
+            {
+                buf.append("                       ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+            }
+        }
+
+        Extensions extensions = c.getTBSCertificate().getExtensions();
+
+        if (extensions != null)
+        {
+            Enumeration     e = extensions.oids();
+
+            if (e.hasMoreElements())
+            {
+                buf.append("       Extensions: \n");
+            }
+
+            while (e.hasMoreElements())
+            {
+                ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)e.nextElement();
+                Extension ext = extensions.getExtension(oid);
+
+                if (ext.getExtnValue() != null)
+                {
+                    byte[]                  octs = ext.getExtnValue().getOctets();
+                    ASN1InputStream         dIn = new ASN1InputStream(octs);
+                    buf.append("                       critical(").append(ext.isCritical()).append(") ");
+                    try
+                    {
+                        if (oid.equals(Extension.basicConstraints))
+                        {
+                            buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(Extension.keyUsage))
+                        {
+                            buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
+                        {
+                            buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
+                        {
+                            buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
+                        {
+                            buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
+                        }
+                        else 
+                        {
+                            buf.append(oid.getId());
+                            buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+                            //buf.append(" value = ").append("*****").append(nl);
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        buf.append(oid.getId());
+                   //     buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl);
+                        buf.append(" value = ").append("*****").append(nl);
+                    }
+                }
+                else
+                {
+                    buf.append(nl);
+                }
+            }
+        }
+
+        return buf.toString();
+    }
+
+    public final void verify(
+        PublicKey   key)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        Signature   signature;
+        String      sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+        
+        try
+        {
+            signature = bcHelper.createSignature(sigName);
+        }
+        catch (Exception e)
+        {
+            signature = Signature.getInstance(sigName);
+        }
+        
+        checkSignature(key, signature);
+    }
+    
+    public final void verify(
+        PublicKey   key,
+        String      sigProvider)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        String    sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+        Signature signature;
+
+        if (sigProvider != null)
+        {
+            signature = Signature.getInstance(sigName, sigProvider);
+        }
+        else
+        {
+            signature = Signature.getInstance(sigName);
+        }
+        
+        checkSignature(key, signature);
+    }
+
+    public final void verify(
+        PublicKey   key,
+        Provider sigProvider)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, SignatureException
+    {
+        String    sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+        Signature signature;
+
+        if (sigProvider != null)
+        {
+            signature = Signature.getInstance(sigName, sigProvider);
+        }
+        else
+        {
+            signature = Signature.getInstance(sigName);
+        }
+
+        checkSignature(key, signature);
+    }
+
+    private void checkSignature(
+        PublicKey key, 
+        Signature signature) 
+        throws CertificateException, NoSuchAlgorithmException, 
+            SignatureException, InvalidKeyException
+    {
+        if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
+        {
+            throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+        }
+
+        ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
+
+        // TODO This should go after the initVerify?
+        X509SignatureUtil.setSignatureParameters(signature, params);
+
+        signature.initVerify(key);
+
+        signature.update(this.getTBSCertificate());
+
+        if (!signature.verify(this.getSignature()))
+        {
+            throw new SignatureException("certificate does not verify with supplied key");
+        }
+    }
+
+    private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+    {
+        if (!id1.getAlgorithm().equals(id2.getAlgorithm()))
+        {
+            return false;
+        }
+
+        if (id1.getParameters() == null)
+        {
+            if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        if (id2.getParameters() == null)
+        {
+            if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
+            {
+                return false;
+            }
+
+            return true;
+        }
+        
+        return id1.getParameters().equals(id2.getParameters());
+    }
+
+    private static Collection getAlternativeNames(byte[] extVal)
+        throws CertificateParsingException
+    {
+        if (extVal == null)
+        {
+            return null;
+        }
+        try
+        {
+            Collection temp = new ArrayList();
+            Enumeration it = ASN1Sequence.getInstance(extVal).getObjects();
+            while (it.hasMoreElements())
+            {
+                GeneralName genName = GeneralName.getInstance(it.nextElement());
+                List list = new ArrayList();
+                list.add(Integers.valueOf(genName.getTagNo()));
+                switch (genName.getTagNo())
+                {
+                case GeneralName.ediPartyName:
+                case GeneralName.x400Address:
+                case GeneralName.otherName:
+                    list.add(genName.getEncoded());
+                    break;
+                case GeneralName.directoryName:
+                    // Android-changed: Unknown reason
+                    // list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString());
+                    list.add(X509Name.getInstance(genName.getName()).toString(true, X509Name.DefaultSymbols));
+                    break;
+                case GeneralName.dNSName:
+                case GeneralName.rfc822Name:
+                case GeneralName.uniformResourceIdentifier:
+                    list.add(((ASN1String)genName.getName()).getString());
+                    break;
+                case GeneralName.registeredID:
+                    list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+                    break;
+                case GeneralName.iPAddress:
+                    byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets();
+                    final String addr;
+                    try
+                    {
+                        addr = InetAddress.getByAddress(addrBytes).getHostAddress();
+                    }
+                    catch (UnknownHostException e)
+                    {
+                        continue;
+                    }
+                    list.add(addr);
+                    break;
+                default:
+                    throw new IOException("Bad tag number: " + genName.getTagNo());
+                }
+
+                temp.add(Collections.unmodifiableList(list));
+            }
+            if (temp.size() == 0)
+            {
+                return null;
+            }
+            return Collections.unmodifiableCollection(temp);
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException(e.getMessage());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
new file mode 100644
index 0000000..5401cc6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
@@ -0,0 +1,130 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.PSSParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Null;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.jcajce.util.MessageDigestUtils;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+class X509SignatureUtil
+{
+    private static final ASN1Null       derNull = DERNull.INSTANCE;
+
+    static void setSignatureParameters(
+        Signature signature,
+        ASN1Encodable params)
+        throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        if (params != null && !derNull.equals(params))
+        {
+            AlgorithmParameters  sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+            
+            try
+            {
+                sigParams.init(params.toASN1Primitive().getEncoded());
+            }
+            catch (IOException e)
+            {
+                throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+            }
+            
+            if (signature.getAlgorithm().endsWith("MGF1"))
+            {
+                try
+                {
+                    signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+                }
+                catch (GeneralSecurityException e)
+                {
+                    throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+                }
+            }
+        }
+    }
+    
+    static String getSignatureName(
+        AlgorithmIdentifier sigAlgId) 
+    {
+        ASN1Encodable params = sigAlgId.getParameters();
+        
+        if (params != null && !derNull.equals(params))
+        {
+            if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+            {
+                RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+                
+                return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1";
+            }
+            if (sigAlgId.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA2))
+            {
+                ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params);
+                
+                return getDigestAlgName((ASN1ObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA";
+            }
+        }
+
+        Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
+
+        if (prov != null)
+        {
+            String      algName = prov.getProperty("Alg.Alias.Signature." + sigAlgId.getAlgorithm().getId());
+
+            if (algName != null)
+            {
+                return algName;
+            }
+        }
+
+        Provider[] provs = Security.getProviders();
+
+        //
+        // search every provider looking for a real algorithm
+        //
+        for (int i = 0; i != provs.length; i++)
+        {
+            String algName = provs[i].getProperty("Alg.Alias.Signature." + sigAlgId.getAlgorithm().getId());
+            if (algName != null)
+            {
+                return algName;
+            }
+        }
+
+        return sigAlgId.getAlgorithm().getId();
+    }
+    
+    /**
+     * Return the digest algorithm using one of the standard JCA string
+     * representations rather the the algorithm identifier (if possible).
+     */
+    private static String getDigestAlgName(
+        ASN1ObjectIdentifier digestAlgOID)
+    {
+        String name = MessageDigestUtils.getDigestName(digestAlgOID);
+
+        int dIndex = name.indexOf('-');
+        if (dIndex > 0 && !name.startsWith("SHA3"))
+        {
+            return name.substring(0, dIndex) + name.substring(dIndex + 1);
+        }
+
+        return MessageDigestUtils.getDigestName(digestAlgOID);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
new file mode 100644
index 0000000..bedc241
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
@@ -0,0 +1,57 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.config;
+
+import java.util.Map;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+/**
+ * Implemented by the BC provider. This allows setting of hidden parameters,
+ * such as the ImplicitCA parameters from X.962, if used.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ConfigurableProvider
+{
+    /**
+     * Elliptic Curve CA parameters - thread local version
+     */
+    static final String THREAD_LOCAL_EC_IMPLICITLY_CA = "threadLocalEcImplicitlyCa";
+
+    /**
+     * Elliptic Curve CA parameters - VM wide version
+     */
+    static final String EC_IMPLICITLY_CA = "ecImplicitlyCa";
+
+    /**
+     * Diffie-Hellman Default Parameters - thread local version
+     */
+    static final String THREAD_LOCAL_DH_DEFAULT_PARAMS = "threadLocalDhDefaultParams";
+
+    /**
+     * Diffie-Hellman Default Parameters - VM wide version
+     */
+    static final String DH_DEFAULT_PARAMS = "DhDefaultParams";
+
+    /**
+     * A set of OBJECT IDENTIFIERs representing acceptable named curves for imported keys.
+     */
+    static final String ACCEPTABLE_EC_CURVES = "acceptableEcCurves";
+
+    /**
+     * A set of OBJECT IDENTIFIERs to EC Curves providing local curve name mapping.
+     */
+    static final String ADDITIONAL_EC_PARAMETERS = "additionalEcParameters";
+
+    void setParameter(String parameterName, Object parameter);
+
+    void addAlgorithm(String key, String value);
+
+    void addAlgorithm(String type, ASN1ObjectIdentifier oid, String className);
+
+    boolean hasAlgorithm(String type, String name);
+
+    void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter);
+
+    void addAttributes(String key, Map<String, String> attributeMap);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/PKCS12StoreParameter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/PKCS12StoreParameter.java
new file mode 100644
index 0000000..67eaff2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/PKCS12StoreParameter.java
@@ -0,0 +1,34 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.config;
+
+import java.io.OutputStream;
+import java.security.KeyStore;
+import java.security.KeyStore.ProtectionParameter;
+
+/**
+ * @deprecated use org.bouncycastle.jcajce.PKCS12StoreParameter
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS12StoreParameter
+    extends com.android.internal.org.bouncycastle.jcajce.PKCS12StoreParameter
+{
+    public PKCS12StoreParameter(OutputStream out, char[] password)
+    {
+        super(out, password, false);
+    }
+
+    public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter)
+    {
+        super(out, protectionParameter, false);
+    }
+
+    public PKCS12StoreParameter(OutputStream out, char[] password, boolean forDEREncoding)
+    {
+        super(out, new KeyStore.PasswordProtection(password), forDEREncoding);
+    }
+
+    public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter, boolean forDEREncoding)
+    {
+        super(out, protectionParameter, forDEREncoding);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java
new file mode 100644
index 0000000..ccca505
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java
@@ -0,0 +1,26 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.config;
+
+import java.security.spec.DSAParameterSpec;
+import java.util.Map;
+import java.util.Set;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ProviderConfiguration
+{
+    ECParameterSpec getEcImplicitlyCa();
+
+    DHParameterSpec getDHDefaultParameters(int keySize);
+
+    DSAParameterSpec getDSADefaultParameters(int keySize);
+
+    Set getAcceptableNamedCurves();
+
+    Map getAdditionalECParameters();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java
new file mode 100644
index 0000000..ccb8327
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java
@@ -0,0 +1,161 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.config;
+
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.util.StringTokenizer;
+
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * A permission class to define what can be done with the ConfigurableProvider interface.
+ * <p>
+ * Available permissions are "threadLocalEcImplicitlyCa" and "ecImplicitlyCa" which allow the setting
+ * of the thread local and global ecImplicitlyCa parameters respectively.
+ * </p>
+ * <p>
+ * Examples:
+ * <ul>
+ * <li>ProviderConfigurationPermission("BC"); // enable all permissions</li>
+ * <li>ProviderConfigurationPermission("BC", "threadLocalEcImplicitlyCa"); // enable thread local only</li>
+ * <li>ProviderConfigurationPermission("BC", "ecImplicitlyCa"); // enable global setting only</li>
+ * <li>ProviderConfigurationPermission("BC", "threadLocalEcImplicitlyCa, ecImplicitlyCa"); // enable both explicitly</li>
+ * </ul>
+ * <p>
+ * Note: permission checks are only enforced if a security manager is present.
+ * </p>
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ProviderConfigurationPermission
+    extends BasicPermission
+{
+    private static final int THREAD_LOCAL_EC_IMPLICITLY_CA = 0x01;
+    private static final int EC_IMPLICITLY_CA = 0x02;
+    private static final int THREAD_LOCAL_DH_DEFAULT_PARAMS = 0x04;
+    private static final int DH_DEFAULT_PARAMS = 0x08;
+    private static final int ACCEPTABLE_EC_CURVES = 0x10;
+    private static final int ADDITIONAL_EC_PARAMETERS = 0x20;
+
+    private static final int  ALL =
+            THREAD_LOCAL_EC_IMPLICITLY_CA | EC_IMPLICITLY_CA | THREAD_LOCAL_DH_DEFAULT_PARAMS | DH_DEFAULT_PARAMS |
+            ACCEPTABLE_EC_CURVES | ADDITIONAL_EC_PARAMETERS;
+
+    private static final String THREAD_LOCAL_EC_IMPLICITLY_CA_STR = "threadlocalecimplicitlyca";
+    private static final String EC_IMPLICITLY_CA_STR = "ecimplicitlyca";
+    private static final String THREAD_LOCAL_DH_DEFAULT_PARAMS_STR = "threadlocaldhdefaultparams";
+    private static final String DH_DEFAULT_PARAMS_STR = "dhdefaultparams";
+    private static final String ACCEPTABLE_EC_CURVES_STR = "acceptableeccurves";
+    private static final String ADDITIONAL_EC_PARAMETERS_STR = "additionalecparameters";
+    private static final String ALL_STR = "all";
+
+    private final String actions;
+    private final int permissionMask;
+
+    public ProviderConfigurationPermission(String name)
+    {
+        super(name);
+        this.actions = "all";
+        this.permissionMask = ALL;
+    }
+
+    public ProviderConfigurationPermission(String name, String actions)
+    {
+        super(name, actions);
+        this.actions = actions;
+        this.permissionMask = calculateMask(actions);
+    }
+
+    private int calculateMask(
+        String actions)
+    {
+        StringTokenizer tok = new StringTokenizer(Strings.toLowerCase(actions), " ,");
+        int             mask = 0;
+
+        while (tok.hasMoreTokens())
+        {
+            String s = tok.nextToken();
+
+            if (s.equals(THREAD_LOCAL_EC_IMPLICITLY_CA_STR))
+            {
+                mask |= THREAD_LOCAL_EC_IMPLICITLY_CA;
+            }
+            else if (s.equals(EC_IMPLICITLY_CA_STR))
+            {
+                mask |= EC_IMPLICITLY_CA;
+            }
+            else if (s.equals(THREAD_LOCAL_DH_DEFAULT_PARAMS_STR))
+            {
+                mask |= THREAD_LOCAL_DH_DEFAULT_PARAMS;
+            }
+            else if (s.equals(DH_DEFAULT_PARAMS_STR))
+            {
+                mask |= DH_DEFAULT_PARAMS;
+            }
+            else if (s.equals(ACCEPTABLE_EC_CURVES_STR))
+            {
+                mask |= ACCEPTABLE_EC_CURVES;
+            }
+            else if (s.equals(ADDITIONAL_EC_PARAMETERS_STR))
+            {
+                mask |= ADDITIONAL_EC_PARAMETERS;
+            }
+            else if (s.equals(ALL_STR))
+            {
+                mask |= ALL;
+            }
+        }
+
+        if (mask == 0)
+        {
+            throw new IllegalArgumentException("unknown permissions passed to mask");
+        }
+        
+        return mask;
+    }
+
+    public String getActions()
+    {
+        return actions;
+    }
+
+    public boolean implies(
+        Permission permission)
+    {
+        if (!(permission instanceof ProviderConfigurationPermission))
+        {
+            return false;
+        }
+
+        if (!this.getName().equals(permission.getName()))
+        {
+            return false;
+        }
+        
+        ProviderConfigurationPermission other = (ProviderConfigurationPermission)permission;
+        
+        return (this.permissionMask & other.permissionMask) == other.permissionMask;
+    }
+
+    public boolean equals(
+        Object obj)
+    {
+        if (obj == this)
+        {
+            return true;
+        }
+
+        if (obj instanceof ProviderConfigurationPermission)
+        {
+            ProviderConfigurationPermission other = (ProviderConfigurationPermission)obj;
+
+            return this.permissionMask == other.permissionMask && this.getName().equals(other.getName());
+        }
+
+        return false;
+    }
+
+    public int hashCode()
+    {
+        return this.getName().hashCode() + this.permissionMask;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/BCMessageDigest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/BCMessageDigest.java
new file mode 100644
index 0000000..a2d23a4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/BCMessageDigest.java
@@ -0,0 +1,51 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.digest;
+
+import java.security.MessageDigest;
+
+import com.android.internal.org.bouncycastle.crypto.Digest;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCMessageDigest
+    extends MessageDigest
+{
+    protected Digest  digest;
+
+    protected BCMessageDigest(
+        Digest digest)
+    {
+        super(digest.getAlgorithmName());
+
+        this.digest = digest;
+    }
+
+    public void engineReset() 
+    {
+        digest.reset();
+    }
+
+    public void engineUpdate(
+        byte    input) 
+    {
+        digest.update(input);
+    }
+
+    public void engineUpdate(
+        byte[]  input,
+        int     offset,
+        int     len) 
+    {
+        digest.update(input, offset, len);
+    }
+
+    public byte[] engineDigest() 
+    {
+        byte[]  digestBytes = new byte[digest.getDigestSize()];
+
+        digest.doFinal(digestBytes, 0);
+
+        return digestBytes;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/DigestAlgorithmProvider.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/DigestAlgorithmProvider.java
new file mode 100644
index 0000000..b89a44e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/DigestAlgorithmProvider.java
@@ -0,0 +1,37 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.digest;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+abstract class DigestAlgorithmProvider
+    extends AlgorithmProvider
+{
+    protected void addHMACAlgorithm(
+        ConfigurableProvider provider,
+        String algorithm,
+        String algorithmClassName,
+        String keyGeneratorClassName)
+    {
+        String mainName = "HMAC" + algorithm;
+
+        provider.addAlgorithm("Mac." + mainName, algorithmClassName);
+        provider.addAlgorithm("Alg.Alias.Mac.HMAC-" + algorithm, mainName);
+        provider.addAlgorithm("Alg.Alias.Mac.HMAC/" + algorithm, mainName);
+        provider.addAlgorithm("KeyGenerator." + mainName, keyGeneratorClassName);
+        provider.addAlgorithm("Alg.Alias.KeyGenerator.HMAC-" + algorithm, mainName);
+        provider.addAlgorithm("Alg.Alias.KeyGenerator.HMAC/" + algorithm, mainName);
+    }
+
+    protected void addHMACAlias(
+        ConfigurableProvider provider,
+        String algorithm,
+        ASN1ObjectIdentifier oid)
+    {
+        String mainName = "HMAC" + algorithm;
+
+        provider.addAlgorithm("Alg.Alias.Mac." + oid, mainName);
+        provider.addAlgorithm("Alg.Alias.KeyGenerator." + oid, mainName);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/MD5.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/MD5.java
new file mode 100644
index 0000000..86584a1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/MD5.java
@@ -0,0 +1,95 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.digest;
+
+import com.android.internal.org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.digests.MD5Digest;
+import com.android.internal.org.bouncycastle.crypto.macs.HMac;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class MD5
+{
+    private MD5()
+    {
+
+    }
+
+    /**
+     * MD5 HashMac
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class HashMac
+        extends BaseMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new MD5Digest()));
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACMD5", 128, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new MD5Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new MD5Digest((MD5Digest)digest);
+
+            return d;
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = MD5.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN Android-removed: Unsupported algorithm
+            /*
+            provider.addAlgorithm("MessageDigest.MD5", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md5, "MD5");
+
+            addHMACAlgorithm(provider, "MD5", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "MD5", IANAObjectIdentifiers.hmacMD5);
+            */
+            // END Android-removed: Unsupported algorithm
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA1.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA1.java
new file mode 100644
index 0000000..da2136d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA1.java
@@ -0,0 +1,134 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.digest;
+
+import com.android.internal.org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.digests.SHA1Digest;
+import com.android.internal.org.bouncycastle.crypto.macs.HMac;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SHA1
+{
+    private SHA1()
+    {
+
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new SHA1Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new SHA1Digest((SHA1Digest)digest);
+
+            return d;
+        }
+    }
+
+    /**
+     * SHA1 HMac
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class HashMac
+        extends BaseMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new SHA1Digest()));
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACSHA1", 160, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * SHA1 HMac
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class SHA1Mac
+        extends BaseMac
+    {
+        public SHA1Mac()
+        {
+            super(new HMac(new SHA1Digest()));
+        }
+    }
+
+    /**
+     * PBEWithHmacSHA
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithMacKeyFactory
+        extends PBESecretKeyFactory
+    {
+        public PBEWithMacKeyFactory()
+        {
+            super("PBEwithHmacSHA", null, false, PKCS12, SHA1, 160, 0);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = SHA1.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN Android-removed: Unsupported algorithm
+            /*
+            provider.addAlgorithm("MessageDigest.SHA-1", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA", "SHA-1");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + OIWObjectIdentifiers.idSHA1, "SHA-1");
+
+            addHMACAlgorithm(provider, "SHA1", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "SHA1", PKCSObjectIdentifiers.id_hmacWithSHA1);
+            addHMACAlias(provider, "SHA1", IANAObjectIdentifiers.hmacSHA1);
+            */
+            // END Android-removed: Unsupported algorithm
+
+            provider.addAlgorithm("Mac.PBEWITHHMACSHA", PREFIX + "$SHA1Mac");
+            provider.addAlgorithm("Mac.PBEWITHHMACSHA1", PREFIX + "$SHA1Mac");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHHMACSHA", "PBEWITHHMACSHA1");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + OIWObjectIdentifiers.idSHA1, "PBEWITHHMACSHA1");
+            provider.addAlgorithm("Alg.Alias.Mac." + OIWObjectIdentifiers.idSHA1, "PBEWITHHMACSHA");
+
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACSHA1", PREFIX + "$PBEWithMacKeyFactory");
+          }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA224.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA224.java
new file mode 100644
index 0000000..5b5d951
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA224.java
@@ -0,0 +1,97 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.digest;
+
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.digests.SHA224Digest;
+import com.android.internal.org.bouncycastle.crypto.macs.HMac;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SHA224
+{
+    private SHA224()
+    {
+
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new SHA224Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new SHA224Digest((SHA224Digest)digest);
+
+            return d;
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class HashMac
+        extends BaseMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new SHA224Digest()));
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACSHA224", 224, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = SHA224.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("MessageDigest.SHA-224", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA224", "SHA-224");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha224, "SHA-224");
+
+            provider.addAlgorithm("Mac.PBEWITHHMACSHA224", PREFIX + "$HashMac");
+            
+            addHMACAlgorithm(provider, "SHA224", PREFIX + "$HashMac",  PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA256.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA256.java
new file mode 100644
index 0000000..929364f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA256.java
@@ -0,0 +1,120 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.digest;
+
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.digests.SHA256Digest;
+import com.android.internal.org.bouncycastle.crypto.macs.HMac;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SHA256
+{
+    private SHA256()
+    {
+
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new SHA256Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new SHA256Digest((SHA256Digest)digest);
+
+            return d;
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class HashMac
+        extends BaseMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new SHA256Digest()));
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    /**
+     * PBEWithHmacSHA
+     *
+    public static class PBEWithMacKeyFactory
+        extends PBESecretKeyFactory
+    {
+        public PBEWithMacKeyFactory()
+        {
+            super("PBEwithHmacSHA256", null, false, PKCS12, SHA256, 256, 0);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * HMACSHA256
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACSHA256", 256, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = SHA256.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("MessageDigest.SHA-256", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA256", "SHA-256");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha256, "SHA-256");
+
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACSHA256", PREFIX + "$PBEWithMacKeyFactory");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHHMACSHA-256", "PBEWITHHMACSHA256");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + NISTObjectIdentifiers.id_sha256, "PBEWITHHMACSHA256");
+
+            provider.addAlgorithm("Mac.PBEWITHHMACSHA256", PREFIX + "$HashMac");
+
+            addHMACAlgorithm(provider, "SHA256", PREFIX + "$HashMac",  PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
+            addHMACAlias(provider, "SHA256", NISTObjectIdentifiers.id_sha256);
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA384.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA384.java
new file mode 100644
index 0000000..89d1443
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA384.java
@@ -0,0 +1,114 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.digest;
+
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.digests.SHA384Digest;
+import com.android.internal.org.bouncycastle.crypto.macs.HMac;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.macs.OldHMac;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SHA384
+{
+    private SHA384()
+    {
+
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new SHA384Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new SHA384Digest((SHA384Digest)digest);
+
+            return d;
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class HashMac
+        extends BaseMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new SHA384Digest()));
+        }
+    }
+
+    /**
+     * HMACSHA384
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACSHA384", 384, new CipherKeyGenerator());
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class OldSHA384
+        extends BaseMac
+    {
+        public OldSHA384()
+        {
+            super(new OldHMac(new SHA384Digest()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = SHA384.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("MessageDigest.SHA-384", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA384", "SHA-384");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha384, "SHA-384");
+            provider.addAlgorithm("Mac.OLDHMACSHA384", PREFIX + "$OldSHA384");
+
+            provider.addAlgorithm("Mac.PBEWITHHMACSHA384", PREFIX + "$HashMac");
+
+            addHMACAlgorithm(provider, "SHA384", PREFIX + "$HashMac",  PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA512.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA512.java
new file mode 100644
index 0000000..b726dbf
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/digest/SHA512.java
@@ -0,0 +1,213 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.digest;
+
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.digests.SHA512Digest;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.digests.SHA512tDigest;
+import com.android.internal.org.bouncycastle.crypto.macs.HMac;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.macs.OldHMac;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SHA512
+{
+    private SHA512()
+    {
+
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new SHA512Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new SHA512Digest((SHA512Digest)digest);
+
+            return d;
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    static public class DigestT
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public DigestT(int bitLength)
+        {
+            super(new SHA512tDigest(bitLength));
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            DigestT d = (DigestT)super.clone();
+            d.digest = new SHA512tDigest((SHA512tDigest)digest);
+
+            return d;
+        }
+    }
+
+    static public class DigestT224
+        extends DigestT
+    {
+        public DigestT224()
+        {
+            super(224);
+        }
+    }
+
+    static public class DigestT256
+        extends DigestT
+    {
+        public DigestT256()
+        {
+            super(256);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class HashMac
+        extends BaseMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new SHA512Digest()));
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class HashMacT224
+        extends BaseMac
+    {
+        public HashMacT224()
+        {
+            super(new HMac(new SHA512tDigest(224)));
+        }
+    }
+
+    public static class HashMacT256
+        extends BaseMac
+    {
+        public HashMacT256()
+        {
+            super(new HMac(new SHA512tDigest(256)));
+        }
+    }
+
+    /**
+     * SHA-512 HMac
+     *
+    public static class OldSHA512
+        extends BaseMac
+    {
+        public OldSHA512()
+        {
+            super(new OldHMac(new SHA512Digest()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * HMACSHA512
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACSHA512", 512, new CipherKeyGenerator());
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class KeyGeneratorT224
+        extends BaseKeyGenerator
+    {
+        public KeyGeneratorT224()
+        {
+            super("HMACSHA512/224", 224, new CipherKeyGenerator());
+        }
+    }
+
+    public static class KeyGeneratorT256
+        extends BaseKeyGenerator
+    {
+        public KeyGeneratorT256()
+        {
+            super("HMACSHA512/256", 256, new CipherKeyGenerator());
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = SHA512.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("MessageDigest.SHA-512", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA512", "SHA-512");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512, "SHA-512");
+
+            provider.addAlgorithm("MessageDigest.SHA-512/224", PREFIX + "$DigestT224");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA512/224", "SHA-512/224");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512_224, "SHA-512/224");
+
+            provider.addAlgorithm("MessageDigest.SHA-512/256", PREFIX + "$DigestT256");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA512256", "SHA-512/256");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512_256, "SHA-512/256");
+
+            provider.addAlgorithm("Mac.OLDHMACSHA512", PREFIX + "$OldSHA512");
+
+            provider.addAlgorithm("Mac.PBEWITHHMACSHA512", PREFIX + "$HashMac");
+
+            addHMACAlgorithm(provider, "SHA512", PREFIX + "$HashMac",  PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "SHA512", PKCSObjectIdentifiers.id_hmacWithSHA512);
+
+            addHMACAlgorithm(provider, "SHA512/224", PREFIX + "$HashMacT224",  PREFIX + "$KeyGeneratorT224");
+            addHMACAlgorithm(provider, "SHA512/256", PREFIX + "$HashMacT256",  PREFIX + "$KeyGeneratorT256");
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/BC.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/BC.java
new file mode 100644
index 0000000..1cfc616
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/BC.java
@@ -0,0 +1,35 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.keystore;
+
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BC
+{
+    private static final String PREFIX = "com.android.internal.org.bouncycastle.jcajce.provider.keystore" + ".bc.";
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("KeyStore.BKS", PREFIX + "BcKeyStoreSpi$Std");
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("KeyStore.BKS-V1", PREFIX + "BcKeyStoreSpi$Version1");
+            provider.addAlgorithm("KeyStore.BouncyCastle", PREFIX + "BcKeyStoreSpi$BouncyCastleStore");
+            provider.addAlgorithm("Alg.Alias.KeyStore.UBER", "BouncyCastle");
+            provider.addAlgorithm("Alg.Alias.KeyStore.BOUNCYCASTLE", "BouncyCastle");
+            provider.addAlgorithm("Alg.Alias.KeyStore.bouncycastle", "BouncyCastle");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/PKCS12.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/PKCS12.java
new file mode 100644
index 0000000..e0f800d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/PKCS12.java
@@ -0,0 +1,41 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.keystore;
+
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS12
+{
+    private static final String PREFIX = "com.android.internal.org.bouncycastle.jcajce.provider.keystore" + ".pkcs12.";
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AsymmetricAlgorithmProvider
+    {
+        public Mappings()
+        {
+        }
+        
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("KeyStore.PKCS12", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore");
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("KeyStore.BCPKCS12", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore");
+            provider.addAlgorithm("KeyStore.PKCS12-DEF", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStore");
+
+            provider.addAlgorithm("KeyStore.PKCS12-3DES-40RC2", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore");
+            provider.addAlgorithm("KeyStore.PKCS12-3DES-3DES", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore3DES");
+    
+            provider.addAlgorithm("KeyStore.PKCS12-DEF-3DES-40RC2", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStore");
+            provider.addAlgorithm("KeyStore.PKCS12-DEF-3DES-3DES", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStore3DES");
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java
new file mode 100644
index 0000000..62e8a43
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java
@@ -0,0 +1,1082 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.keystore.bc;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.PBEParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.digests.SHA1Digest;
+import com.android.internal.org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.io.DigestInputStream;
+import com.android.internal.org.bouncycastle.crypto.io.DigestOutputStream;
+import com.android.internal.org.bouncycastle.crypto.io.MacInputStream;
+import com.android.internal.org.bouncycastle.crypto.io.MacOutputStream;
+import com.android.internal.org.bouncycastle.crypto.macs.HMac;
+// Android-changed: Use default provider for JCA algorithms instead of BC
+// Was: import org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.jce.interfaces.BCKeyStore;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.io.Streams;
+import com.android.internal.org.bouncycastle.util.io.TeeOutputStream;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BcKeyStoreSpi
+    extends KeyStoreSpi
+    implements BCKeyStore
+{
+    private static final int    STORE_VERSION = 2;
+
+    private static final int    STORE_SALT_SIZE = 20;
+    private static final String STORE_CIPHER = "PBEWithSHAAndTwofish-CBC";
+
+    private static final int    KEY_SALT_SIZE = 20;
+    private static final int    MIN_ITERATIONS = 1024;
+
+    private static final String KEY_CIPHER = "PBEWithSHAAnd3-KeyTripleDES-CBC";
+
+    //
+    // generic object types
+    //
+    static final int NULL           = 0;
+    static final int CERTIFICATE    = 1;
+    static final int KEY            = 2;
+    static final int SECRET         = 3;
+    static final int SEALED         = 4;
+
+    //
+    // key types
+    //
+    static final int    KEY_PRIVATE = 0;
+    static final int    KEY_PUBLIC  = 1;
+    static final int    KEY_SECRET  = 2;
+
+    protected Hashtable       table = new Hashtable();
+
+    protected SecureRandom    random = CryptoServicesRegistrar.getSecureRandom();
+
+    protected int              version;
+
+    // Android-changed: Use default provider for JCA algorithms instead of BC
+    // Was: private final JcaJceHelper helper = new BCJcaJceHelper();
+    private final JcaJceHelper helper = new DefaultJcaJceHelper();
+
+    public BcKeyStoreSpi(int version)
+    {
+        this.version = version;
+    }
+
+    private class StoreEntry
+    {
+        int             type;
+        String          alias;
+        Object          obj;
+        Certificate[]   certChain;
+        Date            date = new Date();
+
+        StoreEntry(
+            String       alias,
+            Certificate  obj)
+        {
+            this.type = CERTIFICATE;
+            this.alias = alias;
+            this.obj = obj;
+            this.certChain = null;
+        }
+
+        StoreEntry(
+            String          alias,
+            byte[]          obj,
+            Certificate[]   certChain)
+        {
+            this.type = SECRET;
+            this.alias = alias;
+            this.obj = obj;
+            this.certChain = certChain;
+        }
+
+        StoreEntry(
+            String          alias,
+            Key             key,
+            char[]          password,
+            Certificate[]   certChain)
+            throws Exception
+        {
+            this.type = SEALED;
+            this.alias = alias;
+            this.certChain = certChain;
+
+            byte[] salt = new byte[KEY_SALT_SIZE];
+
+            random.setSeed(System.currentTimeMillis());
+            random.nextBytes(salt);
+
+            int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+
+
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DataOutputStream        dOut = new DataOutputStream(bOut);
+
+            dOut.writeInt(salt.length);
+            dOut.write(salt);
+            dOut.writeInt(iterationCount);
+
+            Cipher              cipher = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+            CipherOutputStream  cOut = new CipherOutputStream(dOut, cipher);
+
+            dOut = new DataOutputStream(cOut);
+
+            encodeKey(key, dOut);
+
+            dOut.close();
+
+            obj = bOut.toByteArray();
+        }
+
+        StoreEntry(
+            String          alias,
+            Date            date,
+            int             type,
+            Object          obj)
+        {
+            this.alias = alias;
+            this.date = date;
+            this.type = type;
+            this.obj = obj;
+        }
+
+        StoreEntry(
+            String          alias,
+            Date            date,
+            int             type,
+            Object          obj,
+            Certificate[]   certChain)
+        {
+            this.alias = alias;
+            this.date = date;
+            this.type = type;
+            this.obj = obj;
+            this.certChain = certChain;
+        }
+
+        int getType()
+        {
+            return type;
+        }
+
+        String getAlias()
+        {
+            return alias;
+        }
+
+        Object getObject()
+        {
+            return obj;
+        }
+
+        Object getObject(
+            char[]  password)
+            throws NoSuchAlgorithmException, UnrecoverableKeyException
+        {
+            if (password == null || password.length == 0)
+            {
+                if (obj instanceof Key)
+                {
+                    return obj;
+                }
+            }
+
+            if (type == SEALED)
+            {
+                ByteArrayInputStream    bIn = new ByteArrayInputStream((byte[])obj);
+                DataInputStream         dIn = new DataInputStream(bIn);
+            
+                try
+                {
+                    byte[]      salt = new byte[dIn.readInt()];
+
+                    dIn.readFully(salt);
+
+                    int     iterationCount = dIn.readInt();
+                
+                    Cipher      cipher = makePBECipher(KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+                    CipherInputStream cIn = new CipherInputStream(dIn, cipher);
+
+                    try
+                    {
+                        return decodeKey(new DataInputStream(cIn));
+                    }
+                    catch (Exception x)
+                    {
+                        bIn = new ByteArrayInputStream((byte[])obj);
+                        dIn = new DataInputStream(bIn);
+            
+                        salt = new byte[dIn.readInt()];
+
+                        dIn.readFully(salt);
+
+                        iterationCount = dIn.readInt();
+
+                        cipher = makePBECipher("Broken" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+                        cIn = new CipherInputStream(dIn, cipher);
+
+                        Key k = null;
+
+                        try
+                        {
+                            k = decodeKey(new DataInputStream(cIn));
+                        }
+                        catch (Exception y)
+                        {
+                            bIn = new ByteArrayInputStream((byte[])obj);
+                            dIn = new DataInputStream(bIn);
+                
+                            salt = new byte[dIn.readInt()];
+
+                            dIn.readFully(salt);
+
+                            iterationCount = dIn.readInt();
+
+                            cipher = makePBECipher("Old" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+                            cIn = new CipherInputStream(dIn, cipher);
+
+                            k = decodeKey(new DataInputStream(cIn));
+                        }
+
+                        //
+                        // reencrypt key with correct cipher.
+                        //
+                        if (k != null)
+                        {
+                            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+                            DataOutputStream        dOut = new DataOutputStream(bOut);
+
+                            dOut.writeInt(salt.length);
+                            dOut.write(salt);
+                            dOut.writeInt(iterationCount);
+
+                            Cipher              out = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+                            CipherOutputStream  cOut = new CipherOutputStream(dOut, out);
+
+                            dOut = new DataOutputStream(cOut);
+
+                            encodeKey(k, dOut);
+
+                            dOut.close();
+
+                            obj = bOut.toByteArray();
+
+                            return k;
+                        }
+                        else
+                        {
+                            throw new UnrecoverableKeyException("no match");
+                        }
+                    }
+                }
+                catch (Exception e)
+                {
+                    throw new UnrecoverableKeyException("no match");
+                }
+            }
+            else
+            {
+                throw new RuntimeException("forget something!");
+                // TODO
+                // if we get to here key was saved as byte data, which
+                // according to the docs means it must be a private key
+                // in EncryptedPrivateKeyInfo (PKCS8 format), later...
+                //
+            }
+        }
+
+        Certificate[] getCertificateChain()
+        {
+            return certChain;
+        }
+
+        Date getDate()
+        {
+            return date;
+        }
+    }
+
+    private void encodeCertificate(
+        Certificate         cert,
+        DataOutputStream    dOut)
+        throws IOException
+    {
+        try
+        {
+            byte[]      cEnc = cert.getEncoded();
+
+            dOut.writeUTF(cert.getType());
+            dOut.writeInt(cEnc.length);
+            dOut.write(cEnc);
+        }
+        catch (CertificateEncodingException ex)
+        {
+            throw new IOException(ex.toString());
+        }
+    }
+
+    private Certificate decodeCertificate(
+        DataInputStream   dIn)
+        throws IOException
+    {
+        String      type = dIn.readUTF();
+        byte[]      cEnc = new byte[dIn.readInt()];
+
+        dIn.readFully(cEnc);
+
+        try
+        {
+            CertificateFactory cFact = helper.createCertificateFactory(type);
+            ByteArrayInputStream bIn = new ByteArrayInputStream(cEnc);
+
+            return cFact.generateCertificate(bIn);
+        }
+        catch (NoSuchProviderException ex)
+        {
+            throw new IOException(ex.toString());
+        }
+        catch (CertificateException ex)
+        {
+            throw new IOException(ex.toString());
+        }
+    }
+
+    private void encodeKey(
+        Key                 key,
+        DataOutputStream    dOut)
+        throws IOException
+    {
+        byte[]      enc = key.getEncoded();
+
+        if (key instanceof PrivateKey)
+        {
+            dOut.write(KEY_PRIVATE);
+        }
+        else if (key instanceof PublicKey)
+        {
+            dOut.write(KEY_PUBLIC);
+        }
+        else
+        {
+            dOut.write(KEY_SECRET);
+        }
+    
+        dOut.writeUTF(key.getFormat());
+        dOut.writeUTF(key.getAlgorithm());
+        dOut.writeInt(enc.length);
+        dOut.write(enc);
+    }
+
+    private Key decodeKey(
+        DataInputStream dIn)
+        throws IOException
+    {
+        int         keyType = dIn.read();
+        String      format = dIn.readUTF();
+        String      algorithm = dIn.readUTF();
+        byte[]      enc = new byte[dIn.readInt()];
+        KeySpec     spec;
+
+        dIn.readFully(enc);
+
+        if (format.equals("PKCS#8") || format.equals("PKCS8"))
+        {
+            spec = new PKCS8EncodedKeySpec(enc);
+        }
+        else if (format.equals("X.509") || format.equals("X509"))
+        {
+            spec = new X509EncodedKeySpec(enc);
+        }
+        else if (format.equals("RAW"))
+        {
+            return new SecretKeySpec(enc, algorithm);
+        }
+        else
+        {
+            throw new IOException("Key format " + format + " not recognised!");
+        }
+
+        try
+        {
+            switch (keyType)
+            {
+            case KEY_PRIVATE:
+                return BouncyCastleProvider.getPrivateKey(PrivateKeyInfo.getInstance(enc));
+            case KEY_PUBLIC:
+                return  BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(enc));
+            case KEY_SECRET:
+                return  helper.createSecretKeyFactory(algorithm).generateSecret(spec);
+            default:
+                throw new IOException("Key type " + keyType + " not recognised!");
+            }
+        }
+        catch (Exception e)
+        {
+            throw new IOException("Exception creating key: " + e.toString());
+        }
+    }
+
+    protected Cipher makePBECipher(
+        String  algorithm,
+        int     mode,
+        char[]  password,
+        byte[]  salt,
+        int     iterationCount)
+        throws IOException
+    {
+        try
+        {
+            PBEKeySpec          pbeSpec = new PBEKeySpec(password);
+            SecretKeyFactory    keyFact = helper.createSecretKeyFactory(algorithm);
+            PBEParameterSpec    defParams = new PBEParameterSpec(salt, iterationCount);
+
+            Cipher cipher = helper.createCipher(algorithm);
+
+            cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams);
+
+            return cipher;
+        }
+        catch (Exception e)
+        {
+            throw new IOException("Error initialising store of key store: " + e);
+        }
+    }
+
+    public void setRandom(
+            SecureRandom    rand)
+    {
+        this.random = rand;
+    }
+
+    public Enumeration engineAliases() 
+    {
+        return table.keys();
+    }
+
+    public boolean engineContainsAlias(
+        String  alias) 
+    {
+        return (table.get(alias) != null);
+    }
+
+    public void engineDeleteEntry(
+        String  alias) 
+        throws KeyStoreException
+    {
+        Object  entry = table.get(alias);
+
+        if (entry == null)
+        {
+            return;
+        }
+
+        table.remove(alias);
+    }
+
+    public Certificate engineGetCertificate(
+        String alias) 
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null)
+        {
+            if (entry.getType() == CERTIFICATE)
+            {
+                return (Certificate)entry.getObject();
+            }
+            else
+            {
+                Certificate[]   chain = entry.getCertificateChain();
+
+                if (chain != null)
+                {
+                    return chain[0];
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public String engineGetCertificateAlias(
+        Certificate cert) 
+    {
+        Enumeration e = table.elements();
+        while (e.hasMoreElements())
+        {
+            StoreEntry  entry = (StoreEntry)e.nextElement();
+
+            if (entry.getObject() instanceof Certificate)
+            {
+                Certificate c = (Certificate)entry.getObject();
+
+                if (c.equals(cert))
+                {
+                    return entry.getAlias();
+                }
+            }
+            else
+            {
+                Certificate[]   chain = entry.getCertificateChain();
+
+                if (chain != null && chain[0].equals(cert))
+                {
+                    return entry.getAlias();
+                }
+            }
+        }
+
+        return null;
+    }
+    
+    public Certificate[] engineGetCertificateChain(
+        String alias) 
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null)
+        {
+            return entry.getCertificateChain();
+        }
+
+        return null;
+    }
+    
+    public Date engineGetCreationDate(String alias) 
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null)
+        {
+            return entry.getDate();
+        }
+
+        return null;
+    }
+
+    public Key engineGetKey(
+        String alias,
+        char[] password) 
+        throws NoSuchAlgorithmException, UnrecoverableKeyException
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry == null || entry.getType() == CERTIFICATE)
+        {
+            return null;
+        }
+
+        return (Key)entry.getObject(password);
+    }
+
+    public boolean engineIsCertificateEntry(
+        String alias) 
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null && entry.getType() == CERTIFICATE)
+        {
+            return true;
+        }
+    
+        return false;
+    }
+
+    public boolean engineIsKeyEntry(
+        String alias) 
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null && entry.getType() != CERTIFICATE)
+        {
+            return true;
+        }
+    
+        return false;
+    }
+
+    public void engineSetCertificateEntry(
+        String      alias,
+        Certificate cert) 
+        throws KeyStoreException
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null && entry.getType() != CERTIFICATE)
+        {
+            throw new KeyStoreException("key store already has a key entry with alias " + alias);
+        }
+
+        table.put(alias, new StoreEntry(alias, cert));
+    }
+
+    public void engineSetKeyEntry(
+        String alias,
+        byte[] key,
+        Certificate[] chain) 
+        throws KeyStoreException
+    {
+        table.put(alias, new StoreEntry(alias, key, chain));
+    }
+
+    public void engineSetKeyEntry(
+        String          alias,
+        Key             key,
+        char[]          password,
+        Certificate[]   chain) 
+        throws KeyStoreException
+    {
+        if ((key instanceof PrivateKey) && (chain == null))
+        {
+            throw new KeyStoreException("no certificate chain for private key");
+        }
+
+        try
+        {
+            table.put(alias, new StoreEntry(alias, key, password, chain));
+        }
+        catch (Exception e)
+        {
+            throw new KeyStoreException(e.toString());
+        }
+    }
+
+    public int engineSize() 
+    {
+        return table.size();
+    }
+
+    protected void loadStore(
+        InputStream in)
+        throws IOException
+    {
+        DataInputStream     dIn = new DataInputStream(in);
+        int                 type = dIn.read();
+
+        while (type > NULL)
+        {
+            String          alias = dIn.readUTF();
+            Date            date = new Date(dIn.readLong());
+            int             chainLength = dIn.readInt();
+            Certificate[]   chain = null;
+
+            if (chainLength != 0)
+            {
+                chain = new Certificate[chainLength];
+
+                for (int i = 0; i != chainLength; i++)
+                {
+                    chain[i] = decodeCertificate(dIn);
+                }
+            }
+
+            switch (type)
+            {
+            case CERTIFICATE:
+                    Certificate     cert = decodeCertificate(dIn);
+
+                    table.put(alias, new StoreEntry(alias, date, CERTIFICATE, cert));
+                    break;
+            case KEY:
+                    Key     key = decodeKey(dIn);
+                    table.put(alias, new StoreEntry(alias, date, KEY, key, chain));
+                    break;
+            case SECRET:
+            case SEALED:
+                    byte[]      b = new byte[dIn.readInt()];
+
+                    dIn.readFully(b);
+                    table.put(alias, new StoreEntry(alias, date, type, b, chain));
+                    break;
+            default:
+                    throw new IOException("Unknown object type in store.");
+            }
+
+            type = dIn.read();
+        }
+    }
+
+    protected void saveStore(
+        OutputStream    out)
+        throws IOException
+    {
+        Enumeration         e = table.elements();
+        DataOutputStream    dOut = new DataOutputStream(out);
+
+        while (e.hasMoreElements())
+        {
+            StoreEntry  entry = (StoreEntry)e.nextElement();
+
+            dOut.write(entry.getType());
+            dOut.writeUTF(entry.getAlias());
+            dOut.writeLong(entry.getDate().getTime());
+
+            Certificate[]   chain = entry.getCertificateChain();
+            if (chain == null)
+            {
+                dOut.writeInt(0);
+            }
+            else
+            {
+                dOut.writeInt(chain.length);
+                for (int i = 0; i != chain.length; i++)
+                {
+                    encodeCertificate(chain[i], dOut);
+                }
+            }
+
+            switch (entry.getType())
+            {
+            case CERTIFICATE:
+                    encodeCertificate((Certificate)entry.getObject(), dOut);
+                    break;
+            case KEY:
+                    encodeKey((Key)entry.getObject(), dOut);
+                    break;
+            case SEALED:
+            case SECRET:
+                    byte[]  b = (byte[])entry.getObject();
+
+                    dOut.writeInt(b.length);
+                    dOut.write(b);
+                    break;
+            default:
+                    throw new IOException("Unknown object type in store.");
+            }
+        }
+
+        dOut.write(NULL);
+    }
+
+    public void engineLoad(
+        InputStream stream,
+        char[]      password) 
+        throws IOException
+    {
+        table.clear();
+
+        if (stream == null)     // just initialising
+        {
+            return;
+        }
+
+        DataInputStream     dIn = new DataInputStream(stream);
+        int                 version = dIn.readInt();
+
+        if (version != STORE_VERSION)
+        {
+            if (version != 0 && version != 1)
+            {
+                throw new IOException("Wrong version of key store.");
+            }
+        }
+
+        int saltLength = dIn.readInt();
+        if (saltLength <= 0)
+        {
+            throw new IOException("Invalid salt detected");
+        }
+
+        byte[]      salt = new byte[saltLength];
+
+        dIn.readFully(salt);
+
+        int         iterationCount = dIn.readInt();
+
+        //
+        // we only do an integrity check if the password is provided.
+        //
+        HMac hMac = new HMac(new SHA1Digest());
+        if (password != null && password.length != 0)
+        {
+            byte[] passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
+
+            PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(new SHA1Digest());
+            pbeGen.init(passKey, salt, iterationCount);
+
+            CipherParameters macParams;
+
+            if (version != 2)
+            {
+                macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize());
+            }
+            else
+            {
+                macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8);
+            }
+
+            Arrays.fill(passKey, (byte)0);
+
+            hMac.init(macParams);
+            MacInputStream mIn = new MacInputStream(dIn, hMac);
+
+            loadStore(mIn);
+
+            // Finalise our mac calculation
+            byte[] mac = new byte[hMac.getMacSize()];
+            hMac.doFinal(mac, 0);
+
+            // TODO Should this actually be reading the remainder of the stream?
+            // Read the original mac from the stream
+            byte[] oldMac = new byte[hMac.getMacSize()];
+            dIn.readFully(oldMac);
+
+            if (!Arrays.constantTimeAreEqual(mac, oldMac))
+            {
+                table.clear();
+                throw new IOException("KeyStore integrity check failed.");
+            }
+        }
+        else
+        {
+            loadStore(dIn);
+
+            // TODO Should this actually be reading the remainder of the stream?
+            // Parse the original mac from the stream too
+            byte[] oldMac = new byte[hMac.getMacSize()];
+            dIn.readFully(oldMac);
+        }
+    }
+
+
+    public void engineStore(OutputStream stream, char[] password) 
+        throws IOException
+    {
+        DataOutputStream    dOut = new DataOutputStream(stream);
+        byte[]              salt = new byte[STORE_SALT_SIZE];
+        int                 iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+
+        random.nextBytes(salt);
+
+        dOut.writeInt(version);
+        dOut.writeInt(salt.length);
+        dOut.write(salt);
+        dOut.writeInt(iterationCount);
+
+        HMac                    hMac = new HMac(new SHA1Digest());
+        MacOutputStream         mOut = new MacOutputStream(hMac);
+        PBEParametersGenerator  pbeGen = new PKCS12ParametersGenerator(new SHA1Digest());
+        byte[]                  passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
+
+        pbeGen.init(passKey, salt, iterationCount);
+
+        if (version < 2)
+        {
+            hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize()));
+        }
+        else
+        {
+            hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8));
+        }
+
+        for (int i = 0; i != passKey.length; i++)
+        {
+            passKey[i] = 0;
+        }
+
+        saveStore(new TeeOutputStream(dOut, mOut));
+
+        byte[]  mac = new byte[hMac.getMacSize()];
+
+        hMac.doFinal(mac, 0);
+
+        dOut.write(mac);
+
+        dOut.close();
+    }
+
+    /**
+     * the BouncyCastle store. This wont work with the key tool as the
+     * store is stored encrypted on disk, so the password is mandatory,
+     * however if you hard drive is in a bad part of town and you absolutely,
+     * positively, don't want nobody peeking at your things, this is the
+     * one to use, no problem! After all in a Bouncy Castle nothing can
+     * touch you.
+     *
+     * Also referred to by the alias UBER.
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class BouncyCastleStore
+        extends BcKeyStoreSpi
+    {
+        public BouncyCastleStore()
+        {
+            super(1);
+        }
+
+        public void engineLoad(
+            InputStream stream,
+            char[]      password) 
+            throws IOException
+        {
+            table.clear();
+    
+            if (stream == null)     // just initialising
+            {
+                return;
+            }
+    
+            DataInputStream     dIn = new DataInputStream(stream);
+            int                 version = dIn.readInt();
+    
+            if (version != STORE_VERSION)
+            {
+                if (version != 0 && version != 1)
+                {
+                    throw new IOException("Wrong version of key store.");
+                }
+            }
+    
+            byte[]      salt = new byte[dIn.readInt()];
+
+            if (salt.length != STORE_SALT_SIZE)
+            {
+                throw new IOException("Key store corrupted.");
+            }
+    
+            dIn.readFully(salt);
+    
+            int         iterationCount = dIn.readInt();
+    
+            if ((iterationCount < 0) || (iterationCount > (MIN_ITERATIONS << 6)))
+            {
+                throw new IOException("Key store corrupted.");
+            }
+    
+            String cipherAlg;
+            if (version == 0)
+            {
+                cipherAlg = "Old" + STORE_CIPHER;
+            }
+            else
+            {
+                cipherAlg = STORE_CIPHER;
+            }
+
+            Cipher cipher = this.makePBECipher(cipherAlg, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+            CipherInputStream cIn = new CipherInputStream(dIn, cipher);
+
+            Digest dig = new SHA1Digest();
+            DigestInputStream  dgIn = new DigestInputStream(cIn, dig);
+    
+            this.loadStore(dgIn);
+
+            // Finalise our digest calculation
+            byte[] hash = new byte[dig.getDigestSize()];
+            dig.doFinal(hash, 0);
+
+            // TODO Should this actually be reading the remainder of the stream?
+            // Read the original digest from the stream
+            byte[] oldHash = new byte[dig.getDigestSize()];
+            Streams.readFully(cIn, oldHash);
+
+            if (!Arrays.constantTimeAreEqual(hash, oldHash))
+            {
+                table.clear();
+                throw new IOException("KeyStore integrity check failed.");
+            }
+        }
+
+        public void engineStore(OutputStream stream, char[] password) 
+            throws IOException
+        {
+            Cipher              cipher;
+            DataOutputStream    dOut = new DataOutputStream(stream);
+            byte[]              salt = new byte[STORE_SALT_SIZE];
+            int                 iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+    
+            random.nextBytes(salt);
+    
+            dOut.writeInt(version);
+            dOut.writeInt(salt.length);
+            dOut.write(salt);
+            dOut.writeInt(iterationCount);
+    
+            cipher = this.makePBECipher(STORE_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+    
+            CipherOutputStream  cOut = new CipherOutputStream(dOut, cipher);
+            DigestOutputStream  dgOut = new DigestOutputStream(new SHA1Digest());
+    
+            this.saveStore(new TeeOutputStream(cOut, dgOut));
+    
+            byte[]  dig = dgOut.getDigest();
+
+            cOut.write(dig);
+    
+            cOut.close();
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Std
+       extends BcKeyStoreSpi
+    {
+        public Std()
+        {
+            super(STORE_VERSION);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Version1
+        extends BcKeyStoreSpi
+    {
+        public Version1()
+        {
+            super(1);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
new file mode 100644
index 0000000..44c46e0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -0,0 +1,1889 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.keystore.pkcs12;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.ProtectionParameter;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.BEROctetString;
+import com.android.internal.org.bouncycastle.asn1.BEROutputStream;
+import com.android.internal.org.bouncycastle.asn1.DERBMPString;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DEROutputStream;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.DERSet;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// import org.bouncycastle.asn1.cryptopro.GOST28147Parameters;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+// import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
+import com.android.internal.org.bouncycastle.asn1.pkcs.CertBag;
+import com.android.internal.org.bouncycastle.asn1.pkcs.ContentInfo;
+import com.android.internal.org.bouncycastle.asn1.pkcs.EncryptedData;
+import com.android.internal.org.bouncycastle.asn1.pkcs.MacData;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PBES2Parameters;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PBKDF2Params;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.Pfx;
+import com.android.internal.org.bouncycastle.asn1.pkcs.SafeBag;
+import com.android.internal.org.bouncycastle.asn1.util.ASN1Dump;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.DigestInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+// Android-changed: Use Android digests
+// import org.bouncycastle.crypto.util.DigestFactory;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+import com.android.internal.org.bouncycastle.jcajce.PKCS12Key;
+import com.android.internal.org.bouncycastle.jcajce.PKCS12StoreParameter;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
+import com.android.internal.org.bouncycastle.jcajce.spec.PBKDF2KeySpec;
+import com.android.internal.org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.jce.interfaces.BCKeyStore;
+import com.android.internal.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.jce.provider.JDKPKCS12StoreParameter;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Integers;
+import com.android.internal.org.bouncycastle.util.Properties;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS12KeyStoreSpi
+    extends KeyStoreSpi
+    implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore
+{
+    static final String PKCS12_MAX_IT_COUNT_PROPERTY = "com.android.internal.org.bouncycastle.pkcs12.max_it_count";
+
+    // Android-changed: Use default provider for JCA algorithms instead of BC
+    // Was: private final JcaJceHelper helper = new BCJcaJceHelper();
+    private final JcaJceHelper helper = new DefaultJcaJceHelper();
+
+    private static final int SALT_SIZE = 20;
+    private static final int MIN_ITERATIONS = 50 * 1024;
+
+    private static final DefaultSecretKeyProvider keySizeProvider = new DefaultSecretKeyProvider();
+
+    private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
+    private Hashtable localIds = new Hashtable();
+    private IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
+    private Hashtable chainCerts = new Hashtable();
+    private Hashtable keyCerts = new Hashtable();
+
+    //
+    // generic object types
+    //
+    static final int NULL = 0;
+    static final int CERTIFICATE = 1;
+    static final int KEY = 2;
+    static final int SECRET = 3;
+    static final int SEALED = 4;
+
+    //
+    // key types
+    //
+    static final int KEY_PRIVATE = 0;
+    static final int KEY_PUBLIC = 1;
+    static final int KEY_SECRET = 2;
+
+    protected SecureRandom random = CryptoServicesRegistrar.getSecureRandom();
+
+    // use of final causes problems with JDK 1.2 compiler
+    private CertificateFactory certFact;
+    private ASN1ObjectIdentifier keyAlgorithm;
+    private ASN1ObjectIdentifier certAlgorithm;
+
+    private AlgorithmIdentifier macAlgorithm = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+    private int itCount = 2 * MIN_ITERATIONS;
+    private int saltLength = 20;
+
+    private class CertId
+    {
+        byte[] id;
+
+        CertId(
+            PublicKey key)
+        {
+            this.id = createSubjectKeyId(key).getKeyIdentifier();
+        }
+
+        CertId(
+            byte[] id)
+        {
+            this.id = id;
+        }
+
+        public int hashCode()
+        {
+            return Arrays.hashCode(id);
+        }
+
+        public boolean equals(
+            Object o)
+        {
+            if (o == this)
+            {
+                return true;
+            }
+
+            if (!(o instanceof CertId))
+            {
+                return false;
+            }
+
+            CertId cId = (CertId)o;
+
+            return Arrays.areEqual(id, cId.id);
+        }
+    }
+
+    public PKCS12KeyStoreSpi(
+        JcaJceHelper helper,
+        ASN1ObjectIdentifier keyAlgorithm,
+        ASN1ObjectIdentifier certAlgorithm)
+    {
+        this.keyAlgorithm = keyAlgorithm;
+        this.certAlgorithm = certAlgorithm;
+
+        try
+        {
+            certFact = helper.createCertificateFactory("X.509");
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("can't create cert factory - " + e.toString());
+        }
+    }
+
+    private SubjectKeyIdentifier createSubjectKeyId(
+        PublicKey pubKey)
+    {
+        try
+        {
+            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+
+            return new SubjectKeyIdentifier(getDigest(info));
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException("error creating key");
+        }
+    }
+
+    private static byte[] getDigest(SubjectPublicKeyInfo spki)
+    {
+        // Android-changed: Use Android digests
+        // Digest digest = DigestFactory.createSHA1();
+        Digest digest = AndroidDigestFactory.getSHA1();
+        byte[]  resBuf = new byte[digest.getDigestSize()];
+
+        byte[] bytes = spki.getPublicKeyData().getBytes();
+        digest.update(bytes, 0, bytes.length);
+        digest.doFinal(resBuf, 0);
+        return resBuf;
+    }
+
+    public void setRandom(
+        SecureRandom rand)
+    {
+        this.random = rand;
+    }
+
+    public Enumeration engineAliases()
+    {
+        Hashtable tab = new Hashtable();
+
+        Enumeration e = certs.keys();
+        while (e.hasMoreElements())
+        {
+            tab.put(e.nextElement(), "cert");
+        }
+
+        e = keys.keys();
+        while (e.hasMoreElements())
+        {
+            String a = (String)e.nextElement();
+            if (tab.get(a) == null)
+            {
+                tab.put(a, "key");
+            }
+        }
+
+        return tab.keys();
+    }
+
+    public boolean engineContainsAlias(
+        String alias)
+    {
+        return (certs.get(alias) != null || keys.get(alias) != null);
+    }
+
+    /**
+     * this is not quite complete - we should follow up on the chain, a bit
+     * tricky if a certificate appears in more than one chain... the store method
+     * now prunes out unused certificates from the chain map if they are present.
+     */
+    public void engineDeleteEntry(
+        String alias)
+        throws KeyStoreException
+    {
+        Key k = (Key)keys.remove(alias);
+
+        Certificate c = (Certificate)certs.remove(alias);
+
+        if (c != null)
+        {
+            chainCerts.remove(new CertId(c.getPublicKey()));
+        }
+
+        if (k != null)
+        {
+            String id = (String)localIds.remove(alias);
+            if (id != null)
+            {
+                c = (Certificate)keyCerts.remove(id);
+            }
+            if (c != null)
+            {
+                chainCerts.remove(new CertId(c.getPublicKey()));
+            }
+        }
+    }
+
+    /**
+     * simply return the cert for the private key
+     */
+    public Certificate engineGetCertificate(
+        String alias)
+    {
+        if (alias == null)
+        {
+            throw new IllegalArgumentException("null alias passed to getCertificate.");
+        }
+
+        Certificate c = (Certificate)certs.get(alias);
+
+        //
+        // look up the key table - and try the local key id
+        //
+        if (c == null)
+        {
+            String id = (String)localIds.get(alias);
+            if (id != null)
+            {
+                c = (Certificate)keyCerts.get(id);
+            }
+            else
+            {
+                c = (Certificate)keyCerts.get(alias);
+            }
+        }
+
+        return c;
+    }
+
+    public String engineGetCertificateAlias(
+        Certificate cert)
+    {
+        Enumeration c = certs.elements();
+        Enumeration k = certs.keys();
+
+        while (c.hasMoreElements())
+        {
+            Certificate tc = (Certificate)c.nextElement();
+            String ta = (String)k.nextElement();
+
+            if (tc.equals(cert))
+            {
+                return ta;
+            }
+        }
+
+        c = keyCerts.elements();
+        k = keyCerts.keys();
+
+        while (c.hasMoreElements())
+        {
+            Certificate tc = (Certificate)c.nextElement();
+            String ta = (String)k.nextElement();
+
+            if (tc.equals(cert))
+            {
+                return ta;
+            }
+        }
+
+        return null;
+    }
+
+    public Certificate[] engineGetCertificateChain(
+        String alias)
+    {
+        if (alias == null)
+        {
+            throw new IllegalArgumentException("null alias passed to getCertificateChain.");
+        }
+
+        if (!engineIsKeyEntry(alias))
+        {
+            return null;
+        }
+
+        Certificate c = engineGetCertificate(alias);
+
+        if (c != null)
+        {
+            Vector cs = new Vector();
+
+            while (c != null)
+            {
+                X509Certificate x509c = (X509Certificate)c;
+                Certificate nextC = null;
+
+                byte[] bytes = x509c.getExtensionValue(Extension.authorityKeyIdentifier.getId());
+                if (bytes != null)
+                {
+                    try
+                    {
+                        ASN1InputStream aIn = new ASN1InputStream(bytes);
+
+                        byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets();
+                        aIn = new ASN1InputStream(authBytes);
+
+                        AuthorityKeyIdentifier id = AuthorityKeyIdentifier.getInstance(aIn.readObject());
+                        if (id.getKeyIdentifier() != null)
+                        {
+                            nextC = (Certificate)chainCerts.get(new CertId(id.getKeyIdentifier()));
+                        }
+
+                    }
+                    catch (IOException e)
+                    {
+                        throw new RuntimeException(e.toString());
+                    }
+                }
+
+                if (nextC == null)
+                {
+                    //
+                    // no authority key id, try the Issuer DN
+                    //
+                    Principal i = x509c.getIssuerDN();
+                    Principal s = x509c.getSubjectDN();
+
+                    if (!i.equals(s))
+                    {
+                        Enumeration e = chainCerts.keys();
+
+                        while (e.hasMoreElements())
+                        {
+                            X509Certificate crt = (X509Certificate)chainCerts.get(e.nextElement());
+                            Principal sub = crt.getSubjectDN();
+                            if (sub.equals(i))
+                            {
+                                try
+                                {
+                                    x509c.verify(crt.getPublicKey());
+                                    nextC = crt;
+                                    break;
+                                }
+                                catch (Exception ex)
+                                {
+                                    // continue
+                                }
+                            }
+                        }
+                    }
+                }
+
+                if (cs.contains(c))
+                {
+                    c = null;          // we've got a certificate chain loop time to stop
+                }
+                else
+                {
+                    cs.addElement(c);
+                    if (nextC != c)     // self signed - end of the chain
+                    {
+                        c = nextC;
+                    }
+                    else
+                    {
+                        c = null;
+                    }
+                }
+            }
+
+            Certificate[] certChain = new Certificate[cs.size()];
+
+            for (int i = 0; i != certChain.length; i++)
+            {
+                certChain[i] = (Certificate)cs.elementAt(i);
+            }
+
+            return certChain;
+        }
+
+        return null;
+    }
+
+    public Date engineGetCreationDate(String alias)
+    {
+        if (alias == null)
+        {
+            throw new NullPointerException("alias == null");
+        }
+        if (keys.get(alias) == null && certs.get(alias) == null)
+        {
+            return null;
+        }
+        return new Date();
+    }
+
+    public Key engineGetKey(
+        String alias,
+        char[] password)
+        throws NoSuchAlgorithmException, UnrecoverableKeyException
+    {
+        if (alias == null)
+        {
+            throw new IllegalArgumentException("null alias passed to getKey.");
+        }
+
+        return (Key)keys.get(alias);
+    }
+
+    public boolean engineIsCertificateEntry(
+        String alias)
+    {
+        return (certs.get(alias) != null && keys.get(alias) == null);
+    }
+
+    public boolean engineIsKeyEntry(
+        String alias)
+    {
+        return (keys.get(alias) != null);
+    }
+
+    public void engineSetCertificateEntry(
+        String alias,
+        Certificate cert)
+        throws KeyStoreException
+    {
+        if (keys.get(alias) != null)
+        {
+            throw new KeyStoreException("There is a key entry with the name " + alias + ".");
+        }
+
+        certs.put(alias, cert);
+        chainCerts.put(new CertId(cert.getPublicKey()), cert);
+    }
+
+    public void engineSetKeyEntry(
+        String alias,
+        byte[] key,
+        Certificate[] chain)
+        throws KeyStoreException
+    {
+        throw new RuntimeException("operation not supported");
+    }
+
+    public void engineSetKeyEntry(
+        String alias,
+        Key key,
+        char[] password,
+        Certificate[] chain)
+        throws KeyStoreException
+    {
+        if (!(key instanceof PrivateKey))
+        {
+            throw new KeyStoreException("PKCS12 does not support non-PrivateKeys");
+        }
+
+        if ((key instanceof PrivateKey) && (chain == null))
+        {
+            throw new KeyStoreException("no certificate chain for private key");
+        }
+
+        if (keys.get(alias) != null)
+        {
+            engineDeleteEntry(alias);
+        }
+
+        keys.put(alias, key);
+        if (chain != null)
+        {
+            certs.put(alias, chain[0]);
+
+            for (int i = 0; i != chain.length; i++)
+            {
+                chainCerts.put(new CertId(chain[i].getPublicKey()), chain[i]);
+            }
+        }
+    }
+
+    public int engineSize()
+    {
+        Hashtable tab = new Hashtable();
+
+        Enumeration e = certs.keys();
+        while (e.hasMoreElements())
+        {
+            tab.put(e.nextElement(), "cert");
+        }
+
+        e = keys.keys();
+        while (e.hasMoreElements())
+        {
+            String a = (String)e.nextElement();
+            if (tab.get(a) == null)
+            {
+                tab.put(a, "key");
+            }
+        }
+
+        return tab.size();
+    }
+
+    protected PrivateKey unwrapKey(
+        AlgorithmIdentifier algId,
+        byte[] data,
+        char[] password,
+        boolean wrongPKCS12Zero)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
+        try
+        {
+            if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
+            {
+                PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+                PBEParameterSpec defParams = new PBEParameterSpec(
+                    pbeParams.getIV(),
+                    validateIterationCount(pbeParams.getIterations()));
+
+                Cipher cipher = helper.createCipher(algorithm.getId());
+
+                PKCS12Key key = new PKCS12Key(password, wrongPKCS12Zero);
+
+                cipher.init(Cipher.UNWRAP_MODE, key, defParams);
+
+                // we pass "" as the key algorithm type as it is unknown at this point
+                return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+            }
+            else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
+            {
+
+                Cipher cipher = createCipher(Cipher.UNWRAP_MODE, password, algId);
+
+                // we pass "" as the key algorithm type as it is unknown at this point
+                return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+            }
+        }
+        catch (Exception e)
+        {
+            throw new IOException("exception unwrapping private key - " + e.toString());
+        }
+
+        throw new IOException("exception unwrapping private key - cannot recognise: " + algorithm);
+    }
+
+    protected byte[] wrapKey(
+        String algorithm,
+        Key key,
+        PKCS12PBEParams pbeParams,
+        char[] password)
+        throws IOException
+    {
+        PBEKeySpec pbeSpec = new PBEKeySpec(password);
+        byte[] out;
+
+        try
+        {
+            SecretKeyFactory keyFact =  helper.createSecretKeyFactory(algorithm);
+            PBEParameterSpec defParams = new PBEParameterSpec(
+                pbeParams.getIV(),
+                pbeParams.getIterations().intValue());
+
+            Cipher cipher = helper.createCipher(algorithm);
+
+            cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), defParams);
+
+            out = cipher.wrap(key);
+        }
+        catch (Exception e)
+        {
+            throw new IOException("exception encrypting data - " + e.toString());
+        }
+
+        return out;
+    }
+
+    protected byte[] cryptData(
+        boolean forEncryption,
+        AlgorithmIdentifier algId,
+        char[] password,
+        boolean wrongPKCS12Zero,
+        byte[] data)
+        throws IOException
+    {
+        ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
+        int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+
+        if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
+        {
+            PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+            try
+            {
+                PBEParameterSpec defParams = new PBEParameterSpec(
+                    pbeParams.getIV(),
+                    pbeParams.getIterations().intValue());
+                PKCS12Key key = new PKCS12Key(password, wrongPKCS12Zero);
+
+                Cipher cipher = helper.createCipher(algorithm.getId());
+
+                cipher.init(mode, key, defParams);
+                return cipher.doFinal(data);
+            }
+            catch (Exception e)
+            {
+                throw new IOException("exception decrypting data - " + e.toString());
+            }
+        }
+        else  if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
+        {
+            try
+            {
+                Cipher cipher = createCipher(mode, password, algId);
+
+                return cipher.doFinal(data);
+            }
+            catch (Exception e)
+            {
+                throw new IOException("exception decrypting data - " + e.toString());
+            }
+        }
+        else
+        {
+            throw new IOException("unknown PBE algorithm: " + algorithm);
+        }
+    }
+
+    private Cipher createCipher(int mode, char[] password, AlgorithmIdentifier algId)
+        throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchProviderException
+    {
+        PBES2Parameters alg = PBES2Parameters.getInstance(algId.getParameters());
+        PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
+        AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
+
+        SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
+        SecretKey key;
+
+        if (func.isDefaultPrf())
+        {
+            key = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), validateIterationCount(func.getIterationCount()), keySizeProvider.getKeySize(encScheme)));
+        }
+        else
+        {
+            key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), validateIterationCount(func.getIterationCount()), keySizeProvider.getKeySize(encScheme), func.getPrf()));
+        }
+
+        Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId());
+
+        ASN1Encodable encParams = alg.getEncryptionScheme().getParameters();
+        if (encParams instanceof ASN1OctetString)
+        {
+            cipher.init(mode, key, new IvParameterSpec(ASN1OctetString.getInstance(encParams).getOctets()));
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else
+        {
+            // TODO: at the moment it's just GOST, but...
+            GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams);
+
+            cipher.init(mode, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV()));
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+        return cipher;
+    }
+
+    public void engineLoad(
+        InputStream stream,
+        char[] password)
+        throws IOException
+    {
+        if (stream == null)     // just initialising
+        {
+            return;
+        }
+
+        if (password == null)
+        {
+            throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+        }
+
+        BufferedInputStream bufIn = new BufferedInputStream(stream);
+
+        bufIn.mark(10);
+
+        int head = bufIn.read();
+
+        if (head != 0x30)
+        {
+            throw new IOException("stream does not represent a PKCS12 key store");
+        }
+
+        bufIn.reset();
+
+        ASN1InputStream bIn = new ASN1InputStream(bufIn);
+        
+        Pfx bag;
+        try
+        {
+            bag = Pfx.getInstance(bIn.readObject());
+        }
+        catch (Exception e)
+        {
+            throw new IOException(e.getMessage());
+        }
+
+        ContentInfo info = bag.getAuthSafe();
+        Vector chain = new Vector();
+        boolean unmarkedKey = false;
+        boolean wrongPKCS12Zero = false;
+
+        if (bag.getMacData() != null)           // check the mac code
+        {
+            MacData mData = bag.getMacData();
+            DigestInfo dInfo = mData.getMac();
+            macAlgorithm = dInfo.getAlgorithmId();
+            byte[] salt = mData.getSalt();
+            itCount = validateIterationCount(mData.getIterationCount());
+            saltLength = salt.length;
+
+            byte[] data = ((ASN1OctetString)info.getContent()).getOctets();
+
+            try
+            {
+                byte[] res = calculatePbeMac(macAlgorithm.getAlgorithm(), salt, itCount, password, false, data);
+                byte[] dig = dInfo.getDigest();
+
+                if (!Arrays.constantTimeAreEqual(res, dig))
+                {
+                    if (password.length > 0)
+                    {
+                        throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+                    }
+
+                    // Try with incorrect zero length password
+                    res = calculatePbeMac(macAlgorithm.getAlgorithm(), salt, itCount, password, true, data);
+
+                    if (!Arrays.constantTimeAreEqual(res, dig))
+                    {
+                        throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+                    }
+
+                    wrongPKCS12Zero = true;
+                }
+            }
+            catch (IOException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new IOException("error constructing MAC: " + e.toString());
+            }
+        }
+
+        keys = new IgnoresCaseHashtable();
+        localIds = new Hashtable();
+
+        if (info.getContentType().equals(data))
+        {
+            bIn = new ASN1InputStream(((ASN1OctetString)info.getContent()).getOctets());
+
+            AuthenticatedSafe authSafe = AuthenticatedSafe.getInstance(bIn.readObject());
+            ContentInfo[] c = authSafe.getContentInfo();
+
+            for (int i = 0; i != c.length; i++)
+            {
+                if (c[i].getContentType().equals(data))
+                {
+                    ASN1InputStream dIn = new ASN1InputStream(((ASN1OctetString)c[i].getContent()).getOctets());
+                    ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+                    for (int j = 0; j != seq.size(); j++)
+                    {
+                        SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+                        if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+                        {
+                            com.android.internal.org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = com.android.internal.org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+                            PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+                            //
+                            // set the attributes on the key
+                            //
+                            String alias = null;
+                            ASN1OctetString localId = null;
+
+                            if (b.getBagAttributes() != null)
+                            {
+                                Enumeration e = b.getBagAttributes().getObjects();
+                                while (e.hasMoreElements())
+                                {
+                                    ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+                                    ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+                                    ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+                                    ASN1Primitive attr = null;
+
+                                    if (attrSet.size() > 0)
+                                    {
+                                        attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+                                        if (privKey instanceof PKCS12BagAttributeCarrier)
+                                        {
+                                            PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+                                            ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+                                            if (existing != null)
+                                            {
+                                                // OK, but the value has to be the same
+                                                if (!existing.toASN1Primitive().equals(attr))
+                                                {
+                                                    throw new IOException(
+                                                        "attempt to add existing attribute with different value");
+                                                }
+                                            }
+                                            else
+                                            {
+                                                bagAttr.setBagAttribute(aOid, attr);
+                                            }
+                                        }
+                                    }
+
+                                    if (aOid.equals(pkcs_9_at_friendlyName))
+                                    {
+                                        alias = ((DERBMPString)attr).getString();
+                                        keys.put(alias, privKey);
+                                    }
+                                    else if (aOid.equals(pkcs_9_at_localKeyId))
+                                    {
+                                        localId = (ASN1OctetString)attr;
+                                    }
+                                }
+                            }
+
+                            if (localId != null)
+                            {
+                                String name = new String(Hex.encode(localId.getOctets()));
+
+                                if (alias == null)
+                                {
+                                    keys.put(name, privKey);
+                                }
+                                else
+                                {
+                                    localIds.put(alias, name);
+                                }
+                            }
+                            else
+                            {
+                                unmarkedKey = true;
+                                keys.put("unmarked", privKey);
+                            }
+                        }
+                        else if (b.getBagId().equals(certBag))
+                        {
+                            chain.addElement(b);
+                        }
+                        else
+                        {
+                            System.out.println("extra in data " + b.getBagId());
+                            System.out.println(ASN1Dump.dumpAsString(b));
+                        }
+                    }
+                }
+                else if (c[i].getContentType().equals(encryptedData))
+                {
+                    EncryptedData d = EncryptedData.getInstance(c[i].getContent());
+                    byte[] octets = cryptData(false, d.getEncryptionAlgorithm(),
+                        password, wrongPKCS12Zero, d.getContent().getOctets());
+                    ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(octets);
+
+                    for (int j = 0; j != seq.size(); j++)
+                    {
+                        SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+
+                        if (b.getBagId().equals(certBag))
+                        {
+                            chain.addElement(b);
+                        }
+                        else if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+                        {
+                            com.android.internal.org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = com.android.internal.org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+                            PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+                            //
+                            // set the attributes on the key
+                            //
+                            PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+                            String alias = null;
+                            ASN1OctetString localId = null;
+
+                            Enumeration e = b.getBagAttributes().getObjects();
+                            while (e.hasMoreElements())
+                            {
+                                ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+                                ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+                                ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+                                ASN1Primitive attr = null;
+
+                                if (attrSet.size() > 0)
+                                {
+                                    attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+                                    ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+                                    if (existing != null)
+                                    {
+                                        // OK, but the value has to be the same
+                                        if (!existing.toASN1Primitive().equals(attr))
+                                        {
+                                            throw new IOException(
+                                                "attempt to add existing attribute with different value");
+                                        }
+                                    }
+                                    else
+                                    {
+                                        bagAttr.setBagAttribute(aOid, attr);
+                                    }
+                                }
+
+                                if (aOid.equals(pkcs_9_at_friendlyName))
+                                {
+                                    alias = ((DERBMPString)attr).getString();
+                                    keys.put(alias, privKey);
+                                }
+                                else if (aOid.equals(pkcs_9_at_localKeyId))
+                                {
+                                    localId = (ASN1OctetString)attr;
+                                }
+                            }
+
+                            String name = new String(Hex.encode(localId.getOctets()));
+
+                            if (alias == null)
+                            {
+                                keys.put(name, privKey);
+                            }
+                            else
+                            {
+                                localIds.put(alias, name);
+                            }
+                        }
+                        else if (b.getBagId().equals(keyBag))
+                        {
+                            com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo kInfo = com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo.getInstance(b.getBagValue());
+                            PrivateKey privKey = BouncyCastleProvider.getPrivateKey(kInfo);
+
+                            //
+                            // set the attributes on the key
+                            //
+                            PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+                            String alias = null;
+                            ASN1OctetString localId = null;
+
+                            Enumeration e = b.getBagAttributes().getObjects();
+                            while (e.hasMoreElements())
+                            {
+                                ASN1Sequence sq = ASN1Sequence.getInstance(e.nextElement());
+                                ASN1ObjectIdentifier aOid = ASN1ObjectIdentifier.getInstance(sq.getObjectAt(0));
+                                ASN1Set attrSet = ASN1Set.getInstance(sq.getObjectAt(1));
+                                ASN1Primitive attr = null;
+
+                                if (attrSet.size() > 0)
+                                {
+                                    attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+                                    ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+                                    if (existing != null)
+                                    {
+                                        // OK, but the value has to be the same
+                                        if (!existing.toASN1Primitive().equals(attr))
+                                        {
+                                            throw new IOException(
+                                                "attempt to add existing attribute with different value");
+                                        }
+                                    }
+                                    else
+                                    {
+                                        bagAttr.setBagAttribute(aOid, attr);
+                                    }
+
+                                    if (aOid.equals(pkcs_9_at_friendlyName))
+                                    {
+                                        alias = ((DERBMPString)attr).getString();
+                                        keys.put(alias, privKey);
+                                    }
+                                    else if (aOid.equals(pkcs_9_at_localKeyId))
+                                    {
+                                        localId = (ASN1OctetString)attr;
+                                    }
+                                }
+                            }
+
+                            String name = new String(Hex.encode(localId.getOctets()));
+
+                            if (alias == null)
+                            {
+                                keys.put(name, privKey);
+                            }
+                            else
+                            {
+                                localIds.put(alias, name);
+                            }
+                        }
+                        else
+                        {
+                            System.out.println("extra in encryptedData " + b.getBagId());
+                            System.out.println(ASN1Dump.dumpAsString(b));
+                        }
+                    }
+                }
+                else
+                {
+                    System.out.println("extra " + c[i].getContentType().getId());
+                    System.out.println("extra " + ASN1Dump.dumpAsString(c[i].getContent()));
+                }
+            }
+        }
+
+        certs = new IgnoresCaseHashtable();
+        chainCerts = new Hashtable();
+        keyCerts = new Hashtable();
+
+        for (int i = 0; i != chain.size(); i++)
+        {
+            SafeBag b = (SafeBag)chain.elementAt(i);
+            CertBag cb = CertBag.getInstance(b.getBagValue());
+
+            if (!cb.getCertId().equals(x509Certificate))
+            {
+                throw new RuntimeException("Unsupported certificate type: " + cb.getCertId());
+            }
+
+            Certificate cert;
+
+            try
+            {
+                ByteArrayInputStream cIn = new ByteArrayInputStream(
+                    ((ASN1OctetString)cb.getCertValue()).getOctets());
+                cert = certFact.generateCertificate(cIn);
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.toString());
+            }
+
+            //
+            // set the attributes
+            //
+            ASN1OctetString localId = null;
+            String alias = null;
+
+            if (b.getBagAttributes() != null)
+            {
+                Enumeration e = b.getBagAttributes().getObjects();
+                while (e.hasMoreElements())
+                {
+                    ASN1Sequence sq = ASN1Sequence.getInstance(e.nextElement());
+                    ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(sq.getObjectAt(0));
+                    ASN1Set attrSet = ASN1Set.getInstance(sq.getObjectAt(1));
+
+                    if (attrSet.size() > 0)   // sometimes this is empty!
+                    {
+                        ASN1Primitive attr = (ASN1Primitive)attrSet.getObjectAt(0);
+                        PKCS12BagAttributeCarrier bagAttr = null;
+
+                        if (cert instanceof PKCS12BagAttributeCarrier)
+                        {
+                            bagAttr = (PKCS12BagAttributeCarrier)cert;
+
+                            ASN1Encodable existing = bagAttr.getBagAttribute(oid);
+                            if (existing != null)
+                            {
+                                // OK, but the value has to be the same
+                                if (!existing.toASN1Primitive().equals(attr))
+                                {
+                                    throw new IOException(
+                                        "attempt to add existing attribute with different value");
+                                }
+                            }
+                            else
+                            {
+                                bagAttr.setBagAttribute(oid, attr);
+                            }
+                        }
+
+                        if (oid.equals(pkcs_9_at_friendlyName))
+                        {
+                            alias = ((DERBMPString)attr).getString();
+                        }
+                        else if (oid.equals(pkcs_9_at_localKeyId))
+                        {
+                            localId = (ASN1OctetString)attr;
+                        }
+                    }
+                }
+            }
+
+            chainCerts.put(new CertId(cert.getPublicKey()), cert);
+
+            if (unmarkedKey)
+            {
+                if (keyCerts.isEmpty())
+                {
+                    String name = new String(Hex.encode(createSubjectKeyId(cert.getPublicKey()).getKeyIdentifier()));
+
+                    keyCerts.put(name, cert);
+                    keys.put(name, keys.remove("unmarked"));
+                }
+            }
+            else
+            {
+                //
+                // the local key id needs to override the friendly name
+                //
+                if (localId != null)
+                {
+                    String name = new String(Hex.encode(localId.getOctets()));
+
+                    keyCerts.put(name, cert);
+                }
+                if (alias != null)
+                {
+                    certs.put(alias, cert);
+                }
+            }
+        }
+    }
+
+    private int validateIterationCount(BigInteger i)
+    {
+        int count = i.intValue();
+
+        if (count < 0)
+        {
+            throw new IllegalStateException("negative iteration count found");
+        }
+
+        BigInteger maxValue = Properties.asBigInteger(PKCS12_MAX_IT_COUNT_PROPERTY);
+        if (maxValue != null)
+        {
+            if (maxValue.intValue() < count)
+            {
+                throw new IllegalStateException("iteration count " + count + " greater than " + maxValue.intValue());
+            }
+        }
+
+        return count;
+    }
+
+    public void engineStore(LoadStoreParameter param)
+        throws IOException,
+        NoSuchAlgorithmException, CertificateException
+    {
+        if (param == null)
+        {
+            throw new IllegalArgumentException("'param' arg cannot be null");
+        }
+
+        if (!(param instanceof PKCS12StoreParameter || param instanceof JDKPKCS12StoreParameter))
+        {
+            throw new IllegalArgumentException(
+                "No support for 'param' of type " + param.getClass().getName());
+        }
+
+        PKCS12StoreParameter bcParam;
+
+        if (param instanceof PKCS12StoreParameter)
+        {
+            bcParam = (PKCS12StoreParameter)param;
+        }
+        else
+        {
+            bcParam = new PKCS12StoreParameter(((JDKPKCS12StoreParameter)param).getOutputStream(),
+                param.getProtectionParameter(), ((JDKPKCS12StoreParameter)param).isUseDEREncoding());
+        }
+
+        char[] password;
+        ProtectionParameter protParam = param.getProtectionParameter();
+        if (protParam == null)
+        {
+            password = null;
+        }
+        else if (protParam instanceof KeyStore.PasswordProtection)
+        {
+            password = ((KeyStore.PasswordProtection)protParam).getPassword();
+        }
+        else
+        {
+            throw new IllegalArgumentException(
+                "No support for protection parameter of type " + protParam.getClass().getName());
+        }
+
+        doStore(bcParam.getOutputStream(), password, bcParam.isForDEREncoding());
+    }
+
+    public void engineStore(OutputStream stream, char[] password)
+        throws IOException
+    {
+        doStore(stream, password, false);
+    }
+
+    private void doStore(OutputStream stream, char[] password, boolean useDEREncoding)
+        throws IOException
+    {
+        if (password == null)
+        {
+            throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+        }
+
+        //
+        // handle the key
+        //
+        ASN1EncodableVector keyS = new ASN1EncodableVector();
+
+        Enumeration ks = keys.keys();
+
+        while (ks.hasMoreElements())
+        {
+            byte[] kSalt = new byte[SALT_SIZE];
+
+            random.nextBytes(kSalt);
+
+            String name = (String)ks.nextElement();
+            PrivateKey privKey = (PrivateKey)keys.get(name);
+            PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
+            byte[] kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
+            AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Primitive());
+            com.android.internal.org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new com.android.internal.org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
+            boolean attrSet = false;
+            ASN1EncodableVector kName = new ASN1EncodableVector();
+
+            if (privKey instanceof PKCS12BagAttributeCarrier)
+            {
+                PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)privKey;
+                //
+                // make sure we are using the local alias on store
+                //
+                DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+                if (nm == null || !nm.getString().equals(name))
+                {
+                    bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+                }
+
+                //
+                // make sure we have a local key-id
+                //
+                if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+                {
+                    Certificate ct = engineGetCertificate(name);
+
+                    bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(ct.getPublicKey()));
+                }
+
+                Enumeration e = bagAttrs.getBagAttributeKeys();
+
+                while (e.hasMoreElements())
+                {
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    ASN1EncodableVector kSeq = new ASN1EncodableVector();
+
+                    kSeq.add(oid);
+                    kSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+
+                    attrSet = true;
+
+                    kName.add(new DERSequence(kSeq));
+                }
+            }
+
+            if (!attrSet)
+            {
+                //
+                // set a default friendly name (from the key id) and local id
+                //
+                ASN1EncodableVector kSeq = new ASN1EncodableVector();
+                Certificate ct = engineGetCertificate(name);
+
+                kSeq.add(pkcs_9_at_localKeyId);
+                kSeq.add(new DERSet(createSubjectKeyId(ct.getPublicKey())));
+
+                kName.add(new DERSequence(kSeq));
+
+                kSeq = new ASN1EncodableVector();
+
+                kSeq.add(pkcs_9_at_friendlyName);
+                kSeq.add(new DERSet(new DERBMPString(name)));
+
+                kName.add(new DERSequence(kSeq));
+            }
+
+            SafeBag kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.toASN1Primitive(), new DERSet(kName));
+            keyS.add(kBag);
+        }
+
+        byte[] keySEncoded = new DERSequence(keyS).getEncoded(ASN1Encoding.DER);
+        BEROctetString keyString = new BEROctetString(keySEncoded);
+
+        //
+        // certificate processing
+        //
+        byte[] cSalt = new byte[SALT_SIZE];
+
+        random.nextBytes(cSalt);
+
+        ASN1EncodableVector certSeq = new ASN1EncodableVector();
+        PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
+        AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Primitive());
+        Hashtable doneCerts = new Hashtable();
+
+        Enumeration cs = keys.keys();
+        while (cs.hasMoreElements())
+        {
+            try
+            {
+                String name = (String)cs.nextElement();
+                Certificate cert = engineGetCertificate(name);
+                boolean cAttrSet = false;
+                CertBag cBag = new CertBag(
+                    x509Certificate,
+                    new DEROctetString(cert.getEncoded()));
+                ASN1EncodableVector fName = new ASN1EncodableVector();
+
+                if (cert instanceof PKCS12BagAttributeCarrier)
+                {
+                    PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+                    //
+                    // make sure we are using the local alias on store
+                    //
+                    DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+                    if (nm == null || !nm.getString().equals(name))
+                    {
+                        bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+                    }
+
+                    //
+                    // make sure we have a local key-id
+                    //
+                    if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+                    {
+                        bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(cert.getPublicKey()));
+                    }
+
+                    Enumeration e = bagAttrs.getBagAttributeKeys();
+
+                    while (e.hasMoreElements())
+                    {
+                        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                        ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+                        fSeq.add(oid);
+                        fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+                        fName.add(new DERSequence(fSeq));
+
+                        cAttrSet = true;
+                    }
+                }
+
+                if (!cAttrSet)
+                {
+                    ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+                    fSeq.add(pkcs_9_at_localKeyId);
+                    fSeq.add(new DERSet(createSubjectKeyId(cert.getPublicKey())));
+                    fName.add(new DERSequence(fSeq));
+
+                    fSeq = new ASN1EncodableVector();
+
+                    fSeq.add(pkcs_9_at_friendlyName);
+                    fSeq.add(new DERSet(new DERBMPString(name)));
+
+                    fName.add(new DERSequence(fSeq));
+                }
+
+                SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+                certSeq.add(sBag);
+
+                doneCerts.put(cert, cert);
+            }
+            catch (CertificateEncodingException e)
+            {
+                throw new IOException("Error encoding certificate: " + e.toString());
+            }
+        }
+
+        cs = certs.keys();
+        while (cs.hasMoreElements())
+        {
+            try
+            {
+                String certId = (String)cs.nextElement();
+                Certificate cert = (Certificate)certs.get(certId);
+                boolean cAttrSet = false;
+
+                if (keys.get(certId) != null)
+                {
+                    continue;
+                }
+
+                CertBag cBag = new CertBag(
+                    x509Certificate,
+                    new DEROctetString(cert.getEncoded()));
+                ASN1EncodableVector fName = new ASN1EncodableVector();
+
+                if (cert instanceof PKCS12BagAttributeCarrier)
+                {
+                    PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+                    //
+                    // make sure we are using the local alias on store
+                    //
+                    DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+                    if (nm == null || !nm.getString().equals(certId))
+                    {
+                        bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId));
+                    }
+
+                    Enumeration e = bagAttrs.getBagAttributeKeys();
+
+                    while (e.hasMoreElements())
+                    {
+                        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+                        // a certificate not immediately linked to a key doesn't require
+                        // a localKeyID and will confuse some PKCS12 implementations.
+                        //
+                        // If we find one, we'll prune it out.
+                        if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+                        {
+                            continue;
+                        }
+
+                        ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+                        fSeq.add(oid);
+                        fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+                        fName.add(new DERSequence(fSeq));
+
+                        cAttrSet = true;
+                    }
+                }
+
+                if (!cAttrSet)
+                {
+                    ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+                    fSeq.add(pkcs_9_at_friendlyName);
+                    fSeq.add(new DERSet(new DERBMPString(certId)));
+
+                    fName.add(new DERSequence(fSeq));
+                }
+
+                SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+                certSeq.add(sBag);
+
+                doneCerts.put(cert, cert);
+            }
+            catch (CertificateEncodingException e)
+            {
+                throw new IOException("Error encoding certificate: " + e.toString());
+            }
+        }
+
+        Set usedSet = getUsedCertificateSet();
+
+        cs = chainCerts.keys();
+        while (cs.hasMoreElements())
+        {
+            try
+            {
+                CertId certId = (CertId)cs.nextElement();
+                Certificate cert = (Certificate)chainCerts.get(certId);
+
+                if (!usedSet.contains(cert))
+                {
+                    continue;
+                }
+
+                if (doneCerts.get(cert) != null)
+                {
+                    continue;
+                }
+
+                CertBag cBag = new CertBag(
+                    x509Certificate,
+                    new DEROctetString(cert.getEncoded()));
+                ASN1EncodableVector fName = new ASN1EncodableVector();
+
+                if (cert instanceof PKCS12BagAttributeCarrier)
+                {
+                    PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+                    Enumeration e = bagAttrs.getBagAttributeKeys();
+
+                    while (e.hasMoreElements())
+                    {
+                        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+                        // a certificate not immediately linked to a key doesn't require
+                        // a localKeyID and will confuse some PKCS12 implementations.
+                        //
+                        // If we find one, we'll prune it out.
+                        if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+                        {
+                            continue;
+                        }
+
+                        ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+                        fSeq.add(oid);
+                        fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+                        fName.add(new DERSequence(fSeq));
+                    }
+                }
+
+                SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+                certSeq.add(sBag);
+            }
+            catch (CertificateEncodingException e)
+            {
+                throw new IOException("Error encoding certificate: " + e.toString());
+            }
+        }
+
+        byte[] certSeqEncoded = new DERSequence(certSeq).getEncoded(ASN1Encoding.DER);
+        byte[] certBytes = cryptData(true, cAlgId, password, false, certSeqEncoded);
+        EncryptedData cInfo = new EncryptedData(data, cAlgId, new BEROctetString(certBytes));
+
+        ContentInfo[] info = new ContentInfo[]
+            {
+                new ContentInfo(data, keyString),
+                new ContentInfo(encryptedData, cInfo.toASN1Primitive())
+            };
+
+        AuthenticatedSafe auth = new AuthenticatedSafe(info);
+
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        DEROutputStream asn1Out;
+        if (useDEREncoding)
+        {
+            asn1Out = new DEROutputStream(bOut);
+        }
+        else
+        {
+            asn1Out = new BEROutputStream(bOut);
+        }
+
+        asn1Out.writeObject(auth);
+
+        byte[] pkg = bOut.toByteArray();
+
+        ContentInfo mainInfo = new ContentInfo(data, new BEROctetString(pkg));
+
+        //
+        // create the mac
+        //
+        byte[] mSalt = new byte[saltLength];
+
+        random.nextBytes(mSalt);
+
+        byte[] data = ((ASN1OctetString)mainInfo.getContent()).getOctets();
+
+        MacData mData;
+
+        try
+        {
+            byte[] res = calculatePbeMac(macAlgorithm.getAlgorithm(), mSalt, itCount, password, false, data);
+
+            DigestInfo dInfo = new DigestInfo(macAlgorithm, res);
+
+            mData = new MacData(dInfo, mSalt, itCount);
+        }
+        catch (Exception e)
+        {
+            throw new IOException("error constructing MAC: " + e.toString());
+        }
+
+        //
+        // output the Pfx
+        //
+        Pfx pfx = new Pfx(mainInfo, mData);
+
+        if (useDEREncoding)
+        {
+            asn1Out = new DEROutputStream(stream);
+        }
+        else
+        {
+            asn1Out = new BEROutputStream(stream);
+        }
+
+        asn1Out.writeObject(pfx);
+    }
+
+    private Set getUsedCertificateSet()
+    {
+        Set usedSet = new HashSet();
+
+        for (Enumeration en = keys.keys(); en.hasMoreElements();)
+        {
+            String alias = (String)en.nextElement();
+
+                Certificate[] certs = engineGetCertificateChain(alias);
+
+                for (int i = 0; i != certs.length; i++)
+                {
+                    usedSet.add(certs[i]);
+                }
+        }
+
+        for (Enumeration en = certs.keys(); en.hasMoreElements();)
+        {
+            String alias = (String)en.nextElement();
+
+            Certificate cert = engineGetCertificate(alias);
+
+            usedSet.add(cert);
+        }
+
+        return usedSet;
+    }
+
+    private byte[] calculatePbeMac(
+        ASN1ObjectIdentifier oid,
+        byte[] salt,
+        int itCount,
+        char[] password,
+        boolean wrongPkcs12Zero,
+        byte[] data)
+        throws Exception
+    {
+        PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
+
+        Mac mac = helper.createMac(oid.getId());
+        mac.init(new PKCS12Key(password, wrongPkcs12Zero), defParams);
+        mac.update(data);
+
+        return mac.doFinal();
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class BCPKCS12KeyStore
+        extends PKCS12KeyStoreSpi
+    {
+        public BCPKCS12KeyStore()
+        {
+            // Android-changed: Use default provider for JCA algorithms instead of BC
+            // Was: super(new BCJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+            super(new DefaultJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class BCPKCS12KeyStore3DES
+        extends PKCS12KeyStoreSpi
+    {
+        public BCPKCS12KeyStore3DES()
+        {
+            super(new BCJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+        }
+    }
+
+    public static class DefPKCS12KeyStore
+        extends PKCS12KeyStoreSpi
+    {
+        public DefPKCS12KeyStore()
+        {
+            super(new DefaultJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+        }
+    }
+
+    public static class DefPKCS12KeyStore3DES
+        extends PKCS12KeyStoreSpi
+    {
+        public DefPKCS12KeyStore3DES()
+        {
+            super(new DefaultJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+        }
+    }
+    */
+    // END android-removed
+
+    private static class IgnoresCaseHashtable
+    {
+        private Hashtable orig = new Hashtable();
+        private Hashtable keys = new Hashtable();
+
+        public void put(String key, Object value)
+        {
+            String lower = (key == null) ? null : Strings.toLowerCase(key);
+            String k = (String)keys.get(lower);
+            if (k != null)
+            {
+                orig.remove(k);
+            }
+
+            keys.put(lower, key);
+            orig.put(key, value);
+        }
+
+        public Enumeration keys()
+        {
+            return orig.keys();
+        }
+
+        public Object remove(String alias)
+        {
+            String k = (String)keys.remove(alias == null ? null : Strings.toLowerCase(alias));
+            if (k == null)
+            {
+                return null;
+            }
+
+            return orig.remove(k);
+        }
+
+        public Object get(String alias)
+        {
+            String k = (String)keys.get(alias == null ? null : Strings.toLowerCase(alias));
+            if (k == null)
+            {
+                return null;
+            }
+
+            return orig.get(k);
+        }
+
+        public Enumeration elements()
+        {
+            return orig.elements();
+        }
+    }
+
+    private static class DefaultSecretKeyProvider
+    {
+        private final Map KEY_SIZES;
+
+        DefaultSecretKeyProvider()
+        {
+            Map keySizes = new HashMap();
+
+            keySizes.put(new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"), Integers.valueOf(128));
+
+            keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC, Integers.valueOf(192));
+
+            keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128));
+            keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192));
+            keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256));
+
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            keySizes.put(NTTObjectIdentifiers.id_camellia128_cbc, Integers.valueOf(128));
+            keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192));
+            keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256));
+
+            keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256));
+            */
+            // END Android-removed: Unsupported algorithms
+
+            KEY_SIZES = Collections.unmodifiableMap(keySizes);
+        }
+
+        public int getKeySize(AlgorithmIdentifier algorithmIdentifier)
+        {
+            // TODO: not all ciphers/oid relationships are this simple.
+            Integer keySize = (Integer)KEY_SIZES.get(algorithmIdentifier.getAlgorithm());
+
+            if (keySize != null)
+            {
+                return keySize.intValue();
+            }
+
+            return -1;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/AES.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/AES.java
new file mode 100644
index 0000000..6850b29
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/AES.java
@@ -0,0 +1,1149 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+import java.io.IOException;
+// BEGIN Android-added: Needed for setting mode with GCM
+import java.security.NoSuchAlgorithmException;
+// END Android-added: Needed for setting mode with GCM
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.spec.IvParameterSpec;
+
+// BEGIN Android-added: Needed for setting padding with GCM
+import javax.crypto.NoSuchPaddingException;
+// END Android-added: Needed for setting padding with GCM
+import com.android.internal.org.bouncycastle.asn1.bc.BCObjectIdentifiers;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cms.CCMParameters;
+import com.android.internal.org.bouncycastle.asn1.cms.GCMParameters;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.BufferedBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.Mac;
+import com.android.internal.org.bouncycastle.crypto.engines.AESEngine;
+import com.android.internal.org.bouncycastle.crypto.engines.AESWrapEngine;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.engines.AESWrapPadEngine;
+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+// import org.bouncycastle.crypto.engines.RFC5649WrapEngine;
+// import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
+// import org.bouncycastle.crypto.macs.CMac;
+// import org.bouncycastle.crypto.macs.GMac;
+import com.android.internal.org.bouncycastle.crypto.modes.CBCBlockCipher;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.modes.CCMBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.modes.CFBBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.modes.GCMBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.modes.OFBBlockCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+import com.android.internal.org.bouncycastle.jcajce.spec.AEADParameterSpec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class AES
+{
+    private static final Map<String, String> generalAesAttributes = new HashMap<String, String>();
+
+    static
+    {
+        generalAesAttributes.put("SupportedKeyClasses", "javax.crypto.SecretKey");
+        generalAesAttributes.put("SupportedKeyFormats", "RAW");
+    }
+
+    private AES()
+    {
+    }
+    
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class ECB
+        extends BaseBlockCipher
+    {
+        public ECB()
+        {
+            super(new BlockCipherProvider()
+            {
+                public BlockCipher get()
+                {
+                    return new AESEngine();
+                }
+            });
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class CBC
+       extends BaseBlockCipher
+    {
+        public CBC()
+        {
+            super(new CBCBlockCipher(new AESEngine()), 128);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class CFB
+        extends BaseBlockCipher
+    {
+        public CFB()
+        {
+            super(new BufferedBlockCipher(new CFBBlockCipher(new AESEngine(), 128)), 128);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class OFB
+        extends BaseBlockCipher
+    {
+        public OFB()
+        {
+            super(new BufferedBlockCipher(new OFBBlockCipher(new AESEngine(), 128)), 128);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class GCM
+        extends BaseBlockCipher
+    {
+        public GCM()
+        {
+            super(new GCMBlockCipher(new AESEngine()));
+            // BEGIN Android-added: Set mode and padding due to name change (see note in Mappings)
+            try {
+                engineSetMode("GCM");
+                engineSetPadding("NoPadding");
+            } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+                // this should not be possible
+                throw new RuntimeException("Could not set mode or padding for GCM mode", e);
+            }
+            // END Android-added: Set mode and padding due to name change (see note in Mappings)
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    static public class CCM
+        extends BaseBlockCipher
+    {
+        public CCM()
+        {
+            super(new CCMBlockCipher(new AESEngine()), false, 16);
+        }
+    }
+
+    public static class AESCMAC
+        extends BaseMac
+    {
+        public AESCMAC()
+        {
+            super(new CMac(new AESEngine()));
+        }
+    }
+
+    public static class AESGMAC
+        extends BaseMac
+    {
+        public AESGMAC()
+        {
+            super(new GMac(new GCMBlockCipher(new AESEngine())));
+        }
+    }
+
+    public static class AESCCMMAC
+        extends BaseMac
+    {
+        public AESCCMMAC()
+        {
+            super(new CCMMac());
+        }
+
+        private static class CCMMac
+            implements Mac
+        {
+            private final CCMBlockCipher ccm = new CCMBlockCipher(new AESEngine());
+
+            private int macLength = 8;
+
+            public void init(CipherParameters params)
+                throws IllegalArgumentException
+            {
+                ccm.init(true, params);
+
+                this.macLength = ccm.getMac().length;
+            }
+
+            public String getAlgorithmName()
+            {
+                return ccm.getAlgorithmName() + "Mac";
+            }
+
+            public int getMacSize()
+            {
+                return macLength;
+            }
+
+            public void update(byte in)
+                throws IllegalStateException
+            {
+                ccm.processAADByte(in);
+            }
+
+            public void update(byte[] in, int inOff, int len)
+                throws DataLengthException, IllegalStateException
+            {
+                ccm.processAADBytes(in, inOff, len);
+            }
+
+            public int doFinal(byte[] out, int outOff)
+                throws DataLengthException, IllegalStateException
+            {
+                try
+                {
+                    return ccm.doFinal(out, 0);
+                }
+                catch (InvalidCipherTextException e)
+                {
+                    throw new IllegalStateException("exception on doFinal(): " + e.toString());
+                }
+            }
+
+            public void reset()
+            {
+                ccm.reset();
+            }
+        }
+    }
+
+    static public class KeyFactory
+         extends BaseSecretKeyFactory
+    {
+        public KeyFactory()
+        {
+            super("AES", null);
+        }
+    }
+
+    public static class Poly1305
+        extends BaseMac
+    {
+        public Poly1305()
+        {
+            super(new org.bouncycastle.crypto.macs.Poly1305(new AESEngine()));
+        }
+    }
+
+    public static class Poly1305KeyGen
+        extends BaseKeyGenerator
+    {
+        public Poly1305KeyGen()
+        {
+            super("Poly1305-AES", 256, new Poly1305KeyGenerator());
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class Wrap
+        extends BaseWrapCipher
+    {
+        public Wrap()
+        {
+            super(new AESWrapEngine());
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class WrapPad
+        extends BaseWrapCipher
+    {
+        public WrapPad()
+        {
+            super(new AESWrapPadEngine());
+        }
+    }
+
+    public static class RFC3211Wrap
+        extends BaseWrapCipher
+    {
+        public RFC3211Wrap()
+        {
+            super(new RFC3211WrapEngine(new AESEngine()), 16);
+        }
+    }
+
+    public static class RFC5649Wrap
+        extends BaseWrapCipher
+    {
+        public RFC5649Wrap()
+        {
+            super(new RFC5649WrapEngine(new AESEngine()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * PBEWithAES-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithAESCBC
+        extends BaseBlockCipher
+    {
+        public PBEWithAESCBC()
+        {
+            super(new CBCBlockCipher(new AESEngine()));
+        }
+    }
+
+    /**
+     * PBEWithSHA1AES-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA1AESCBC128
+        extends BaseBlockCipher
+    {
+        public PBEWithSHA1AESCBC128()
+        {
+            super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 128, 16);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA1AESCBC192
+        extends BaseBlockCipher
+    {
+        public PBEWithSHA1AESCBC192()
+        {
+            super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 192, 16);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA1AESCBC256
+        extends BaseBlockCipher
+    {
+        public PBEWithSHA1AESCBC256()
+        {
+            super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 256, 16);
+        }
+    }
+
+    /**
+     * PBEWithSHA256AES-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA256AESCBC128
+        extends BaseBlockCipher
+    {
+        public PBEWithSHA256AESCBC128()
+        {
+            super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 128, 16);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA256AESCBC192
+        extends BaseBlockCipher
+    {
+        public PBEWithSHA256AESCBC192()
+        {
+            super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 192, 16);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA256AESCBC256
+        extends BaseBlockCipher
+    {
+        public PBEWithSHA256AESCBC256()
+        {
+            super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 256, 16);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGen
+        extends BaseKeyGenerator
+    {
+        public KeyGen()
+        {
+            // Android-changed: Use 128-bit keys by default.
+            // Bouncy Castle defaults to 192-bit keys, which is the worst choice: worse security
+            // than 256-bit keys, slower than 128-bit keys, narrower support than either.
+            // Use 128-bit keys by default since they're faster and should still be plenty secure.
+            // this(192);
+            this(128);
+        }
+
+        public KeyGen(int keySize)
+        {
+            super("AES", keySize, new CipherKeyGenerator());
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class KeyGen128
+        extends KeyGen
+    {
+        public KeyGen128()
+        {
+            super(128);
+        }
+    }
+
+    public static class KeyGen192
+        extends KeyGen
+    {
+        public KeyGen192()
+        {
+            super(192);
+        }
+    }
+
+    public static class KeyGen256
+        extends KeyGen
+    {
+        public KeyGen256()
+        {
+            super(256);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+    
+    /**
+     * PBEWithSHA1And128BitAES-BC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAnd128BitAESBC
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHAAnd128BitAESBC()
+        {
+            super("PBEWithSHA1And128BitAES-CBC-BC", null, true, PKCS12, SHA1, 128, 128);
+        }
+    }
+    
+    /**
+     * PBEWithSHA1And192BitAES-BC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAnd192BitAESBC
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHAAnd192BitAESBC()
+        {
+            super("PBEWithSHA1And192BitAES-CBC-BC", null, true, PKCS12, SHA1, 192, 128);
+        }
+    }
+    
+    /**
+     * PBEWithSHA1And256BitAES-BC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAnd256BitAESBC
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHAAnd256BitAESBC()
+        {
+            super("PBEWithSHA1And256BitAES-CBC-BC", null, true, PKCS12, SHA1, 256, 128);
+        }
+    }
+    
+    /**
+     * PBEWithSHA256And128BitAES-BC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA256And128BitAESBC
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHA256And128BitAESBC()
+        {
+            super("PBEWithSHA256And128BitAES-CBC-BC", null, true, PKCS12, SHA256, 128, 128);
+        }
+    }
+    
+    /**
+     * PBEWithSHA256And192BitAES-BC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA256And192BitAESBC
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHA256And192BitAESBC()
+        {
+            super("PBEWithSHA256And192BitAES-CBC-BC", null, true, PKCS12, SHA256, 192, 128);
+        }
+    }
+    
+    /**
+     * PBEWithSHA256And256BitAES-BC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA256And256BitAESBC
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHA256And256BitAESBC()
+        {
+            super("PBEWithSHA256And256BitAES-CBC-BC", null, true, PKCS12, SHA256, 256, 128);
+        }
+    }
+    
+    /**
+     * PBEWithMD5And128BitAES-OpenSSL
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithMD5And128BitAESCBCOpenSSL
+        extends PBESecretKeyFactory
+    {
+        public PBEWithMD5And128BitAESCBCOpenSSL()
+        {
+            super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 128, 128);
+        }
+    }
+    
+    /**
+     * PBEWithMD5And192BitAES-OpenSSL
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithMD5And192BitAESCBCOpenSSL
+        extends PBESecretKeyFactory
+    {
+        public PBEWithMD5And192BitAESCBCOpenSSL()
+        {
+            super("PBEWithMD5And192BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 192, 128);
+        }
+    }
+    
+    /**
+     * PBEWithMD5And256BitAES-OpenSSL
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithMD5And256BitAESCBCOpenSSL
+        extends PBESecretKeyFactory
+    {
+        public PBEWithMD5And256BitAESCBCOpenSSL()
+        {
+            super("PBEWithMD5And256BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 256, 128);
+        }
+    }
+    
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class AlgParamGen
+        extends BaseAlgorithmParameterGenerator
+    {
+        protected void engineInit(
+            AlgorithmParameterSpec genParamSpec,
+            SecureRandom random)
+            throws InvalidAlgorithmParameterException
+        {
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            byte[]  iv = new byte[16];
+
+            if (random == null)
+            {
+                random = new SecureRandom();
+            }
+
+            random.nextBytes(iv);
+
+            AlgorithmParameters params;
+
+            try
+            {
+                params = createParametersInstance("AES");
+                params.init(new IvParameterSpec(iv));
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+
+            return params;
+        }
+    }
+
+    public static class AlgParamGenCCM
+        extends BaseAlgorithmParameterGenerator
+    {
+        protected void engineInit(
+            AlgorithmParameterSpec genParamSpec,
+            SecureRandom random)
+            throws InvalidAlgorithmParameterException
+        {
+            // TODO: add support for GCMParameterSpec as a template.
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            byte[]  iv = new byte[12];
+
+            if (random == null)
+            {
+                random = new SecureRandom();
+            }
+
+            random.nextBytes(iv);
+
+            AlgorithmParameters params;
+
+            try
+            {
+                params = createParametersInstance("CCM");
+                params.init(new CCMParameters(iv, 12).getEncoded());
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+
+            return params;
+        }
+    }
+
+    public static class AlgParamGenGCM
+        extends BaseAlgorithmParameterGenerator
+    {
+        protected void engineInit(
+            AlgorithmParameterSpec genParamSpec,
+            SecureRandom random)
+            throws InvalidAlgorithmParameterException
+        {
+            // TODO: add support for GCMParameterSpec as a template.
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            byte[]  nonce = new byte[12];
+
+            if (random == null)
+            {
+                random = new SecureRandom();
+            }
+
+            random.nextBytes(nonce);
+
+            AlgorithmParameters params;
+
+            try
+            {
+                params = createParametersInstance("GCM");
+                params.init(new GCMParameters(nonce, 16).getEncoded());
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+
+            return params;
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class AlgParams
+        extends IvAlgorithmParameters
+    {
+        protected String engineToString()
+        {
+            return "AES IV";
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class AlgParamsGCM
+        extends BaseAlgorithmParameters
+    {
+        private GCMParameters gcmParams;
+
+        protected void engineInit(AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (GcmSpecUtil.isGcmSpec(paramSpec))
+            {
+                gcmParams = GcmSpecUtil.extractGcmParameters(paramSpec);
+            }
+            else if (paramSpec instanceof AEADParameterSpec)
+            {
+                gcmParams = new GCMParameters(((AEADParameterSpec)paramSpec).getNonce(), ((AEADParameterSpec)paramSpec).getMacSizeInBits() / 8);
+            }
+            else
+            {
+                throw new InvalidParameterSpecException("AlgorithmParameterSpec class not recognized: " + paramSpec.getClass().getName());
+            }
+        }
+
+        protected void engineInit(byte[] params)
+            throws IOException
+        {
+            gcmParams = GCMParameters.getInstance(params);
+        }
+
+        protected void engineInit(byte[] params, String format)
+            throws IOException
+        {
+            if (!isASN1FormatString(format))
+            {
+                throw new IOException("unknown format specified");
+            }
+
+            gcmParams = GCMParameters.getInstance(params);
+        }
+
+        protected byte[] engineGetEncoded()
+            throws IOException
+        {
+            return gcmParams.getEncoded();
+        }
+
+        protected byte[] engineGetEncoded(String format)
+            throws IOException
+        {
+            if (!isASN1FormatString(format))
+            {
+                throw new IOException("unknown format specified");
+            }
+
+            return gcmParams.getEncoded();
+        }
+
+        protected String engineToString()
+        {
+            return "GCM";
+        }
+
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == AlgorithmParameterSpec.class || GcmSpecUtil.isGcmSpec(paramSpec))
+            {
+                if (GcmSpecUtil.gcmSpecExists())
+                {
+                    return GcmSpecUtil.extractGcmSpec(gcmParams.toASN1Primitive());
+                }
+                return new AEADParameterSpec(gcmParams.getNonce(), gcmParams.getIcvLen() * 8);
+            }
+            if (paramSpec == AEADParameterSpec.class)
+            {
+                return new AEADParameterSpec(gcmParams.getNonce(), gcmParams.getIcvLen() * 8);
+            }
+            if (paramSpec == IvParameterSpec.class)
+            {
+                return new IvParameterSpec(gcmParams.getNonce());
+            }
+
+            throw new InvalidParameterSpecException("AlgorithmParameterSpec not recognized: " + paramSpec.getName());
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class AlgParamsCCM
+        extends BaseAlgorithmParameters
+    {
+        private CCMParameters ccmParams;
+
+        protected void engineInit(AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (GcmSpecUtil.isGcmSpec(paramSpec))
+            {
+                ccmParams = CCMParameters.getInstance(GcmSpecUtil.extractGcmParameters(paramSpec));
+            }
+            else if (paramSpec instanceof AEADParameterSpec)
+            {
+                ccmParams = new CCMParameters(((AEADParameterSpec)paramSpec).getNonce(), ((AEADParameterSpec)paramSpec).getMacSizeInBits() / 8);
+            }
+            else
+            {
+                throw new InvalidParameterSpecException("AlgorithmParameterSpec class not recognized: " + paramSpec.getClass().getName());
+            }
+        }
+
+        protected void engineInit(byte[] params)
+            throws IOException
+        {
+            ccmParams = CCMParameters.getInstance(params);
+        }
+
+        protected void engineInit(byte[] params, String format)
+            throws IOException
+        {
+            if (!isASN1FormatString(format))
+            {
+                throw new IOException("unknown format specified");
+            }
+
+            ccmParams = CCMParameters.getInstance(params);
+        }
+
+        protected byte[] engineGetEncoded()
+            throws IOException
+        {
+            return ccmParams.getEncoded();
+        }
+
+        protected byte[] engineGetEncoded(String format)
+            throws IOException
+        {
+            if (!isASN1FormatString(format))
+            {
+                throw new IOException("unknown format specified");
+            }
+
+            return ccmParams.getEncoded();
+        }
+
+        protected String engineToString()
+        {
+            return "CCM";
+        }
+
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == AlgorithmParameterSpec.class || GcmSpecUtil.isGcmSpec(paramSpec))
+            {
+                if (GcmSpecUtil.gcmSpecExists())
+                {
+                    return GcmSpecUtil.extractGcmSpec(ccmParams.toASN1Primitive());
+                }
+                return new AEADParameterSpec(ccmParams.getNonce(), ccmParams.getIcvLen() * 8);
+            }
+            if (paramSpec == AEADParameterSpec.class)
+            {
+                return new AEADParameterSpec(ccmParams.getNonce(), ccmParams.getIcvLen() * 8);
+            }
+            if (paramSpec == IvParameterSpec.class)
+            {
+                return new IvParameterSpec(ccmParams.getNonce());
+            }
+
+            throw new InvalidParameterSpecException("AlgorithmParameterSpec not recognized: " + paramSpec.getName());
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends SymmetricAlgorithmProvider
+    {
+        private static final String PREFIX = AES.class.getName();
+        
+        /**
+         * These three got introduced in some messages as a result of a typo in an
+         * early document. We don't produce anything using these OID values, but we'll
+         * read them.
+         */
+        private static final String wrongAES128 = "2.16.840.1.101.3.4.2";
+        private static final String wrongAES192 = "2.16.840.1.101.3.4.22";
+        private static final String wrongAES256 = "2.16.840.1.101.3.4.42";
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("AlgorithmParameters.AES", PREFIX + "$AlgParams");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES128, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES192, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES256, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+
+            provider.addAlgorithm("AlgorithmParameters.GCM", PREFIX + "$AlgParamsGCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_GCM, "GCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_GCM, "GCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_GCM, "GCM");
+            
+            provider.addAlgorithm("AlgorithmParameters.CCM", PREFIX + "$AlgParamsCCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_CCM, "CCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CCM, "CCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CCM, "CCM");
+
+            provider.addAlgorithm("AlgorithmParameterGenerator.AES", PREFIX + "$AlgParamGen");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAttributes("Cipher.AES", generalAesAttributes);
+            provider.addAlgorithm("Cipher.AES", PREFIX + "$ECB");
+            provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES128, "AES");
+            provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES192, "AES");
+            provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES256, "AES");
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$ECB");
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$ECB");
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$ECB");
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$CBC");
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$CBC");
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$CBC");
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$OFB");
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$OFB");
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$OFB");
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$CFB");
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$CFB");
+            provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$CFB");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAttributes("Cipher.AESWRAP", generalAesAttributes);
+            provider.addAlgorithm("Cipher.AESWRAP", PREFIX + "$Wrap");
+            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
+            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
+            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
+            provider.addAlgorithm("Alg.Alias.Cipher.AESKW", "AESWRAP");
+
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAttributes("Cipher.AESWRAPPAD", generalAesAttributes);
+            provider.addAlgorithm("Cipher.AESWRAPPAD", PREFIX + "$WrapPad");
+            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes128_wrap_pad, "AESWRAPPAD");
+            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes192_wrap_pad, "AESWRAPPAD");
+            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes256_wrap_pad, "AESWRAPPAD");
+            provider.addAlgorithm("Alg.Alias.Cipher.AESKWP", "AESWRAPPAD");
+
+            provider.addAlgorithm("Cipher.AESRFC3211WRAP", PREFIX + "$RFC3211Wrap");
+            provider.addAlgorithm("Cipher.AESRFC5649WRAP", PREFIX + "$RFC5649Wrap");
+
+            provider.addAlgorithm("AlgorithmParameterGenerator.CCM", PREFIX + "$AlgParamGenCCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CCM, "CCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CCM, "CCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CCM, "CCM");
+
+            provider.addAttributes("Cipher.CCM", generalAesAttributes);
+            provider.addAlgorithm("Cipher.CCM", PREFIX + "$CCM");
+            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes128_CCM, "CCM");
+            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes192_CCM, "CCM");
+            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes256_CCM, "CCM");
+
+            provider.addAlgorithm("AlgorithmParameterGenerator.GCM", PREFIX + "$AlgParamGenGCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_GCM, "GCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_GCM, "GCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_GCM, "GCM");
+            
+            provider.addAttributes("Cipher.AES/GCM/NOPADDING", generalAesAttributes);
+            provider.addAlgorithm("Cipher.AES/GCM/NOPADDING", PREFIX + "$GCM");
+            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_GCM, "AES/GCM/NOPADDING");
+            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_GCM, "AES/GCM/NOPADDING");
+            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_GCM, "AES/GCM/NOPADDING");
+            
+            provider.addAlgorithm("KeyGenerator.AES", PREFIX + "$KeyGen");
+            provider.addAlgorithm("KeyGenerator." + wrongAES128, PREFIX + "$KeyGen128");
+            provider.addAlgorithm("KeyGenerator." + wrongAES192, PREFIX + "$KeyGen192");
+            provider.addAlgorithm("KeyGenerator." + wrongAES256, PREFIX + "$KeyGen256");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$KeyGen128");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$KeyGen128");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$KeyGen128");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$KeyGen128");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$KeyGen192");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$KeyGen192");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$KeyGen192");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$KeyGen192");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$KeyGen256");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$KeyGen256");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$KeyGen256");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$KeyGen256");
+            provider.addAlgorithm("KeyGenerator.AESWRAP", PREFIX + "$KeyGen");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_wrap, PREFIX + "$KeyGen128");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_wrap, PREFIX + "$KeyGen192");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_wrap, PREFIX + "$KeyGen256");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_GCM, PREFIX + "$KeyGen128");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_GCM, PREFIX + "$KeyGen192");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_GCM, PREFIX + "$KeyGen256");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_CCM, PREFIX + "$KeyGen128");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_CCM, PREFIX + "$KeyGen192");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_CCM, PREFIX + "$KeyGen256");
+            provider.addAlgorithm("KeyGenerator.AESWRAPPAD", PREFIX + "$KeyGen");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_wrap_pad, PREFIX + "$KeyGen128");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_wrap_pad, PREFIX + "$KeyGen192");
+            provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_wrap_pad, PREFIX + "$KeyGen256");
+
+            provider.addAlgorithm("Mac.AESCMAC", PREFIX + "$AESCMAC");
+
+            provider.addAlgorithm("Mac.AESCCMMAC", PREFIX + "$AESCCMMAC");
+            provider.addAlgorithm("Alg.Alias.Mac." + NISTObjectIdentifiers.id_aes128_CCM.getId(), "AESCCMMAC");
+            provider.addAlgorithm("Alg.Alias.Mac." + NISTObjectIdentifiers.id_aes192_CCM.getId(), "AESCCMMAC");
+            provider.addAlgorithm("Alg.Alias.Mac." + NISTObjectIdentifiers.id_aes256_CCM.getId(), "AESCCMMAC");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc, "PBEWITHSHAAND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc, "PBEWITHSHAAND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc, "PBEWITHSHAAND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc, "PBEWITHSHA256AND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc, "PBEWITHSHA256AND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc, "PBEWITHSHA256AND256BITAES-CBC-BC");
+
+            provider.addAlgorithm("Cipher.PBEWITHSHAAND128BITAES-CBC-BC", PREFIX + "$PBEWithSHA1AESCBC128");
+            provider.addAlgorithm("Cipher.PBEWITHSHAAND192BITAES-CBC-BC", PREFIX + "$PBEWithSHA1AESCBC192");
+            provider.addAlgorithm("Cipher.PBEWITHSHAAND256BITAES-CBC-BC", PREFIX + "$PBEWithSHA1AESCBC256");
+            provider.addAlgorithm("Cipher.PBEWITHSHA256AND128BITAES-CBC-BC", PREFIX + "$PBEWithSHA256AESCBC128");
+            provider.addAlgorithm("Cipher.PBEWITHSHA256AND192BITAES-CBC-BC", PREFIX + "$PBEWithSHA256AESCBC192");
+            provider.addAlgorithm("Cipher.PBEWITHSHA256AND256BITAES-CBC-BC", PREFIX + "$PBEWithSHA256AESCBC256");
+            
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAAND128BITAES-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAAND192BITAES-BC", "PBEWITHSHAAND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAAND256BITAES-BC", "PBEWITHSHAAND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND128BITAES-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND192BITAES-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND256BITAES-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND128BITAES-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND192BITAES-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND256BITAES-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND128BITAES-CBC-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND192BITAES-CBC-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND256BITAES-CBC-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA256AND128BITAES-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA256AND192BITAES-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA256AND256BITAES-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND128BITAES-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND192BITAES-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND256BITAES-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
+
+            provider.addAlgorithm("Cipher.PBEWITHMD5AND128BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
+            provider.addAlgorithm("Cipher.PBEWITHMD5AND192BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
+            provider.addAlgorithm("Cipher.PBEWITHMD5AND256BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
+
+            // BEGIN Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("SecretKeyFactory.AES", PREFIX + "$KeyFactory");
+            // provider.addAlgorithm("SecretKeyFactory", NISTObjectIdentifiers.aes, PREFIX + "$KeyFactory");
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND128BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And128BitAESCBCOpenSSL");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND192BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And192BitAESCBCOpenSSL");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND256BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And256BitAESCBCOpenSSL");
+            
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND128BITAES-CBC-BC", PREFIX + "$PBEWithSHAAnd128BitAESBC");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND192BITAES-CBC-BC", PREFIX + "$PBEWithSHAAnd192BitAESBC");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND256BITAES-CBC-BC", PREFIX + "$PBEWithSHAAnd256BitAESBC");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHA256AND128BITAES-CBC-BC", PREFIX + "$PBEWithSHA256And128BitAESBC");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHA256AND192BITAES-CBC-BC", PREFIX + "$PBEWithSHA256And192BitAESBC");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHA256AND256BITAES-CBC-BC", PREFIX + "$PBEWithSHA256And256BitAESBC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND128BITAES-CBC-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND192BITAES-CBC-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND256BITAES-CBC-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND128BITAES-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND192BITAES-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND256BITAES-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc, "PBEWITHSHAAND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc, "PBEWITHSHAAND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc, "PBEWITHSHAAND256BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc, "PBEWITHSHA256AND128BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc, "PBEWITHSHA256AND192BITAES-CBC-BC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc, "PBEWITHSHA256AND256BITAES-CBC-BC");
+            
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITAES-CBC-BC", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND192BITAES-CBC-BC", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND256BITAES-CBC-BC", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND128BITAES-CBC-BC", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND192BITAES-CBC-BC", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND256BITAES-CBC-BC", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND128BITAES-CBC-BC","PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND192BITAES-CBC-BC","PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND256BITAES-CBC-BC","PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND128BITAES-CBC-BC","PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND192BITAES-CBC-BC","PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND256BITAES-CBC-BC","PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND128BITAES-CBC-BC","PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND192BITAES-CBC-BC","PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND256BITAES-CBC-BC","PKCS12PBE"); 
+            
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
+
+            // BEGIN Android-removed: Unsupported algorithms
+            // addGMacAlgorithm(provider, "AES", PREFIX + "$AESGMAC", PREFIX + "$KeyGen128");
+            // addPoly1305Algorithm(provider, "AES", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
+            // END Android-removed: Unsupported algorithms
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/ARC4.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
new file mode 100644
index 0000000..852248c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
@@ -0,0 +1,147 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.engines.RC4Engine;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class ARC4
+{
+    private ARC4()
+    {
+    }
+    
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Base
+        extends BaseStreamCipher
+    {
+        public Base()
+        {
+            super(new RC4Engine(), 0);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGen
+        extends BaseKeyGenerator
+    {
+        public KeyGen()
+        {
+            // Android-changed: Use ARC4 for algorithm name to match name used in provider
+            // super("RC4", 128, new CipherKeyGenerator());
+            super("ARC4", 128, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd128BitRC4
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAnd128BitKeyFactory
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHAAnd128BitKeyFactory()
+        {
+            super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 128, 0);
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd40BitRC4
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAnd40BitKeyFactory
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHAAnd40BitKeyFactory()
+        {
+            super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 40, 0);
+        }
+    }
+
+
+    /**
+     * PBEWithSHAAnd128BitRC4
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAnd128Bit
+        extends BaseStreamCipher
+    {
+        public PBEWithSHAAnd128Bit()
+        {
+            super(new RC4Engine(), 0, 128, SHA1);
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd40BitRC4
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAnd40Bit
+        extends BaseStreamCipher
+    {
+        public PBEWithSHAAnd40Bit()
+        {
+            super(new RC4Engine(), 0, 40, SHA1);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = ARC4.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("Cipher.ARC4", PREFIX + "$Base");
+            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.rc4, "ARC4");
+            provider.addAlgorithm("Alg.Alias.Cipher.ARCFOUR", "ARC4");
+            provider.addAlgorithm("Alg.Alias.Cipher.RC4", "ARC4");
+            */
+            // END Android-removed: Unsupported algorithms
+            provider.addAlgorithm("KeyGenerator.ARC4", PREFIX + "$KeyGen");
+            provider.addAlgorithm("Alg.Alias.KeyGenerator.RC4", "ARC4");
+            provider.addAlgorithm("Alg.Alias.KeyGenerator.1.2.840.113549.3.4", "ARC4");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND128BITRC4", PREFIX + "$PBEWithSHAAnd128BitKeyFactory");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND40BITRC4", PREFIX + "$PBEWithSHAAnd40BitKeyFactory");
+
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC4", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC4", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDRC4", "PKCS12PBE");
+            provider.addAlgorithm("Cipher.PBEWITHSHAAND128BITRC4", PREFIX + "$PBEWithSHAAnd128Bit");
+            provider.addAlgorithm("Cipher.PBEWITHSHAAND40BITRC4", PREFIX + "$PBEWithSHAAnd40Bit");
+
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, "PBEWITHSHAAND128BITRC4");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, "PBEWITHSHAAND40BITRC4");
+
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC4", "PBEWITHSHAAND128BITRC4");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC4", "PBEWITHSHAAND40BITRC4");
+
+            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, "PBEWITHSHAAND128BITRC4");
+            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, "PBEWITHSHAAND40BITRC4");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
new file mode 100644
index 0000000..9918d36
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
@@ -0,0 +1,114 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+import com.android.internal.org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.engines.BlowfishEngine;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.macs.CMac;
+import com.android.internal.org.bouncycastle.crypto.modes.CBCBlockCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class Blowfish
+{
+    private Blowfish()
+    {
+    }
+    
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class ECB
+        extends BaseBlockCipher
+    {
+        public ECB()
+        {
+            super(new BlowfishEngine());
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class CBC
+        extends BaseBlockCipher
+    {
+        public CBC()
+        {
+            super(new CBCBlockCipher(new BlowfishEngine()), 64);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class CMAC
+        extends BaseMac
+    {
+        public CMAC()
+        {
+            super(new CMac(new BlowfishEngine()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGen
+        extends BaseKeyGenerator
+    {
+        public KeyGen()
+        {
+            super("Blowfish", 128, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class AlgParams
+        extends IvAlgorithmParameters
+    {
+        protected String engineToString()
+        {
+            return "Blowfish IV";
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = Blowfish.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("Mac.BLOWFISHCMAC", PREFIX + "$CMAC");
+            provider.addAlgorithm("Cipher.BLOWFISH", PREFIX + "$ECB");
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("Cipher", MiscObjectIdentifiers.cryptlib_algorithm_blowfish_CBC, PREFIX + "$CBC");
+            provider.addAlgorithm("KeyGenerator.BLOWFISH", PREFIX + "$KeyGen");
+            provider.addAlgorithm("Alg.Alias.KeyGenerator", MiscObjectIdentifiers.cryptlib_algorithm_blowfish_CBC, "BLOWFISH");
+            provider.addAlgorithm("AlgorithmParameters.BLOWFISH", PREFIX + "$AlgParams");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters", MiscObjectIdentifiers.cryptlib_algorithm_blowfish_CBC, "BLOWFISH");
+
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/DES.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/DES.java
new file mode 100644
index 0000000..169497b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/DES.java
@@ -0,0 +1,589 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.PasswordConverter;
+import com.android.internal.org.bouncycastle.crypto.engines.DESEngine;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+import com.android.internal.org.bouncycastle.crypto.generators.DESKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+// import org.bouncycastle.crypto.macs.CMac;
+// import org.bouncycastle.crypto.macs.ISO9797Alg3Mac;
+import com.android.internal.org.bouncycastle.crypto.modes.CBCBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import com.android.internal.org.bouncycastle.crypto.params.DESParameters;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.PBKDF1Key;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.PBE;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class DES
+{
+    private DES()
+    {
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class ECB
+        extends BaseBlockCipher
+    {
+        public ECB()
+        {
+            super(new DESEngine());
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class CBC
+        extends BaseBlockCipher
+    {
+        public CBC()
+        {
+            super(new CBCBlockCipher(new DESEngine()), 64);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    /**
+     * DES   CFB8
+     *
+    public static class DESCFB8
+        extends BaseMac
+    {
+        public DESCFB8()
+        {
+            super(new CFBBlockCipherMac(new DESEngine()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * DES64
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class DES64
+        extends BaseMac
+    {
+        public DES64()
+        {
+            super(new CBCBlockCipherMac(new DESEngine(), 64));
+        }
+    }
+
+    /**
+     * DES64with7816-4Padding
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class DES64with7816d4
+        extends BaseMac
+    {
+        public DES64with7816d4()
+        {
+            super(new CBCBlockCipherMac(new DESEngine(), 64, new ISO7816d4Padding()));
+        }
+    }
+    
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class CBCMAC
+        extends BaseMac
+    {
+        public CBCMAC()
+        {
+            super(new CBCBlockCipherMac(new DESEngine()));
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    static public class CMAC
+        extends BaseMac
+    {
+        public CMAC()
+        {
+            super(new CMac(new DESEngine()));
+        }
+    }
+
+    /**
+     * DES9797Alg3with7816-4Padding
+     *
+    public static class DES9797Alg3with7816d4
+        extends BaseMac
+    {
+        public DES9797Alg3with7816d4()
+        {
+            super(new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()));
+        }
+    }
+
+    /**
+     * DES9797Alg3
+     *
+    public static class DES9797Alg3
+        extends BaseMac
+    {
+        public DES9797Alg3()
+        {
+            super(new ISO9797Alg3Mac(new DESEngine()));
+        }
+    }
+
+    public static class RFC3211
+        extends BaseWrapCipher
+    {
+        public RFC3211()
+        {
+            super(new RFC3211WrapEngine(new DESEngine()), 8);
+        }
+    }
+
+    public static class AlgParamGen
+        extends BaseAlgorithmParameterGenerator
+    {
+        protected void engineInit(
+            AlgorithmParameterSpec genParamSpec,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            byte[]  iv = new byte[8];
+
+            if (random == null)
+            {
+                random = CryptoServicesRegistrar.getSecureRandom();
+            }
+
+            random.nextBytes(iv);
+
+            AlgorithmParameters params;
+
+            try
+            {
+                params = createParametersInstance("DES");
+                params.init(new IvParameterSpec(iv));
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+
+            return params;
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+  /**
+     * DES - the default for this is to generate a key in
+     * a-b-a format that's 24 bytes long but has 16 bytes of
+     * key material (the first 8 bytes is repeated as the last
+     * 8 bytes). If you give it a size, you'll get just what you
+     * asked for.
+ * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("DES", 64, new DESKeyGenerator());
+        }
+
+        protected void engineInit(
+            int             keySize,
+            SecureRandom random)
+        {
+            super.engineInit(keySize, random);
+        }
+
+        protected SecretKey engineGenerateKey()
+        {
+            if (uninitialised)
+            {
+                engine.init(new KeyGenerationParameters(CryptoServicesRegistrar.getSecureRandom(), defaultKeySize));
+                uninitialised = false;
+            }
+
+            return new SecretKeySpec(engine.generateKey(), algName);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class KeyFactory
+        extends BaseSecretKeyFactory
+    {
+        public KeyFactory()
+        {
+            super("DES", null);
+        }
+
+        protected KeySpec engineGetKeySpec(
+            SecretKey key,
+            Class keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec == null)
+            {
+                throw new InvalidKeySpecException("keySpec parameter is null");
+            }
+            if (key == null)
+            {
+                throw new InvalidKeySpecException("key parameter is null");
+            }
+
+            if (SecretKeySpec.class.isAssignableFrom(keySpec))
+            {
+                return new SecretKeySpec(key.getEncoded(), algName);
+            }
+            else if (DESKeySpec.class.isAssignableFrom(keySpec))
+            {
+                byte[]  bytes = key.getEncoded();
+
+                try
+                {
+                    return new DESKeySpec(bytes);
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+
+            throw new InvalidKeySpecException("Invalid KeySpec");
+        }
+
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof DESKeySpec)
+            {
+                DESKeySpec desKeySpec = (DESKeySpec)keySpec;
+                return new SecretKeySpec(desKeySpec.getKey(), "DES");
+            }
+
+            return super.engineGenerateSecret(keySpec);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class DESPBEKeyFactory
+        extends BaseSecretKeyFactory
+    {
+        private boolean forCipher;
+        private int     scheme;
+        private int     digest;
+        private int     keySize;
+        private int     ivSize;
+
+        public DESPBEKeyFactory(
+            String              algorithm,
+            ASN1ObjectIdentifier oid,
+            boolean             forCipher,
+            int                 scheme,
+            int                 digest,
+            int                 keySize,
+            int                 ivSize)
+        {
+            super(algorithm, oid);
+
+            this.forCipher = forCipher;
+            this.scheme = scheme;
+            this.digest = digest;
+            this.keySize = keySize;
+            this.ivSize = ivSize;
+        }
+
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PBEKeySpec)
+            {
+                PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+                CipherParameters param;
+
+                if (pbeSpec.getSalt() == null)
+                {
+                    // BEGIN Android-removed: Unsupported algorithms
+                    /*
+                    if (scheme == PKCS5S1 || scheme == PKCS5S1_UTF8)
+                    {
+                        return new PBKDF1Key(pbeSpec.getPassword(),
+                            scheme == PKCS5S1 ? PasswordConverter.ASCII : PasswordConverter.UTF8);
+                    }
+                    else
+                    {
+                    */
+                    // END Android-removed: Unsupported algorithms
+                        return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+                    /*
+                    }
+                    */
+                }
+
+                if (forCipher)
+                {
+                    param = PBE.Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+                }
+                else
+                {
+                    param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+                }
+
+                KeyParameter kParam;
+                if (param instanceof ParametersWithIV)
+                {
+                    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+                }
+                else
+                {
+                    kParam = (KeyParameter)param;
+                }
+
+                DESParameters.setOddParity(kParam.getKey());
+
+                return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+            }
+
+            throw new InvalidKeySpecException("Invalid KeySpec");
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    /**
+     * PBEWithMD2AndDES
+     *
+    static public class PBEWithMD2KeyFactory
+        extends DESPBEKeyFactory
+    {
+        public PBEWithMD2KeyFactory()
+        {
+            super("PBEwithMD2andDES", PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, true, PKCS5S1, MD2, 64, 64);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * PBEWithMD5AndDES
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithMD5KeyFactory
+        extends DESPBEKeyFactory
+    {
+        public PBEWithMD5KeyFactory()
+        {
+            super("PBEwithMD5andDES", PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, true, PKCS5S1, MD5, 64, 64);
+        }
+    }
+
+    /**
+     * PBEWithSHA1AndDES
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA1KeyFactory
+        extends DESPBEKeyFactory
+    {
+        public PBEWithSHA1KeyFactory()
+        {
+            super("PBEwithSHA1andDES", PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, true, PKCS5S1, SHA1, 64, 64);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    /**
+     * PBEWithMD2AndDES
+     *
+    static public class PBEWithMD2
+        extends BaseBlockCipher
+    {
+        public PBEWithMD2()
+        {
+            super(new CBCBlockCipher(new DESEngine()), PKCS5S1, MD2, 64, 8);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * PBEWithMD5AndDES
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithMD5
+        extends BaseBlockCipher
+    {
+        public PBEWithMD5()
+        {
+            super(new CBCBlockCipher(new DESEngine()), PKCS5S1, MD5, 64, 8);
+        }
+    }
+
+    /**
+     * PBEWithSHA1AndDES
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA1
+        extends BaseBlockCipher
+    {
+        public PBEWithSHA1()
+        {
+            super(new CBCBlockCipher(new DESEngine()), PKCS5S1, SHA1, 64, 8);
+        }
+    }
+    
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = DES.class.getName();
+        private static final String PACKAGE = "com.android.internal.org.bouncycastle.jcajce.provider.symmetric"; // JDK 1.2
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+
+            provider.addAlgorithm("Cipher.DES", PREFIX + "$ECB");
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("Cipher", OIWObjectIdentifiers.desCBC, PREFIX + "$CBC");
+
+            addAlias(provider, OIWObjectIdentifiers.desCBC, "DES");
+
+            provider.addAlgorithm("Cipher.DESRFC3211WRAP", PREFIX + "$RFC3211");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAlgorithm("KeyGenerator.DES", PREFIX + "$KeyGenerator");
+
+            provider.addAlgorithm("SecretKeyFactory.DES", PREFIX + "$KeyFactory");
+
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("Mac.DESCMAC", PREFIX + "$CMAC");
+            provider.addAlgorithm("Mac.DESMAC", PREFIX + "$CBCMAC");
+            provider.addAlgorithm("Alg.Alias.Mac.DES", "DESMAC");
+
+            provider.addAlgorithm("Mac.DESMAC/CFB8", PREFIX + "$DESCFB8");
+            provider.addAlgorithm("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
+
+            provider.addAlgorithm("Mac.DESMAC64", PREFIX + "$DES64");
+            provider.addAlgorithm("Alg.Alias.Mac.DES64", "DESMAC64");
+
+            provider.addAlgorithm("Mac.DESMAC64WITHISO7816-4PADDING", PREFIX + "$DES64with7816d4");
+            provider.addAlgorithm("Alg.Alias.Mac.DES64WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+            provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1MACWITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+            provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+
+            provider.addAlgorithm("Mac.DESWITHISO9797", PREFIX + "$DES9797Alg3");
+            provider.addAlgorithm("Alg.Alias.Mac.DESISO9797MAC", "DESWITHISO9797");
+
+            provider.addAlgorithm("Mac.ISO9797ALG3MAC", PREFIX + "$DES9797Alg3");
+            provider.addAlgorithm("Alg.Alias.Mac.ISO9797ALG3", "ISO9797ALG3MAC");
+            provider.addAlgorithm("Mac.ISO9797ALG3WITHISO7816-4PADDING", PREFIX + "$DES9797Alg3with7816d4");
+            provider.addAlgorithm("Alg.Alias.Mac.ISO9797ALG3MACWITHISO7816-4PADDING", "ISO9797ALG3WITHISO7816-4PADDING");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAlgorithm("AlgorithmParameters.DES", PACKAGE + ".util.IvAlgorithmParameters");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters", OIWObjectIdentifiers.desCBC, "DES");
+
+            // BEGIN Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("AlgorithmParameterGenerator.DES",  PREFIX + "$AlgParamGen");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + OIWObjectIdentifiers.desCBC, "DES");
+            //
+            // provider.addAlgorithm("Cipher.PBEWITHMD2ANDDES", PREFIX + "$PBEWithMD2");
+            // END Android-removed: Unsupported algorithms
+            provider.addAlgorithm("Cipher.PBEWITHMD5ANDDES", PREFIX + "$PBEWithMD5");
+            provider.addAlgorithm("Cipher.PBEWITHSHA1ANDDES", PREFIX + "$PBEWithSHA1");
+            
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
+            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
+            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
+
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHMD2ANDDES-CBC", "PBEWITHMD2ANDDES");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHMD5ANDDES-CBC", "PBEWITHMD5ANDDES");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1ANDDES-CBC", "PBEWITHSHA1ANDDES");
+
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("SecretKeyFactory.PBEWITHMD2ANDDES", PREFIX + "$PBEWithMD2KeyFactory");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5ANDDES", PREFIX + "$PBEWithMD5KeyFactory");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHA1ANDDES", PREFIX + "$PBEWithSHA1KeyFactory");
+
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHMD2ANDDES-CBC", "PBEWITHMD2ANDDES");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHMD5ANDDES-CBC", "PBEWITHMD5ANDDES");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1ANDDES-CBC", "PBEWITHSHA1ANDDES");
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
+        }
+
+        private void addAlias(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name)
+        {
+            provider.addAlgorithm("Alg.Alias.KeyGenerator." + oid.getId(), name);
+            provider.addAlgorithm("Alg.Alias.KeyFactory." + oid.getId(), name);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/DESede.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/DESede.java
new file mode 100644
index 0000000..2cbe3fd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/DESede.java
@@ -0,0 +1,517 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+// Android-removed: Unsupported algorithms
+// import java.security.AlgorithmParameters;
+// import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+// Android-removed: Unsupported algorithms
+// import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESedeKeySpec;
+// Android-removed: Unsupported algorithms
+// import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+import com.android.internal.org.bouncycastle.crypto.engines.DESedeEngine;
+import com.android.internal.org.bouncycastle.crypto.engines.DESedeWrapEngine;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+import com.android.internal.org.bouncycastle.crypto.generators.DESedeKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+// import org.bouncycastle.crypto.macs.CMac;
+import com.android.internal.org.bouncycastle.crypto.modes.CBCBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class DESede
+{
+    private DESede()
+    {
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class ECB
+        extends BaseBlockCipher
+    {
+        public ECB()
+        {
+            super(new DESedeEngine());
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class CBC
+        extends BaseBlockCipher
+    {
+        public CBC()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()), 64);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    /**
+     * DESede   CFB8
+     *
+    public static class DESedeCFB8
+        extends BaseMac
+    {
+        public DESedeCFB8()
+        {
+            super(new CFBBlockCipherMac(new DESedeEngine()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * DESede64
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class DESede64
+        extends BaseMac
+    {
+        public DESede64()
+        {
+            super(new CBCBlockCipherMac(new DESedeEngine(), 64));
+        }
+    }
+
+    /**
+     * DESede64with7816-4Padding
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class DESede64with7816d4
+        extends BaseMac
+    {
+        public DESede64with7816d4()
+        {
+            super(new CBCBlockCipherMac(new DESedeEngine(), 64, new ISO7816d4Padding()));
+        }
+    }
+    
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class CBCMAC
+        extends BaseMac
+    {
+        public CBCMAC()
+        {
+            super(new CBCBlockCipherMac(new DESedeEngine()));
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    static public class CMAC
+        extends BaseMac
+    {
+        public CMAC()
+        {
+            super(new CMac(new DESedeEngine()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Wrap
+        extends BaseWrapCipher
+    {
+        public Wrap()
+        {
+            super(new DESedeWrapEngine());
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class RFC3211
+        extends BaseWrapCipher
+    {
+        public RFC3211()
+        {
+            super(new RFC3211WrapEngine(new DESedeEngine()), 8);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+  /**
+     * DESede - the default for this is to generate a key in
+     * a-b-a format that's 24 bytes long but has 16 bytes of
+     * key material (the first 8 bytes is repeated as the last
+     * 8 bytes). If you give it a size, you'll get just what you
+     * asked for.
+ * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        private boolean     keySizeSet = false;
+
+        public KeyGenerator()
+        {
+            super("DESede", 192, new DESedeKeyGenerator());
+        }
+
+        protected void engineInit(
+            int             keySize,
+            SecureRandom random)
+        {
+            super.engineInit(keySize, random);
+            keySizeSet = true;
+        }
+
+        protected SecretKey engineGenerateKey()
+        {
+            if (uninitialised)
+            {
+                engine.init(new KeyGenerationParameters(CryptoServicesRegistrar.getSecureRandom(), defaultKeySize));
+                uninitialised = false;
+            }
+
+            //
+            // if no key size has been defined generate a 24 byte key in
+            // the a-b-a format
+            //
+            if (!keySizeSet)
+            {
+                byte[]     k = engine.generateKey();
+
+                System.arraycopy(k, 0, k, 16, 8);
+
+                return new SecretKeySpec(k, algName);
+            }
+            else
+            {
+                return new SecretKeySpec(engine.generateKey(), algName);
+            }
+        }
+    }
+
+    /**
+     * generate a desEDE key in the a-b-c format.
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class KeyGenerator3
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator3()
+        {
+            super("DESede3", 192, new DESedeKeyGenerator());
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd3-KeyTripleDES-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAndDES3Key
+        extends BaseBlockCipher
+    {
+        public PBEWithSHAAndDES3Key()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()), PKCS12, SHA1, 192, 8);
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd2-KeyTripleDES-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAndDES2Key
+        extends BaseBlockCipher
+    {
+        public PBEWithSHAAndDES2Key()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()), PKCS12, SHA1, 128, 8);
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd3-KeyTripleDES-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAndDES3KeyFactory
+        extends DES.DESPBEKeyFactory
+    {
+        public PBEWithSHAAndDES3KeyFactory()
+        {
+            super("PBEwithSHAandDES3Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, true, PKCS12, SHA1, 192, 64);
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd2-KeyTripleDES-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAndDES2KeyFactory
+        extends DES.DESPBEKeyFactory
+    {
+        public PBEWithSHAAndDES2KeyFactory()
+        {
+            super("PBEwithSHAandDES2Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, true, PKCS12, SHA1, 128, 64);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class AlgParamGen
+        extends BaseAlgorithmParameterGenerator
+    {
+        protected void engineInit(
+            AlgorithmParameterSpec genParamSpec,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            byte[]  iv = new byte[8];
+
+            if (random == null)
+            {
+                random = CryptoServicesRegistrar.getSecureRandom();
+            }
+
+            random.nextBytes(iv);
+
+            AlgorithmParameters params;
+
+            try
+            {
+                params = createParametersInstance("DES");
+                params.init(new IvParameterSpec(iv));
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+
+            return params;
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class KeyFactory
+        extends BaseSecretKeyFactory
+    {
+        public KeyFactory()
+        {
+            super("DESede", null);
+        }
+
+        protected KeySpec engineGetKeySpec(
+            SecretKey key,
+            Class keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec == null)
+            {
+                throw new InvalidKeySpecException("keySpec parameter is null");
+            }
+            if (key == null)
+            {
+                throw new InvalidKeySpecException("key parameter is null");
+            }
+
+            if (SecretKeySpec.class.isAssignableFrom(keySpec))
+            {
+                return new SecretKeySpec(key.getEncoded(), algName);
+            }
+            else if (DESedeKeySpec.class.isAssignableFrom(keySpec))
+            {
+                byte[]  bytes = key.getEncoded();
+
+                try
+                {
+                    if (bytes.length == 16)
+                    {
+                        byte[]  longKey = new byte[24];
+
+                        System.arraycopy(bytes, 0, longKey, 0, 16);
+                        System.arraycopy(bytes, 0, longKey, 16, 8);
+
+                        return new DESedeKeySpec(longKey);
+                    }
+                    else
+                    {
+                        return new DESedeKeySpec(bytes);
+                    }
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+
+            throw new InvalidKeySpecException("Invalid KeySpec");
+        }
+
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof DESedeKeySpec)
+            {
+                DESedeKeySpec desKeySpec = (DESedeKeySpec)keySpec;
+                return new SecretKeySpec(desKeySpec.getKey(), "DESede");
+            }
+
+            return super.engineGenerateSecret(keySpec);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = DESede.class.getName();
+        private static final String PACKAGE = "com.android.internal.org.bouncycastle.jcajce.provider.symmetric"; // JDK 1.2
+                
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("Cipher.DESEDE", PREFIX + "$ECB");
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("Cipher", PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$CBC");
+            provider.addAlgorithm("Cipher.DESEDEWRAP", PREFIX + "$Wrap");
+            // BEGIN Android-changed: Make alias of DESEDEWRAP rather than separate algorithm
+            provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWRAP");
+            // END Android-changed: Make alias of DESEDEWRAP rather than separate algorithm
+            // BEGIN Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("Cipher.DESEDERFC3211WRAP", PREFIX + "$RFC3211");
+            // provider.addAlgorithm("Alg.Alias.Cipher.DESEDERFC3217WRAP", "DESEDEWRAP");
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAlgorithm("Alg.Alias.Cipher.TDEA", "DESEDE");
+            provider.addAlgorithm("Alg.Alias.Cipher.TDEAWRAP", "DESEDEWRAP");
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("Alg.Alias.KeyGenerator.TDEA", "DESEDE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.TDEA", "DESEDE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator.TDEA", "DESEDE");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.TDEA", "DESEDE");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            // Android-removed Bouncy Castle's SHA-1 implementation is removed but we still need PBEWithSHAAnd3-KeyTripleDES-CBC
+            // if (provider.hasAlgorithm("MessageDigest", "SHA-1"))
+            {
+                provider.addAlgorithm("Cipher.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES3Key");
+                // BEGIN Android-removed: Unsupported algorithms
+                // provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES3Key");
+                // provider.addAlgorithm("Cipher.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$OldPBEWithSHAAndDES3Key");
+                // END Android-removed: Unsupported algorithms
+                provider.addAlgorithm("Cipher.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES2Key");
+                // Android-removed: Unsupported algorithms
+                // provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES2Key");
+                provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1ANDDESEDE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAAND3-KEYDESEDE-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAAND2-KEYDESEDE-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYDESEDE-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYDESEDE-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1ANDDESEDE-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+            }
+
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("KeyGenerator.DESEDE", PREFIX + "$KeyGenerator");
+            provider.addAlgorithm("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$KeyGenerator3");
+            provider.addAlgorithm("KeyGenerator.DESEDEWRAP", PREFIX + "$KeyGenerator");
+
+            provider.addAlgorithm("SecretKeyFactory.DESEDE", PREFIX + "$KeyFactory");
+
+            provider.addAlgorithm("SecretKeyFactory", OIWObjectIdentifiers.desEDE, PREFIX + "$KeyFactory");
+
+            provider.addAlgorithm("Mac.DESEDECMAC", PREFIX + "$CMAC");
+            provider.addAlgorithm("Mac.DESEDEMAC", PREFIX + "$CBCMAC");
+            provider.addAlgorithm("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
+
+            provider.addAlgorithm("Mac.DESEDEMAC/CFB8", PREFIX + "$DESedeCFB8");
+            provider.addAlgorithm("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
+
+            provider.addAlgorithm("Mac.DESEDEMAC64", PREFIX + "$DESede64");
+            provider.addAlgorithm("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
+
+            provider.addAlgorithm("Mac.DESEDEMAC64WITHISO7816-4PADDING", PREFIX + "$DESede64with7816d4");
+            provider.addAlgorithm("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+            provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+            provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+
+            provider.addAlgorithm("AlgorithmParameters.DESEDE", PACKAGE + ".util.IvAlgorithmParameters");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            // BEGIN Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("AlgorithmParameterGenerator.DESEDE",  PREFIX + "$AlgParamGen");
+            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
+            // END Android-removed: Unsupported algorithms
+
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES3KeyFactory");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES2KeyFactory");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1ANDDESEDE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND2-KEYTRIPLEDES", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES3KEY-CBC", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES2KEY-CBC", "PKCS12PBE");
+
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.3", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.4", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWithSHAAnd3KeyTripleDES", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.3", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.4", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWithSHAAnd3KeyTripleDES",  "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/GcmSpecUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/GcmSpecUtil.java
new file mode 100644
index 0000000..55feea6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/GcmSpecUtil.java
@@ -0,0 +1,68 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.cms.GCMParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.ClassUtil;
+import com.android.internal.org.bouncycastle.util.Integers;
+
+class GcmSpecUtil
+{
+    static final Class gcmSpecClass = ClassUtil.loadClass(GcmSpecUtil.class, "javax.crypto.spec.GCMParameterSpec");
+
+    static boolean gcmSpecExists()
+    {
+        return gcmSpecClass != null;
+    }
+
+    static boolean isGcmSpec(AlgorithmParameterSpec paramSpec)
+    {
+        return gcmSpecClass != null && gcmSpecClass.isInstance(paramSpec);
+    }
+
+    static boolean isGcmSpec(Class paramSpecClass)
+    {
+        return gcmSpecClass == paramSpecClass;
+    }
+
+    static AlgorithmParameterSpec extractGcmSpec(ASN1Primitive spec)
+        throws InvalidParameterSpecException
+    {
+        try
+        {
+            GCMParameters gcmParams = GCMParameters.getInstance(spec);
+            Constructor constructor = gcmSpecClass.getConstructor(new Class[]{Integer.TYPE, byte[].class});
+
+            return (AlgorithmParameterSpec)constructor.newInstance(new Object[] { Integers.valueOf(gcmParams.getIcvLen() * 8), gcmParams.getNonce() });
+        }
+        catch (NoSuchMethodException e)
+        {
+            throw new InvalidParameterSpecException("No constructor found!");   // should never happen
+        }
+        catch (Exception e)
+        {
+            throw new InvalidParameterSpecException("Construction failed: " + e.getMessage());   // should never happen
+        }
+    }
+
+    static GCMParameters extractGcmParameters(AlgorithmParameterSpec paramSpec)
+        throws InvalidParameterSpecException
+    {
+        try
+        {
+            Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
+            Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
+
+            return new GCMParameters((byte[])iv.invoke(paramSpec, new Object[0]), ((Integer)tLen.invoke(paramSpec, new Object[0])).intValue() / 8);
+        }
+        catch (Exception e)
+        {
+            throw new InvalidParameterSpecException("Cannot process GCMParameterSpec");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
new file mode 100644
index 0000000..e069d08
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java
@@ -0,0 +1,677 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.KeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PBKDF2Params;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+// Android-removed: Unneeded imports of files we don't include
+// import org.bouncycastle.crypto.PasswordConverter;
+// import org.bouncycastle.jcajce.PBKDF2Key;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.PBE;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+import com.android.internal.org.bouncycastle.jcajce.spec.PBKDF2KeySpec;
+import com.android.internal.org.bouncycastle.util.Integers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PBEPBKDF2
+{
+    private static final Map prfCodes = new HashMap();
+
+    static
+    {
+        // BEGIN Android-removed: Unsupported algorithm
+        /*
+        prfCodes.put(CryptoProObjectIdentifiers.gostR3411Hmac, Integers.valueOf(PBE.GOST3411));
+        prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA1, Integers.valueOf(PBE.SHA1));
+        prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA256, Integers.valueOf(PBE.SHA256));
+        prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA224, Integers.valueOf(PBE.SHA224));
+        prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA384, Integers.valueOf(PBE.SHA384));
+        prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA512, Integers.valueOf(PBE.SHA512));
+        prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_256, Integers.valueOf(PBE.SHA3_256));
+        prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_224, Integers.valueOf(PBE.SHA3_224));
+        prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_384, Integers.valueOf(PBE.SHA3_384));
+        prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_512, Integers.valueOf(PBE.SHA3_512));
+        */
+        // END Android-removed: Unsupported algorithm
+    }
+
+    private PBEPBKDF2()
+    {
+
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class AlgParams
+        extends BaseAlgorithmParameters
+    {
+        PBKDF2Params params;
+
+        protected byte[] engineGetEncoded()
+        {
+            try
+            {
+                return params.getEncoded(ASN1Encoding.DER);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Oooops! " + e.toString());
+            }
+        }
+
+        protected byte[] engineGetEncoded(
+            String format)
+        {
+            if (this.isASN1FormatString(format))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+            Class paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == PBEParameterSpec.class)
+            {
+                return new PBEParameterSpec(params.getSalt(),
+                    params.getIterationCount().intValue());
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to PBKDF2 PBE parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof PBEParameterSpec))
+            {
+                throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PBKDF2 PBE parameters algorithm parameters object");
+            }
+
+            PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec;
+
+            this.params = new PBKDF2Params(pbeSpec.getSalt(),
+                pbeSpec.getIterationCount());
+        }
+
+        protected void engineInit(
+            byte[] params)
+            throws IOException
+        {
+            this.params = PBKDF2Params.getInstance(ASN1Primitive.fromByteArray(params));
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format)
+            throws IOException
+        {
+            if (this.isASN1FormatString(format))
+            {
+                engineInit(params);
+                return;
+            }
+
+            throw new IOException("Unknown parameters format in PBKDF2 parameters object");
+        }
+
+        protected String engineToString()
+        {
+            return "PBKDF2 Parameters";
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class BasePBKDF2
+        extends BaseSecretKeyFactory
+    {
+        private int scheme;
+        // BEGIN Android-added: Allow to specify a key using only the password.
+        private int keySizeInBits;
+        private int ivSizeInBits;
+        // END Android-added: Allow to specify a key using only the password.
+        private int defaultDigest;
+
+        public BasePBKDF2(String name, int scheme)
+        {
+            this(name, scheme, SHA1);
+        }
+
+        // BEGIN Android-changed: Allow to specify a key using only the password.
+        // public BasePBKDF2(String name, int scheme, int defaultDigest)
+        private BasePBKDF2(
+                String name, int scheme, int digest, int keySizeInBits, int ivSizeInBits)
+        // END Android-changed: Allow to specify a key using only the password.
+        {
+            super(name, PKCSObjectIdentifiers.id_PBKDF2);
+
+            this.scheme = scheme;
+            // BEGIN Android-added: Support key-restricted versions.
+            this.keySizeInBits = keySizeInBits;
+            this.ivSizeInBits = ivSizeInBits;
+            // END Android-added: Support key-restricted versions.
+            this.defaultDigest = digest;
+        }
+
+        // BEGIN Android-added: Allow to specify a key using only the password.
+        private BasePBKDF2(String name, int scheme, int digest) {
+            this(name, scheme, digest, 0, 0);
+        }
+        // END Android-added: Allow to specify a key using only the password.
+
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PBEKeySpec)
+            {
+                PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+
+                // BEGIN Android-added: Allow to specify a key using only the password.
+                // The key will be generated later when other parameters are known.
+                if (pbeSpec.getSalt() == null
+                        && pbeSpec.getIterationCount() == 0
+                        && pbeSpec.getKeyLength() == 0
+                        && pbeSpec.getPassword().length > 0
+                        && keySizeInBits != 0) {
+                    return new BCPBEKey(
+                            this.algName, this.algOid, scheme, defaultDigest, keySizeInBits,
+                            ivSizeInBits, pbeSpec,
+                            // cipherParameters, to be generated when the PBE parameters are known.
+                            null);
+                }
+                // END Android-added: Allow to specify a key using only the password.
+
+                if (pbeSpec.getSalt() == null)
+                {
+                    // Android-changed: Throw an exception if the salt is missing
+                    // return new PBKDF2Key(((PBEKeySpec)keySpec).getPassword(),
+                    //     scheme == PKCS5S2 ? PasswordConverter.ASCII : PasswordConverter.UTF8);
+                    throw new InvalidKeySpecException("missing required salt");
+                }
+
+                if (pbeSpec.getIterationCount() <= 0)
+                {
+                    throw new InvalidKeySpecException("positive iteration count required: "
+                        + pbeSpec.getIterationCount());
+                }
+
+                if (pbeSpec.getKeyLength() <= 0)
+                {
+                    throw new InvalidKeySpecException("positive key length required: "
+                        + pbeSpec.getKeyLength());
+                }
+
+                if (pbeSpec.getPassword().length == 0)
+                {
+                    throw new IllegalArgumentException("password empty");
+                }
+
+                if (pbeSpec instanceof PBKDF2KeySpec)
+                {
+                    PBKDF2KeySpec spec = (PBKDF2KeySpec)pbeSpec;
+
+                    int digest = getDigestCode(spec.getPrf().getAlgorithm());
+                    int keySize = pbeSpec.getKeyLength();
+                    int ivSize = -1;    // JDK 1,2 and earlier does not understand simplified version.
+                    CipherParameters param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+
+                    return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+                }
+                else
+                {
+                    int digest = defaultDigest;
+                    int keySize = pbeSpec.getKeyLength();
+                    int ivSize = -1;    // JDK 1,2 and earlier does not understand simplified version.
+                    CipherParameters param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+
+                    return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+                }
+            }
+
+            throw new InvalidKeySpecException("Invalid KeySpec");
+        }
+
+
+        private int getDigestCode(ASN1ObjectIdentifier algorithm)
+            throws InvalidKeySpecException
+        {
+            Integer code = (Integer)prfCodes.get(algorithm);
+            if (code != null)
+            {
+                return code.intValue();
+            }
+            
+            throw new InvalidKeySpecException("Invalid KeySpec: unknown PRF algorithm " + algorithm);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class PBKDF2withUTF8
+        extends BasePBKDF2
+    {
+        public PBKDF2withUTF8()
+        {
+            super("PBKDF2", PKCS5S2_UTF8);
+        }
+    }
+
+    public static class PBKDF2withSHA224
+        extends BasePBKDF2
+    {
+        public PBKDF2withSHA224()
+        {
+            super("PBKDF2", PKCS5S2_UTF8, SHA224);
+        }
+    }
+
+    public static class PBKDF2withSHA256
+        extends BasePBKDF2
+    {
+        public PBKDF2withSHA256()
+        {
+            super("PBKDF2", PKCS5S2_UTF8, SHA256);
+        }
+    }
+
+    public static class PBKDF2withSHA384
+        extends BasePBKDF2
+    {
+        public PBKDF2withSHA384()
+        {
+            super("PBKDF2", PKCS5S2_UTF8, SHA384);
+        }
+    }
+
+    public static class PBKDF2withSHA512
+        extends BasePBKDF2
+    {
+        public PBKDF2withSHA512()
+        {
+            super("PBKDF2", PKCS5S2_UTF8, SHA512);
+        }
+    }
+
+    public static class PBKDF2withGOST3411
+        extends BasePBKDF2
+    {
+        public PBKDF2withGOST3411()
+        {
+            super("PBKDF2", PKCS5S2_UTF8, GOST3411);
+        }
+    }
+
+    public static class PBKDF2withSHA3_224
+        extends BasePBKDF2
+    {
+        public PBKDF2withSHA3_224()
+        {
+            super("PBKDF2", PKCS5S2_UTF8, SHA3_224);
+        }
+    }
+
+    public static class PBKDF2withSHA3_256
+        extends BasePBKDF2
+    {
+        public PBKDF2withSHA3_256()
+        {
+            super("PBKDF2", PKCS5S2_UTF8, SHA3_256);
+        }
+    }
+
+    public static class PBKDF2withSHA3_384
+        extends BasePBKDF2
+    {
+        public PBKDF2withSHA3_384()
+        {
+            super("PBKDF2", PKCS5S2_UTF8, SHA3_384);
+        }
+    }
+
+    public static class PBKDF2withSHA3_512
+        extends BasePBKDF2
+    {
+        public PBKDF2withSHA3_512()
+        {
+            super("PBKDF2", PKCS5S2_UTF8, SHA3_512);
+        }
+    }
+
+    public static class PBKDF2with8BIT
+        extends BasePBKDF2
+    {
+        public PBKDF2with8BIT()
+        {
+            super("PBKDF2", PKCS5S2);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    // BEGIN Android-added: Android implementations of PBKDF2 algorithms.
+    // See note in Mappings below.
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class BasePBKDF2WithHmacSHA1 extends BasePBKDF2 {
+        public BasePBKDF2WithHmacSHA1(String name, int scheme)
+        {
+            super(name, scheme, SHA1);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBKDF2WithHmacSHA1UTF8
+            extends BasePBKDF2WithHmacSHA1
+    {
+        public PBKDF2WithHmacSHA1UTF8()
+        {
+            super("PBKDF2WithHmacSHA1", PKCS5S2_UTF8);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBKDF2WithHmacSHA18BIT
+            extends BasePBKDF2WithHmacSHA1
+    {
+        public PBKDF2WithHmacSHA18BIT()
+        {
+            super("PBKDF2WithHmacSHA1And8bit", PKCS5S2);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class BasePBKDF2WithHmacSHA224 extends BasePBKDF2 {
+        public BasePBKDF2WithHmacSHA224(String name, int scheme)
+        {
+            super(name, scheme, SHA224);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBKDF2WithHmacSHA224UTF8
+            extends BasePBKDF2WithHmacSHA224
+    {
+        public PBKDF2WithHmacSHA224UTF8()
+        {
+            super("PBKDF2WithHmacSHA224", PKCS5S2_UTF8);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class BasePBKDF2WithHmacSHA256 extends BasePBKDF2 {
+        public BasePBKDF2WithHmacSHA256(String name, int scheme)
+        {
+            super(name, scheme, SHA256);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBKDF2WithHmacSHA256UTF8
+            extends BasePBKDF2WithHmacSHA256
+    {
+        public PBKDF2WithHmacSHA256UTF8()
+        {
+            super("PBKDF2WithHmacSHA256", PKCS5S2_UTF8);
+        }
+    }
+
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class BasePBKDF2WithHmacSHA384 extends BasePBKDF2 {
+        public BasePBKDF2WithHmacSHA384(String name, int scheme)
+        {
+            super(name, scheme, SHA384);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBKDF2WithHmacSHA384UTF8
+            extends BasePBKDF2WithHmacSHA384
+    {
+        public PBKDF2WithHmacSHA384UTF8()
+        {
+            super("PBKDF2WithHmacSHA384", PKCS5S2_UTF8);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class BasePBKDF2WithHmacSHA512 extends BasePBKDF2 {
+        public BasePBKDF2WithHmacSHA512(String name, int scheme)
+        {
+            super(name, scheme, SHA512);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBKDF2WithHmacSHA512UTF8
+            extends BasePBKDF2WithHmacSHA512
+    {
+        public PBKDF2WithHmacSHA512UTF8()
+        {
+            super("PBKDF2WithHmacSHA512", PKCS5S2_UTF8);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA1AndAES_128
+            extends BasePBKDF2 {
+        public PBEWithHmacSHA1AndAES_128() {
+            super("PBEWithHmacSHA1AndAES_128", PKCS5S2_UTF8, SHA1, 128, 128);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA224AndAES_128
+            extends BasePBKDF2 {
+        public PBEWithHmacSHA224AndAES_128() {
+            super("PBEWithHmacSHA224AndAES_128", PKCS5S2_UTF8, SHA224, 128, 128);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA256AndAES_128
+            extends BasePBKDF2 {
+        public PBEWithHmacSHA256AndAES_128() {
+            super("PBEWithHmacSHA256AndAES_128", PKCS5S2_UTF8, SHA256, 128, 128);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA384AndAES_128
+            extends BasePBKDF2 {
+        public PBEWithHmacSHA384AndAES_128() {
+            super("PBEWithHmacSHA384AndAES_128", PKCS5S2_UTF8, SHA384, 128, 128);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA512AndAES_128
+            extends BasePBKDF2 {
+        public PBEWithHmacSHA512AndAES_128() {
+            super("PBEWithHmacSHA512AndAES_128", PKCS5S2_UTF8, SHA512, 128, 128);
+        }
+    }
+
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA1AndAES_256
+            extends BasePBKDF2 {
+        public PBEWithHmacSHA1AndAES_256() {
+            super("PBEWithHmacSHA1AndAES_256", PKCS5S2_UTF8, SHA1, 256, 128);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA224AndAES_256
+            extends BasePBKDF2 {
+        public PBEWithHmacSHA224AndAES_256() {
+            super("PBEWithHmacSHA224AndAES_256", PKCS5S2_UTF8, SHA224, 256, 128);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA256AndAES_256
+            extends BasePBKDF2 {
+        public PBEWithHmacSHA256AndAES_256() {
+            super("PBEWithHmacSHA256AndAES_256", PKCS5S2_UTF8, SHA256, 256, 128);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA384AndAES_256
+            extends BasePBKDF2 {
+        public PBEWithHmacSHA384AndAES_256() {
+            super("PBEWithHmacSHA384AndAES_256", PKCS5S2_UTF8, SHA384, 256, 128);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA512AndAES_256
+            extends BasePBKDF2 {
+        public PBEWithHmacSHA512AndAES_256() {
+            super("PBEWithHmacSHA512AndAES_256", PKCS5S2_UTF8, SHA512, 256, 128);
+        }
+    }
+    // END Android-added: Android implementations of PBKDF2 algorithms.
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = PBEPBKDF2.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // Android-note: Provided classes differ significantly from upstream.
+            // Before BC 1.56, this class was omitted in Android and the algorithms we desired
+            // were provided in org.bouncycastle.jcajce.provider.digest.SHA1.  During that
+            // time, Android added some additional versions of these algorithms for fixed key sizes.
+            // BC eventually consolidated the algorithms into this class.  As a result, when
+            // upgrading to BC 1.56, we added this class but replaced its contents with
+            // our versions.
+            // BEGIN Android-removed: Bouncy Castle versions of algorithms.
+            /*
+            provider.addAlgorithm("AlgorithmParameters.PBKDF2", PREFIX + "$AlgParams");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2", PREFIX + "$PBKDF2withUTF8");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1", "PBKDF2");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1ANDUTF8", "PBKDF2");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHASCII", PREFIX + "$PBKDF2with8BIT");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITH8BIT", "PBKDF2WITHASCII");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WITHHMACSHA1AND8BIT", "PBKDF2WITHASCII");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA224", PREFIX + "$PBKDF2withSHA224");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA256", PREFIX + "$PBKDF2withSHA256");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA384", PREFIX + "$PBKDF2withSHA384");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA512", PREFIX + "$PBKDF2withSHA512");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-224", PREFIX + "$PBKDF2withSHA3_224");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-256", PREFIX + "$PBKDF2withSHA3_256");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-384", PREFIX + "$PBKDF2withSHA3_384");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-512", PREFIX + "$PBKDF2withSHA3_512");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACGOST3411", PREFIX + "$PBKDF2withGOST3411");
+            */
+            // END Android-removed: Bouncy Castle versions of algorithms.
+            // BEGIN Android-added: Android versions of algorithms.
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WithHmacSHA1AndUTF8", "PBKDF2WithHmacSHA1");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2with8BIT", "PBKDF2WithHmacSHA1And8BIT");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2withASCII", "PBKDF2WithHmacSHA1And8BIT");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1", PREFIX + "$PBKDF2WithHmacSHA1UTF8");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA224", PREFIX + "$PBKDF2WithHmacSHA224UTF8");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA256", PREFIX + "$PBKDF2WithHmacSHA256UTF8");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA384", PREFIX + "$PBKDF2WithHmacSHA384UTF8");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA512", PREFIX + "$PBKDF2WithHmacSHA512UTF8");
+            provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA1AndAES_128", PREFIX + "$PBEWithHmacSHA1AndAES_128");
+            provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA224AndAES_128", PREFIX + "$PBEWithHmacSHA224AndAES_128");
+            provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA256AndAES_128", PREFIX + "$PBEWithHmacSHA256AndAES_128");
+            provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA384AndAES_128", PREFIX + "$PBEWithHmacSHA384AndAES_128");
+            provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA512AndAES_128", PREFIX + "$PBEWithHmacSHA512AndAES_128");
+            provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA1AndAES_256", PREFIX + "$PBEWithHmacSHA1AndAES_256");
+            provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA224AndAES_256", PREFIX + "$PBEWithHmacSHA224AndAES_256");
+            provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA256AndAES_256", PREFIX + "$PBEWithHmacSHA256AndAES_256");
+            provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA384AndAES_256", PREFIX + "$PBEWithHmacSHA384AndAES_256");
+            provider.addAlgorithm("SecretKeyFactory.PBEWithHmacSHA512AndAES_256", PREFIX + "$PBEWithHmacSHA512AndAES_256");
+            provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1And8BIT", PREFIX + "$PBKDF2WithHmacSHA18BIT");
+            // END Android-added: Android versions of algorithms.
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBEPKCS12.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBEPKCS12.java
new file mode 100644
index 0000000..1a7d0ba
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBEPKCS12.java
@@ -0,0 +1,130 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.PBEParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PBEPKCS12
+{
+    private PBEPKCS12()
+    {
+
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class AlgParams
+        extends BaseAlgorithmParameters
+    {
+        PKCS12PBEParams params;
+
+        protected byte[] engineGetEncoded()
+        {
+            try
+            {
+                return params.getEncoded(ASN1Encoding.DER);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Oooops! " + e.toString());
+            }
+        }
+
+        protected byte[] engineGetEncoded(
+            String format)
+        {
+            if (this.isASN1FormatString(format))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+            Class paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == PBEParameterSpec.class)
+            {
+                return new PBEParameterSpec(params.getIV(),
+                    params.getIterations().intValue());
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof PBEParameterSpec))
+            {
+                throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
+            }
+
+            PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec;
+
+            this.params = new PKCS12PBEParams(pbeSpec.getSalt(),
+                pbeSpec.getIterationCount());
+        }
+
+        protected void engineInit(
+            byte[] params)
+            throws IOException
+        {
+            this.params = PKCS12PBEParams.getInstance(ASN1Primitive.fromByteArray(params));
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format)
+            throws IOException
+        {
+            if (this.isASN1FormatString(format))
+            {
+                engineInit(params);
+                return;
+            }
+
+            throw new IOException("Unknown parameters format in PKCS12 PBE parameters object");
+        }
+
+        protected String engineToString()
+        {
+            return "PKCS12 PBE Parameters";
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = PBEPKCS12.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("AlgorithmParameters.PKCS12PBE", PREFIX + "$AlgParams");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBES2AlgorithmParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBES2AlgorithmParameters.java
new file mode 100644
index 0000000..2898aa9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/PBES2AlgorithmParameters.java
@@ -0,0 +1,367 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+// BEGIN android-added
+// Based on org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12
+
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.EncryptionScheme;
+import com.android.internal.org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PBES2Parameters;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PBKDF2Params;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.PBE;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.Enumeration;
+
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PBES2AlgorithmParameters
+{
+    private PBES2AlgorithmParameters()
+    {
+
+    }
+
+    private static abstract class BasePBEWithHmacAlgorithmParameters
+            extends BaseAlgorithmParameters
+    {
+        private final AlgorithmIdentifier kdf;
+        private final String kdfShortName;
+        private final int keySize;
+        private final ASN1ObjectIdentifier cipherAlgorithm;
+        private final String cipherAlgorithmShortName;
+
+        private PBES2Parameters params;
+
+        private BasePBEWithHmacAlgorithmParameters(
+                ASN1ObjectIdentifier kdf,
+                String kdfShortName,
+                int keySize,
+                ASN1ObjectIdentifier cipherAlgorithm,
+                String cipherAlgorithmShortName) {
+            this.kdf = new AlgorithmIdentifier(kdf, DERNull.INSTANCE);
+            this.kdfShortName = kdfShortName;
+            this.keySize = keySize;
+            this.cipherAlgorithm = cipherAlgorithm;
+            this.cipherAlgorithmShortName = cipherAlgorithmShortName;
+        }
+
+        protected byte[] engineGetEncoded()
+        {
+            try
+            {
+                return new DERSequence(new ASN1Encodable[] {
+                        PKCSObjectIdentifiers.id_PBES2,
+                        params
+                }).getEncoded();
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Unable to read PBES2 parameters: " + e.toString());
+            }
+        }
+
+        protected byte[] engineGetEncoded(
+                String format)
+        {
+            if (this.isASN1FormatString(format))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+                Class parameterSpec)
+                throws InvalidParameterSpecException
+        {
+            if (parameterSpec == PBEParameterSpec.class)
+            {
+                PBKDF2Params pbeParamSpec =
+                        (PBKDF2Params) params.getKeyDerivationFunc().getParameters();
+                byte[] iv =  ((ASN1OctetString) params.getEncryptionScheme().getParameters())
+                        .getOctets();
+                return createPBEParameterSpec(pbeParamSpec.getSalt(),
+                        pbeParamSpec.getIterationCount().intValue(),
+                        iv);
+            }
+
+            throw new InvalidParameterSpecException(
+                    "unknown parameter spec passed to PBES2 parameters object.");
+        }
+
+        protected void engineInit(
+                AlgorithmParameterSpec paramSpec)
+                throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof PBEParameterSpec))
+            {
+                throw new InvalidParameterSpecException(
+                        "PBEParameterSpec required to initialise PBES2 algorithm parameters");
+            }
+
+            PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec;
+
+            byte[] iv;
+
+            AlgorithmParameterSpec algorithmParameterSpec =
+                    PBE.Util.getParameterSpecFromPBEParameterSpec(pbeSpec);
+            if (algorithmParameterSpec instanceof IvParameterSpec) {
+                iv = ((IvParameterSpec) algorithmParameterSpec).getIV();
+            } else {
+                throw new IllegalArgumentException("Expecting an IV as a parameter");
+            }
+
+            this.params = new PBES2Parameters(
+                    new KeyDerivationFunc(
+                            PKCSObjectIdentifiers.id_PBKDF2,
+                            new PBKDF2Params(
+                                    pbeSpec.getSalt(), pbeSpec.getIterationCount(), keySize, kdf)),
+                    new EncryptionScheme(cipherAlgorithm, new DEROctetString(iv)));
+        }
+
+        protected void engineInit(
+                byte[] params)
+                throws IOException
+        {
+            // Dual of engineGetEncoded()
+            ASN1Sequence seq = ASN1Sequence.getInstance(ASN1Primitive.fromByteArray(params));
+            Enumeration seqObjects = seq.getObjects();
+            ASN1ObjectIdentifier id = (ASN1ObjectIdentifier) seqObjects.nextElement();
+            if (!id.getId().equals(PKCSObjectIdentifiers.id_PBES2.getId())) {
+                throw new IllegalArgumentException("Invalid PBES2 parameters");
+            }
+            this.params = PBES2Parameters.getInstance(seqObjects.nextElement());
+        }
+
+        protected void engineInit(
+                byte[] params,
+                String format)
+                throws IOException
+        {
+            if (this.isASN1FormatString(format))
+            {
+                engineInit(params);
+                return;
+            }
+
+            throw new IOException("Unknown parameters format in PBES2 parameters object");
+        }
+
+        protected String engineToString()
+        {
+            return "PBES2 " + kdfShortName + " " + cipherAlgorithmShortName + " Parameters";
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA1AES128AlgorithmParameters
+            extends BasePBEWithHmacAlgorithmParameters {
+        public PBEWithHmacSHA1AES128AlgorithmParameters() {
+            super(PKCSObjectIdentifiers.id_hmacWithSHA1,
+                    "HmacSHA1",
+                    16, /* keySize */
+                    NISTObjectIdentifiers.id_aes128_CBC,
+                    "AES128");
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA224AES128AlgorithmParameters
+            extends BasePBEWithHmacAlgorithmParameters {
+        public PBEWithHmacSHA224AES128AlgorithmParameters() {
+            super(PKCSObjectIdentifiers.id_hmacWithSHA224,
+                    "HmacSHA224",
+                    16, /* keySize */
+                    NISTObjectIdentifiers.id_aes128_CBC,
+                    "AES128");
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA256AES128AlgorithmParameters
+            extends BasePBEWithHmacAlgorithmParameters {
+        public PBEWithHmacSHA256AES128AlgorithmParameters() {
+            super(PKCSObjectIdentifiers.id_hmacWithSHA256,
+                    "HmacSHA256",
+                    16, /* keySize */
+                    NISTObjectIdentifiers.id_aes128_CBC,
+                    "AES128");
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA384AES128AlgorithmParameters
+            extends BasePBEWithHmacAlgorithmParameters {
+        public PBEWithHmacSHA384AES128AlgorithmParameters() {
+            super(PKCSObjectIdentifiers.id_hmacWithSHA384,
+                    "HmacSHA384",
+                    16, /* keySize */
+                    NISTObjectIdentifiers.id_aes128_CBC,
+                    "AES128");
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA512AES128AlgorithmParameters
+            extends BasePBEWithHmacAlgorithmParameters {
+        public PBEWithHmacSHA512AES128AlgorithmParameters() {
+            super(PKCSObjectIdentifiers.id_hmacWithSHA512,
+                    "HmacSHA512",
+                    16, /* keySize */
+                    NISTObjectIdentifiers.id_aes128_CBC,
+                    "AES128");
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA1AES256AlgorithmParameters
+            extends BasePBEWithHmacAlgorithmParameters {
+        public PBEWithHmacSHA1AES256AlgorithmParameters() {
+            super(PKCSObjectIdentifiers.id_hmacWithSHA1,
+                    "HmacSHA1",
+                    32, /* keySize */
+                    NISTObjectIdentifiers.id_aes256_CBC,
+                    "AES256");
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA224AES256AlgorithmParameters
+            extends BasePBEWithHmacAlgorithmParameters {
+        public PBEWithHmacSHA224AES256AlgorithmParameters() {
+            super(PKCSObjectIdentifiers.id_hmacWithSHA224,
+                    "HmacSHA224",
+                    32, /* keySize */
+                    NISTObjectIdentifiers.id_aes256_CBC,
+                    "AES256");
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA256AES256AlgorithmParameters
+            extends BasePBEWithHmacAlgorithmParameters {
+        public PBEWithHmacSHA256AES256AlgorithmParameters() {
+            super(PKCSObjectIdentifiers.id_hmacWithSHA256,
+                    "HmacSHA256",
+                    32, /* keySize */
+                    NISTObjectIdentifiers.id_aes256_CBC,
+                    "AES256");
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA384AES256AlgorithmParameters
+            extends BasePBEWithHmacAlgorithmParameters {
+        public PBEWithHmacSHA384AES256AlgorithmParameters() {
+            super(PKCSObjectIdentifiers.id_hmacWithSHA384,
+                    "HmacSHA384",
+                    32, /* keySize */
+                    NISTObjectIdentifiers.id_aes256_CBC,
+                    "AES256");
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class PBEWithHmacSHA512AES256AlgorithmParameters
+            extends BasePBEWithHmacAlgorithmParameters {
+        public PBEWithHmacSHA512AES256AlgorithmParameters() {
+            super(PKCSObjectIdentifiers.id_hmacWithSHA512,
+                    "HmacSHA512",
+                    32, /* keySize */
+                    NISTObjectIdentifiers.id_aes256_CBC,
+                    "AES256");
+        }
+    }
+
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+            extends AlgorithmProvider
+    {
+        private static final String PREFIX = PBES2AlgorithmParameters.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            int[] keySizes = { 128, 256 };
+            int[] shaVariants = { 1, 224, 256, 384, 512 };
+            for (int keySize : keySizes) {
+                for (int shaVariant : shaVariants) {
+                    provider.addAlgorithm(
+                            "AlgorithmParameters.PBEWithHmacSHA" + shaVariant + "AndAES_" + keySize,
+                            PREFIX + "$PBEWithHmacSHA" + shaVariant + "AES" + keySize
+                                    + "AlgorithmParameters");
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper method to create a PBEParameterSpec with a parameter specification via reflection, as
+     * the constructor became available in Java 1.8 and Bouncycastle is at level 1.5.
+     */
+    private static PBEParameterSpec createPBEParameterSpec(
+            byte[] salt, int iterationCount, byte[] iv) {
+        try {
+            Class<PBEParameterSpec> pbeParameterSpecClass =
+                    (Class<PBEParameterSpec>) PBES2AlgorithmParameters.class.getClassLoader()
+                            .loadClass("javax.crypto.spec.PBEParameterSpec");
+            Constructor<PBEParameterSpec> constructor =
+                    pbeParameterSpecClass.getConstructor(new Class[]{
+                            byte[].class, int.class, AlgorithmParameterSpec.class });
+            return constructor.newInstance(salt, iterationCount, new IvParameterSpec(iv));
+        } catch (Exception e) {
+            throw new IllegalStateException(
+                    "Requested creation PBES2 parameters in an SDK that doesn't support them", e);
+        }
+    }
+}
+// END android-added
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/RC2.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/RC2.java
new file mode 100644
index 0000000..5f86d90
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/RC2.java
@@ -0,0 +1,566 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
+// import org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.engines.RC2Engine;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.engines.RC2WrapEngine;
+// import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+import com.android.internal.org.bouncycastle.crypto.modes.CBCBlockCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class RC2
+{
+    private RC2()
+    {
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    /**
+     * RC2
+     *
+    static public class ECB
+        extends BaseBlockCipher
+    {
+        public ECB()
+        {
+            super(new RC2Engine());
+        }
+    }
+
+    /**
+     * RC2CBC
+     *
+    static public class CBC
+        extends BaseBlockCipher
+    {
+        public CBC()
+        {
+            super(new CBCBlockCipher(new RC2Engine()), 64);
+        }
+    }
+
+    public static class Wrap
+        extends BaseWrapCipher
+    {
+        public Wrap()
+        {
+            super(new RC2WrapEngine());
+        }
+    }
+
+    /**
+     * RC2
+     *
+    public static class CBCMAC
+        extends BaseMac
+    {
+        public CBCMAC()
+        {
+            super(new CBCBlockCipherMac(new RC2Engine()));
+        }
+    }
+
+    public static class CFB8MAC
+        extends BaseMac
+    {
+        public CFB8MAC()
+        {
+            super(new CFBBlockCipherMac(new RC2Engine()));
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * PBEWithSHA1AndRC2
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA1KeyFactory
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHA1KeyFactory()
+        {
+            super("PBEwithSHA1andRC2", PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, true, PKCS5S1, SHA1, 64, 64);
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd128BitRC2-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAnd128BitKeyFactory
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHAAnd128BitKeyFactory()
+        {
+            super("PBEwithSHAand128BitRC2-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, true, PKCS12, SHA1, 128, 64);
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd40BitRC2-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAnd40BitKeyFactory
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHAAnd40BitKeyFactory()
+        {
+            super("PBEwithSHAand40BitRC2-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, true, PKCS12, SHA1, 40, 64);
+        }
+    }
+
+    /**
+     * PBEWithMD5AndRC2
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithMD5AndRC2
+        extends BaseBlockCipher
+    {
+        public PBEWithMD5AndRC2()
+        {
+            super(new CBCBlockCipher(new RC2Engine()), PKCS5S1, MD5, 64, 8);
+        }
+    }
+    
+    /**
+     * PBEWithSHA1AndRC2
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA1AndRC2
+        extends BaseBlockCipher
+    {
+        public PBEWithSHA1AndRC2()
+        {
+            super(new CBCBlockCipher(new RC2Engine()), PKCS5S1, SHA1, 64, 8);
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd128BitRC2-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAnd128BitRC2
+        extends BaseBlockCipher
+    {
+        public PBEWithSHAAnd128BitRC2()
+        {
+            super(new CBCBlockCipher(new RC2Engine()), PKCS12, SHA1, 128, 8);
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd40BitRC2-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAAnd40BitRC2
+        extends BaseBlockCipher
+    {
+        public PBEWithSHAAnd40BitRC2()
+        {
+            super(new CBCBlockCipher(new RC2Engine()), PKCS12, SHA1, 40, 8);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    /**
+     * PBEWithMD2AndRC2
+     *
+    static public class PBEWithMD2KeyFactory
+        extends PBESecretKeyFactory
+    {
+        public PBEWithMD2KeyFactory()
+        {
+            super("PBEwithMD2andRC2", PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, true, PKCS5S1, MD2, 64, 64);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+   /**
+    * PBEWithMD5AndRC2
+ * @hide This class is not part of the Android public SDK API
+    */
+   static public class PBEWithMD5KeyFactory
+       extends PBESecretKeyFactory
+   {
+       public PBEWithMD5KeyFactory()
+       {
+           super("PBEwithMD5andRC2", PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, true, PKCS5S1, MD5, 64, 64);
+       }
+   }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class AlgParamGen
+        extends BaseAlgorithmParameterGenerator
+    {
+        RC2ParameterSpec spec = null;
+
+        protected void engineInit(
+            AlgorithmParameterSpec genParamSpec,
+            SecureRandom random)
+            throws InvalidAlgorithmParameterException
+        {
+            if (genParamSpec instanceof RC2ParameterSpec)
+            {
+                spec = (RC2ParameterSpec)genParamSpec;
+                return;
+            }
+
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for RC2 parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            AlgorithmParameters params;
+
+            if (spec == null)
+            {
+                byte[] iv = new byte[8];
+
+                if (random == null)
+                {
+                    random = CryptoServicesRegistrar.getSecureRandom();
+                }
+
+                random.nextBytes(iv);
+
+                try
+                {
+                    params = createParametersInstance("RC2");
+                    params.init(new IvParameterSpec(iv));
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+            else
+            {
+                try
+                {
+                    params = createParametersInstance("RC2");
+                    params.init(spec);
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+
+            return params;
+        }
+    }
+
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("RC2", 128, new CipherKeyGenerator());
+        }
+    }
+
+    public static class AlgParams
+        extends BaseAlgorithmParameters
+    {
+        private static final short[] table = {
+            0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
+            0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
+            0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
+            0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
+            0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
+            0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
+            0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
+            0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
+            0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
+            0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
+            0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
+            0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
+            0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
+            0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
+            0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
+            0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
+        };
+
+        private static final short[] ekb = {
+            0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
+            0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
+            0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
+            0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
+            0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
+            0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
+            0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
+            0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
+            0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
+            0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
+            0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
+            0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
+            0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
+            0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
+            0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
+            0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
+        };
+
+        private byte[] iv;
+        private int parameterVersion = 58;
+
+        protected byte[] engineGetEncoded()
+        {
+            return Arrays.clone(iv);
+        }
+
+        protected byte[] engineGetEncoded(
+            String format)
+            throws IOException
+        {
+            if (this.isASN1FormatString(format))
+            {
+                if (parameterVersion == -1)
+                {
+                    return new RC2CBCParameter(engineGetEncoded()).getEncoded();
+                }
+                else
+                {
+                    return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
+                }
+            }
+
+            if (format.equals("RAW"))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(
+            Class paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == RC2ParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
+            {
+                if (parameterVersion != -1)
+                {
+                    if (parameterVersion < 256)
+                    {
+                        return new RC2ParameterSpec(ekb[parameterVersion], iv);
+                    }
+                    else
+                    {
+                        return new RC2ParameterSpec(parameterVersion, iv);
+                    }
+                }
+            }
+
+            if (paramSpec == IvParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
+            {
+                return new IvParameterSpec(iv);
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec instanceof IvParameterSpec)
+            {
+                this.iv = ((IvParameterSpec)paramSpec).getIV();
+            }
+            else if (paramSpec instanceof RC2ParameterSpec)
+            {
+                int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
+                if (effKeyBits != -1)
+                {
+                    if (effKeyBits < 256)
+                    {
+                        parameterVersion = table[effKeyBits];
+                    }
+                    else
+                    {
+                        parameterVersion = effKeyBits;
+                    }
+                }
+
+                this.iv = ((RC2ParameterSpec)paramSpec).getIV();
+            }
+            else
+            {
+                throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
+            }
+        }
+
+        protected void engineInit(
+            byte[] params)
+            throws IOException
+        {
+            this.iv = Arrays.clone(params);
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format)
+            throws IOException
+        {
+            if (this.isASN1FormatString(format))
+            {
+                RC2CBCParameter p = RC2CBCParameter.getInstance(ASN1Primitive.fromByteArray(params));
+
+                if (p.getRC2ParameterVersion() != null)
+                {
+                    parameterVersion = p.getRC2ParameterVersion().intValue();
+                }
+
+                iv = p.getIV();
+
+                return;
+            }
+
+            if (format.equals("RAW"))
+            {
+                engineInit(params);
+                return;
+            }
+
+            throw new IOException("Unknown parameters format in IV parameters object");
+        }
+
+        protected String engineToString()
+        {
+            return "RC2 Parameters";
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends AlgorithmProvider
+    {
+        private static final String PREFIX = RC2.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            provider.addAlgorithm("AlgorithmParameterGenerator.RC2", PREFIX + "$AlgParamGen");
+            provider.addAlgorithm("AlgorithmParameterGenerator.1.2.840.113549.3.2", PREFIX + "$AlgParamGen");
+
+            provider.addAlgorithm("KeyGenerator.RC2", PREFIX + "$KeyGenerator");
+            provider.addAlgorithm("KeyGenerator.1.2.840.113549.3.2", PREFIX + "$KeyGenerator");
+
+            provider.addAlgorithm("AlgorithmParameters.RC2", PREFIX + "$AlgParams");
+            provider.addAlgorithm("AlgorithmParameters.1.2.840.113549.3.2", PREFIX + "$AlgParams");
+
+            provider.addAlgorithm("Cipher.RC2", PREFIX + "$ECB");
+            provider.addAlgorithm("Cipher.RC2WRAP", PREFIX + "$Wrap");
+            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.id_alg_CMSRC2wrap, "RC2WRAP");
+            provider.addAlgorithm("Cipher", PKCSObjectIdentifiers.RC2_CBC, PREFIX + "$CBC");
+
+            provider.addAlgorithm("Mac.RC2MAC", PREFIX + "$CBCMAC");
+            provider.addAlgorithm("Alg.Alias.Mac.RC2", "RC2MAC");
+            provider.addAlgorithm("Mac.RC2MAC/CFB8", PREFIX + "$CFB8MAC");
+            provider.addAlgorithm("Alg.Alias.Mac.RC2/CFB8", "RC2MAC/CFB8");
+
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHMD2ANDRC2-CBC", "PBEWITHMD2ANDRC2");
+            */
+            // END Android-removed: Unsupported algorithms
+
+            // Android-note: All of the non-disabled algorithms in this class are necessary
+            // for KeyStore.PKCS12
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHMD5ANDRC2-CBC", "PBEWITHMD5ANDRC2");
+
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1ANDRC2-CBC", "PBEWITHSHA1ANDRC2");
+
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("Alg.Alias.SecretKeyFactory", PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
+
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
+
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.5", "PBEWITHSHAAND128BITRC2-CBC");
+            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.6", "PBEWITHSHAAND40BITRC2-CBC");
+
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("SecretKeyFactory.PBEWITHMD2ANDRC2", PREFIX + "$PBEWithMD2KeyFactory");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5ANDRC2", PREFIX + "$PBEWithMD5KeyFactory");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHA1ANDRC2", PREFIX + "$PBEWithSHA1KeyFactory");
+
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND128BITRC2-CBC", PREFIX + "$PBEWithSHAAnd128BitKeyFactory");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND40BITRC2-CBC", PREFIX + "$PBEWithSHAAnd40BitKeyFactory");
+
+            // Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
+
+            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
+
+            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
+
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.5", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.6", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWithSHAAnd3KeyTripleDES", "PKCS12PBE");
+
+            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, "PBEWITHSHAAND128BITRC2-CBC");
+            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, "PBEWITHSHAAND40BITRC2-CBC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC2-CBC", "PBEWITHSHAAND128BITRC2-CBC");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC");
+            provider.addAlgorithm("Cipher.PBEWITHSHA1ANDRC2", PREFIX + "$PBEWithSHA1AndRC2");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAANDRC2-CBC", "PBEWITHSHA1ANDRC2");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1ANDRC2-CBC", "PBEWITHSHA1ANDRC2");
+
+            provider.addAlgorithm("Cipher.PBEWITHSHAAND128BITRC2-CBC", PREFIX + "$PBEWithSHAAnd128BitRC2");
+            provider.addAlgorithm("Cipher.PBEWITHSHAAND40BITRC2-CBC", PREFIX + "$PBEWithSHAAnd40BitRC2");
+            provider.addAlgorithm("Cipher.PBEWITHMD5ANDRC2", PREFIX + "$PBEWithMD5AndRC2");
+            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHMD5ANDRC2-CBC", "PBEWITHMD5ANDRC2");
+
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA1ANDRC2", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDRC2", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA1ANDRC2-CBC", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC2-CBC", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC2-CBC", "PKCS12PBE");
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
new file mode 100644
index 0000000..02c2d16
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
@@ -0,0 +1,52 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+abstract class SymmetricAlgorithmProvider
+    extends AlgorithmProvider
+{
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    protected void addCMacAlgorithm(
+        ConfigurableProvider provider,
+        String algorithm,
+        String algorithmClassName,
+        String keyGeneratorClassName)
+    {
+        provider.addAlgorithm("Mac." + algorithm + "-CMAC", algorithmClassName);
+        provider.addAlgorithm("Alg.Alias.Mac." + algorithm + "CMAC", algorithm + "-CMAC");
+
+        provider.addAlgorithm("KeyGenerator." + algorithm + "-CMAC", keyGeneratorClassName);
+        provider.addAlgorithm("Alg.Alias.KeyGenerator." + algorithm + "CMAC",  algorithm + "-CMAC");
+    }
+
+    protected void addGMacAlgorithm(
+        ConfigurableProvider provider,
+        String algorithm,
+        String algorithmClassName,
+        String keyGeneratorClassName)
+    {
+        provider.addAlgorithm("Mac." + algorithm + "-GMAC", algorithmClassName);
+        provider.addAlgorithm("Alg.Alias.Mac." + algorithm + "GMAC", algorithm + "-GMAC");
+
+        provider.addAlgorithm("KeyGenerator." + algorithm + "-GMAC", keyGeneratorClassName);
+        provider.addAlgorithm("Alg.Alias.KeyGenerator." + algorithm + "GMAC",  algorithm + "-GMAC");
+    }
+
+    protected void addPoly1305Algorithm(ConfigurableProvider provider,
+                                        String algorithm,
+                                        String algorithmClassName,
+                                        String keyGeneratorClassName)
+    {
+        provider.addAlgorithm("Mac.POLY1305-" + algorithm, algorithmClassName);
+        provider.addAlgorithm("Alg.Alias.Mac.POLY1305" + algorithm, "POLY1305-" + algorithm);
+
+        provider.addAlgorithm("KeyGenerator.POLY1305-" + algorithm, keyGeneratorClassName);
+        provider.addAlgorithm("Alg.Alias.KeyGenerator.POLY1305" + algorithm, "POLY1305-" + algorithm);
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/Twofish.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
new file mode 100644
index 0000000..8681eeb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
@@ -0,0 +1,158 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric;
+
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.BlockCipher;
+// import org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.engines.TwofishEngine;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
+// import org.bouncycastle.crypto.macs.GMac;
+import com.android.internal.org.bouncycastle.crypto.modes.CBCBlockCipher;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.modes.GCMBlockCipher;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+// import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+// import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class Twofish
+{
+    private Twofish()
+    {
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class ECB
+        extends BaseBlockCipher
+    {
+        public ECB()
+        {
+            super(new BlockCipherProvider()
+            {
+                public BlockCipher get()
+                {
+                    return new TwofishEngine();
+                }
+            });
+        }
+    }
+
+    public static class KeyGen
+        extends BaseKeyGenerator
+    {
+        public KeyGen()
+        {
+            super("Twofish", 256, new CipherKeyGenerator());
+        }
+    }
+
+    public static class GMAC
+        extends BaseMac
+    {
+        public GMAC()
+        {
+            super(new GMac(new GCMBlockCipher(new TwofishEngine())));
+        }
+    }
+
+    public static class Poly1305
+        extends BaseMac
+    {
+        public Poly1305()
+        {
+            super(new org.bouncycastle.crypto.macs.Poly1305(new TwofishEngine()));
+        }
+    }
+
+    public static class Poly1305KeyGen
+        extends BaseKeyGenerator
+    {
+        public Poly1305KeyGen()
+        {
+            super("Poly1305-Twofish", 256, new Poly1305KeyGenerator());
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * PBEWithSHAAndTwofish-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHAKeyFactory
+        extends PBESecretKeyFactory
+    {
+        public PBEWithSHAKeyFactory()
+        {
+            super("PBEwithSHAandTwofish-CBC", null, true, PKCS12, SHA1, 256, 128);
+        }
+    }
+
+    /**
+     * PBEWithSHAAndTwofish-CBC
+     * @hide This class is not part of the Android public SDK API
+     */
+    static public class PBEWithSHA
+        extends BaseBlockCipher
+    {
+        public PBEWithSHA()
+        {
+            super(new CBCBlockCipher(new TwofishEngine()), PKCS12, SHA1, 256, 16);
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    public static class AlgParams
+        extends IvAlgorithmParameters
+    {
+        protected String engineToString()
+        {
+            return "Twofish IV";
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Mappings
+        extends SymmetricAlgorithmProvider
+    {
+        private static final String PREFIX = Twofish.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            // provider.addAlgorithm("Cipher.Twofish", PREFIX + "$ECB");
+            // provider.addAlgorithm("KeyGenerator.Twofish", PREFIX + "$KeyGen");
+            // provider.addAlgorithm("AlgorithmParameters.Twofish", PREFIX + "$AlgParams");
+            // END Android-removed: Unsupported algorithms
+
+            // Android-note: These algorithms are necessary for KeyStore.BouncyCastle
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH", "PKCS12PBE");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH-CBC", "PKCS12PBE");
+            provider.addAlgorithm("Cipher.PBEWITHSHAANDTWOFISH-CBC",  PREFIX + "$PBEWithSHA");
+            provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAANDTWOFISH-CBC", PREFIX + "$PBEWithSHAKeyFactory");
+
+            // BEGIN Android-removed: Unsupported algorithms
+            // addGMacAlgorithm(provider, "Twofish", PREFIX + "$GMAC", PREFIX + "$KeyGen");
+            // addPoly1305Algorithm(provider, "Twofish", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
+            // END Android-removed: Unsupported algorithms
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java
new file mode 100644
index 0000000..dbeab4b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java
@@ -0,0 +1,168 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.spec.KeySpec;
+
+import javax.crypto.interfaces.PBEKey;
+import javax.crypto.spec.PBEKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.PBEParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCPBEKey
+    implements PBEKey
+{
+    String              algorithm;
+    ASN1ObjectIdentifier oid;
+    int                 type;
+    int                 digest;
+    int                 keySize;
+    int                 ivSize;
+    CipherParameters    param;
+    PBEKeySpec          pbeKeySpec;
+    boolean             tryWrong = false;
+
+    /**
+     * @param param
+     */
+    public BCPBEKey(
+        String algorithm,
+        ASN1ObjectIdentifier oid,
+        int type,
+        int digest,
+        int keySize,
+        int ivSize,
+        PBEKeySpec pbeKeySpec,
+        CipherParameters param)
+    {
+        this.algorithm = algorithm;
+        this.oid = oid;
+        this.type = type;
+        this.digest = digest;
+        this.keySize = keySize;
+        this.ivSize = ivSize;
+        this.pbeKeySpec = pbeKeySpec;
+        this.param = param;
+    }
+
+    public BCPBEKey(String algName,
+                    KeySpec pbeSpec, CipherParameters param)
+    {
+        this.algorithm = algName;
+        this.param = param;
+    }
+
+    public String getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    public String getFormat()
+    {
+        return "RAW";
+    }
+
+    public byte[] getEncoded()
+    {
+        if (param != null)
+        {
+            KeyParameter    kParam;
+            
+            if (param instanceof ParametersWithIV)
+            {
+                kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+            }
+            else
+            {
+                kParam = (KeyParameter)param;
+            }
+            
+            return kParam.getKey();
+        }
+        else
+        {
+            if (type == PBE.PKCS12)
+            {
+                return PBEParametersGenerator.PKCS12PasswordToBytes(pbeKeySpec.getPassword());
+            }
+            else if (type == PBE.PKCS5S2_UTF8)
+            {
+                return PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(pbeKeySpec.getPassword());
+            }
+            else
+            {   
+                return PBEParametersGenerator.PKCS5PasswordToBytes(pbeKeySpec.getPassword());
+            }
+        }
+    }
+    
+    int getType()
+    {
+        return type;
+    }
+    
+    int getDigest()
+    {
+        return digest;
+    }
+    
+    int getKeySize()
+    {
+        return keySize;
+    }
+    
+    public int getIvSize()
+    {
+        return ivSize;
+    }
+    
+    public CipherParameters getParam()
+    {
+        return param;
+    }
+
+    /* (non-Javadoc)
+     * @see javax.crypto.interfaces.PBEKey#getPassword()
+     */
+    public char[] getPassword()
+    {
+        return pbeKeySpec.getPassword();
+    }
+
+    /* (non-Javadoc)
+     * @see javax.crypto.interfaces.PBEKey#getSalt()
+     */
+    public byte[] getSalt()
+    {
+        return pbeKeySpec.getSalt();
+    }
+
+    /* (non-Javadoc)
+     * @see javax.crypto.interfaces.PBEKey#getIterationCount()
+     */
+    public int getIterationCount()
+    {
+        return pbeKeySpec.getIterationCount();
+    }
+    
+    public ASN1ObjectIdentifier getOID()
+    {
+        return oid;
+    }
+    
+    public void setTryWrongPKCS12Zero(boolean tryWrong)
+    {
+        this.tryWrong = tryWrong; 
+    }
+    
+    boolean shouldTryWrongPKCS12()
+    {
+        return tryWrong;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java
new file mode 100644
index 0000000..aecf672
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java
@@ -0,0 +1,45 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParameterGeneratorSpi;
+import java.security.AlgorithmParameters;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+
+// Android-changed: Use default provider for JCA algorithms instead of BC
+// Was: import org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class BaseAlgorithmParameterGenerator
+    extends AlgorithmParameterGeneratorSpi
+{
+    // Android-changed: Use default provider for JCA algorithms instead of BC
+    // Was: private final JcaJceHelper helper = new BCJcaJceHelper();
+    private final JcaJceHelper helper = new DefaultJcaJceHelper();
+
+    protected SecureRandom  random;
+    protected int           strength = 1024;
+
+    public BaseAlgorithmParameterGenerator()
+    {
+    }
+
+    protected final AlgorithmParameters createParametersInstance(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return helper.createAlgorithmParameters(algorithm);
+    }
+
+    protected void engineInit(
+        int             strength,
+        SecureRandom    random)
+    {
+        this.strength = strength;
+        this.random = random;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java
new file mode 100644
index 0000000..aac6631
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java
@@ -0,0 +1,33 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class BaseAlgorithmParameters
+    extends AlgorithmParametersSpi
+{
+    protected boolean isASN1FormatString(String format)
+    {
+        return format == null || format.equals("ASN.1");
+    }
+
+    protected AlgorithmParameterSpec engineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == null)
+        {
+            throw new NullPointerException("argument to getParameterSpec must not be null");
+        }
+
+        return localEngineGetParameterSpec(paramSpec);
+    }
+
+    protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+        throws InvalidParameterSpecException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
new file mode 100644
index 0000000..51cca62
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
@@ -0,0 +1,1500 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.interfaces.PBEKey;
+import javax.crypto.spec.IvParameterSpec;
+// BEGIN Android-added: Various key-handling modifications
+import javax.crypto.spec.PBEKeySpec;
+// END Android-added: Various key-handling modifications
+import javax.crypto.spec.PBEParameterSpec;
+// Android-removed: Unsupported algorithms
+// import javax.crypto.spec.RC2ParameterSpec;
+// import javax.crypto.spec.RC5ParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.cms.GCMParameters;
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+import com.android.internal.org.bouncycastle.crypto.BufferedBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.OutputLengthException;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.engines.DSTU7624Engine;
+import com.android.internal.org.bouncycastle.crypto.modes.AEADBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.modes.CBCBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.modes.CCMBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.modes.CFBBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.modes.CTSBlockCipher;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.modes.EAXBlockCipher;
+// import org.bouncycastle.crypto.modes.GCFBBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.modes.GCMBlockCipher;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.modes.GOFBBlockCipher;
+// import org.bouncycastle.crypto.modes.KCCMBlockCipher;
+// import org.bouncycastle.crypto.modes.KCTRBlockCipher;
+// import org.bouncycastle.crypto.modes.KGCMBlockCipher;
+// import org.bouncycastle.crypto.modes.OCBBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.modes.OFBBlockCipher;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
+// import org.bouncycastle.crypto.modes.PGPCFBBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.modes.SICBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.paddings.BlockCipherPadding;
+import com.android.internal.org.bouncycastle.crypto.paddings.ISO10126d2Padding;
+import com.android.internal.org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import com.android.internal.org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import com.android.internal.org.bouncycastle.crypto.paddings.TBCPadding;
+import com.android.internal.org.bouncycastle.crypto.paddings.X923Padding;
+import com.android.internal.org.bouncycastle.crypto.paddings.ZeroBytePadding;
+import com.android.internal.org.bouncycastle.crypto.params.AEADParameters;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.params.ParametersWithSBox;
+import com.android.internal.org.bouncycastle.crypto.params.RC2Parameters;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.params.RC5Parameters;
+// import org.bouncycastle.jcajce.PBKDF1Key;
+// import org.bouncycastle.jcajce.PBKDF1KeyWithParameters;
+import com.android.internal.org.bouncycastle.jcajce.PKCS12Key;
+import com.android.internal.org.bouncycastle.jcajce.PKCS12KeyWithParameters;
+import com.android.internal.org.bouncycastle.jcajce.spec.AEADParameterSpec;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
+// import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BaseBlockCipher
+    extends BaseWrapCipher
+    implements PBE
+{
+    private static final Class gcmSpecClass = ClassUtil.loadClass(BaseBlockCipher.class, "javax.crypto.spec.GCMParameterSpec");
+
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        // Android-removed: Unsupported algorithms
+                                        // RC2ParameterSpec.class,
+                                        // RC5ParameterSpec.class,
+                                        gcmSpecClass,
+                                        // Android-removed: Unsupported algorithms
+                                        // GOST28147ParameterSpec.class
+                                        IvParameterSpec.class,
+                                        PBEParameterSpec.class
+                                    };
+
+    private BlockCipher             baseEngine;
+    private BlockCipherProvider     engineProvider;
+    private GenericBlockCipher      cipher;
+    private ParametersWithIV        ivParam;
+    private AEADParameters          aeadParams;
+
+    private int keySizeInBits;
+    private int scheme = -1;
+    private int digest;
+
+    private int                     ivLength = 0;
+
+    private boolean                 padded;
+    private boolean                 fixedIv = true;
+    private PBEParameterSpec        pbeSpec = null;
+    private String                  pbeAlgorithm = null;
+
+    private String                  modeName = null;
+
+    protected BaseBlockCipher(
+        BlockCipher engine)
+    {
+        baseEngine = engine;
+
+        cipher = new BufferedGenericBlockCipher(engine);
+    }
+
+    protected BaseBlockCipher(
+        BlockCipher engine,
+        int scheme,
+        int digest,
+        int keySizeInBits,
+        int ivLength)
+    {
+        baseEngine = engine;
+
+        this.scheme = scheme;
+        this.digest = digest;
+        this.keySizeInBits = keySizeInBits;
+        this.ivLength = ivLength;
+
+        cipher = new BufferedGenericBlockCipher(engine);
+    }
+
+    protected BaseBlockCipher(
+        BlockCipherProvider provider)
+    {
+        baseEngine = provider.get();
+        engineProvider = provider;
+
+        cipher = new BufferedGenericBlockCipher(provider.get());
+    }
+
+    protected BaseBlockCipher(
+        AEADBlockCipher engine)
+    {
+        this.baseEngine = engine.getUnderlyingCipher();
+        this.ivLength = baseEngine.getBlockSize();
+        this.cipher = new AEADGenericBlockCipher(engine);
+    }
+
+    protected BaseBlockCipher(
+        AEADBlockCipher engine,
+        boolean fixedIv,
+        int ivLength)
+    {
+        this.baseEngine = engine.getUnderlyingCipher();
+        this.fixedIv = fixedIv;
+        this.ivLength = ivLength;
+        this.cipher = new AEADGenericBlockCipher(engine);
+    }
+
+    protected BaseBlockCipher(
+        com.android.internal.org.bouncycastle.crypto.BlockCipher engine,
+        int ivLength)
+    {
+        this(engine, true, ivLength);
+    }
+
+    protected BaseBlockCipher(
+        com.android.internal.org.bouncycastle.crypto.BlockCipher engine,
+        boolean fixedIv,
+        int ivLength)
+    {
+        baseEngine = engine;
+
+        this.fixedIv = fixedIv;
+        this.cipher = new BufferedGenericBlockCipher(engine);
+        this.ivLength = ivLength / 8;
+    }
+
+    protected BaseBlockCipher(
+        BufferedBlockCipher engine,
+        int ivLength)
+    {
+        this(engine, true, ivLength);
+    }
+
+    protected BaseBlockCipher(
+        BufferedBlockCipher engine,
+        boolean fixedIv,
+        int ivLength)
+    {
+        baseEngine = engine.getUnderlyingCipher();
+
+        this.cipher = new BufferedGenericBlockCipher(engine);
+        this.fixedIv = fixedIv;
+        this.ivLength = ivLength / 8;
+    }
+
+    protected int engineGetBlockSize()
+    {
+        return baseEngine.getBlockSize();
+    }
+
+    protected byte[] engineGetIV()
+    {
+        if (aeadParams != null)
+        {
+            return aeadParams.getNonce();
+        }
+
+        return (ivParam != null) ? ivParam.getIV() : null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key)
+    {
+        return key.getEncoded().length * 8;
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen)
+    {
+        return cipher.getOutputSize(inputLen);
+    }
+
+    protected AlgorithmParameters engineGetParameters()
+    {
+        if (engineParams == null)
+        {
+            if (pbeSpec != null)
+            {
+                try
+                {
+                    engineParams = createParametersInstance(pbeAlgorithm);
+                    engineParams.init(pbeSpec);
+                }
+                catch (Exception e)
+                {
+                    return null;
+                }
+            }
+            else if (aeadParams != null)
+            {
+                try
+                {
+                    engineParams = createParametersInstance("GCM");
+                    engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize() / 8).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
+            else if (ivParam != null)
+            {
+                String  name = cipher.getUnderlyingCipher().getAlgorithmName();
+
+                if (name.indexOf('/') >= 0)
+                {
+                    name = name.substring(0, name.indexOf('/'));
+                }
+
+                try
+                {
+                    engineParams = createParametersInstance(name);
+                    engineParams.init(new IvParameterSpec(ivParam.getIV()));
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
+        }
+
+        return engineParams;
+    }
+
+    protected void engineSetMode(
+        String  mode)
+        throws NoSuchAlgorithmException
+    {
+        modeName = Strings.toUpperCase(mode);
+
+        if (modeName.equals("ECB"))
+        {
+            ivLength = 0;
+            cipher = new BufferedGenericBlockCipher(baseEngine);
+        }
+        else if (modeName.equals("CBC"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new BufferedGenericBlockCipher(
+                            new CBCBlockCipher(baseEngine));
+        }
+        else if (modeName.startsWith("OFB"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            if (modeName.length() != 3)
+            {
+                int wordSize = Integer.parseInt(modeName.substring(3));
+
+                cipher = new BufferedGenericBlockCipher(
+                                new OFBBlockCipher(baseEngine, wordSize));
+            }
+            else
+            {
+                cipher = new BufferedGenericBlockCipher(
+                        new OFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+            }
+        }
+        else if (modeName.startsWith("CFB"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            if (modeName.length() != 3)
+            {
+                int wordSize = Integer.parseInt(modeName.substring(3));
+
+                cipher = new BufferedGenericBlockCipher(
+                                new CFBBlockCipher(baseEngine, wordSize));
+            }
+            else
+            {
+                cipher = new BufferedGenericBlockCipher(
+                        new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+            }
+        }
+        // BEGIN Android-removed: Unsupported modes
+        /*
+        else if (modeName.startsWith("PGP"))
+        {
+            boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
+
+            ivLength = baseEngine.getBlockSize();
+            cipher = new BufferedGenericBlockCipher(
+                new PGPCFBBlockCipher(baseEngine, inlineIV));
+        }
+        else if (modeName.equalsIgnoreCase("OpenPGPCFB"))
+        {
+            ivLength = 0;
+            cipher = new BufferedGenericBlockCipher(
+                new OpenPGPCFBBlockCipher(baseEngine));
+        }
+        else if (modeName.startsWith("SIC"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            if (ivLength < 16)
+            {
+                throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
+            }
+            fixedIv = false;
+            cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+                        new SICBlockCipher(baseEngine)));
+        }
+        */
+        // END Android-removed: Unsupported modes
+        else if (modeName.startsWith("CTR"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            fixedIv = false;
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            if (baseEngine instanceof DSTU7624Engine)
+            {
+                cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+                                    new KCTRBlockCipher(baseEngine)));
+            }
+            else
+            {
+            */
+                cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+                    new SICBlockCipher(baseEngine)));
+            /*
+            }
+            */
+        }
+        // BEGIN Android-removed: Unsupported modes
+        /*
+        else if (modeName.startsWith("GOFB"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+                        new GOFBBlockCipher(baseEngine)));
+        }
+        else if (modeName.startsWith("GCFB"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+                        new GCFBBlockCipher(baseEngine)));
+        }
+        */
+        // END Android-removed: Unsupported modes
+        else if (modeName.startsWith("CTS"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(new CBCBlockCipher(baseEngine)));
+        }
+        else if (modeName.startsWith("CCM"))
+        {
+            ivLength = 12; // CCM nonce 7..13 bytes
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            if (baseEngine instanceof DSTU7624Engine)
+            {
+                cipher = new AEADGenericBlockCipher(new KCCMBlockCipher(baseEngine));
+            }
+            else
+            {
+            */
+                cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
+            /*
+            }
+            */
+        }
+        // BEGIN Android-removed: Unsupported modes
+        /*
+        else if (modeName.startsWith("OCB"))
+        {
+            if (engineProvider != null)
+            {
+                /*
+                 * RFC 7253 4.2. Nonce is a string of no more than 120 bits
+                 *
+                ivLength = 15;
+                cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get()));
+            }
+            else
+            {
+                throw new NoSuchAlgorithmException("can't support mode " + mode);
+            }
+        }
+        else if (modeName.startsWith("EAX"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
+        }
+        */
+        // END Android-removed: Unsupported modes
+        // Android-changed: Use equals instead of startsWith to not catch GCM-SIV
+        else if (modeName.equalsIgnoreCase("GCM"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            if (baseEngine instanceof DSTU7624Engine)
+            {
+                cipher = new AEADGenericBlockCipher(new KGCMBlockCipher(baseEngine));
+            }
+            else
+            {
+            */
+                cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine));
+            /*
+            }
+            */
+        }
+        else
+        {
+            throw new NoSuchAlgorithmException("can't support mode " + mode);
+        }
+    }
+
+    protected void engineSetPadding(
+        String  padding)
+    throws NoSuchPaddingException
+    {
+        String  paddingName = Strings.toUpperCase(padding);
+
+        if (paddingName.equals("NOPADDING"))
+        {
+            if (cipher.wrapOnNoPadding())
+            {
+                cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(cipher.getUnderlyingCipher()));
+            }
+        }
+        else if (paddingName.equals("WITHCTS") || paddingName.equals("CTSPADDING") || paddingName.equals("CS3PADDING"))
+        {
+            cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(cipher.getUnderlyingCipher()));
+        }
+        else
+        {
+            padded = true;
+
+            if (isAEADModeName(modeName))
+            {
+                throw new NoSuchPaddingException("Only NoPadding can be used with AEAD modes.");
+            }
+            else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher());
+            }
+            else if (paddingName.equals("ZEROBYTEPADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ZeroBytePadding());
+            }
+            else if (paddingName.equals("ISO10126PADDING") || paddingName.equals("ISO10126-2PADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO10126d2Padding());
+            }
+            else if (paddingName.equals("X9.23PADDING") || paddingName.equals("X923PADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new X923Padding());
+            }
+            else if (paddingName.equals("ISO7816-4PADDING") || paddingName.equals("ISO9797-1PADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO7816d4Padding());
+            }
+            else if (paddingName.equals("TBCPADDING"))
+            {
+                cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new TBCPadding());
+            }
+            else
+            {
+                throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+            }
+        }
+    }
+
+    // BEGIN Android-added: Handling missing IVs
+    private boolean isBCPBEKeyWithoutIV(Key key) {
+        return (key instanceof BCPBEKey) && !(((BCPBEKey)key).getParam() instanceof ParametersWithIV);
+    }
+    // END Android-added: Handling missing IVs
+
+    protected void engineInit(
+        int                     opmode,
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        this.pbeSpec = null;
+        this.pbeAlgorithm = null;
+        this.engineParams = null;
+        this.aeadParams = null;
+
+        //
+        // basic key check
+        //
+        if (!(key instanceof SecretKey))
+        {
+            throw new InvalidKeyException("Key for algorithm " + ((key != null) ? key.getAlgorithm() : null) + " not suitable for symmetric enryption.");
+        }
+
+        //
+        // for RC5-64 we must have some default parameters
+        //
+        if (params == null && baseEngine.getAlgorithmName().startsWith("RC5-64"))
+        {
+            throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in.");
+        }
+
+        //
+        // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
+        //
+        // BEGIN Android-changed: Don't use PKCS12 with missing IV.
+        // If the key is a BCPBE one without an IV, ignore the fact that the scheme is PKCS12.
+        // if (scheme == PKCS12 || key instanceof PKCS12Key)
+        if ((scheme == PKCS12 || key instanceof PKCS12Key) && !isBCPBEKeyWithoutIV(key))
+        // END Android-changed: Don't use PKCS12 with missing IV.
+        {
+            SecretKey k;
+            try
+            {
+                k = (SecretKey)key;
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeyException("PKCS12 requires a SecretKey/PBEKey");
+            }
+
+            if (params instanceof  PBEParameterSpec)
+            {
+                pbeSpec = (PBEParameterSpec)params;
+            }
+
+            if (k instanceof PBEKey && pbeSpec == null)
+            {
+                PBEKey pbeKey = (PBEKey)k;
+                if (pbeKey.getSalt() == null)
+                {
+                    throw new InvalidAlgorithmParameterException("PBEKey requires parameters to specify salt");
+                }
+                pbeSpec = new PBEParameterSpec(pbeKey.getSalt(), pbeKey.getIterationCount());
+            }
+
+            if (pbeSpec == null && !(k instanceof PBEKey))
+            {
+                throw new InvalidKeyException("Algorithm requires a PBE key");
+            }
+
+            if (key instanceof BCPBEKey)
+            {
+                // PKCS#12 sets an IV, if we get a key that doesn't have ParametersWithIV we need to reject it. If the
+                // key has no parameters it means it's an old-school JCE PBE Key - we use getEncoded() on it.
+                CipherParameters pbeKeyParam = ((BCPBEKey)key).getParam();
+                if (pbeKeyParam instanceof ParametersWithIV)
+                {
+                    param = pbeKeyParam;
+                }
+                else if (pbeKeyParam == null)
+                {
+                    // BEGIN Android-changed: Unreachable code
+                    // See above for the Android change that makes this code unreachable.
+                    // param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS12, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
+                    throw new AssertionError("Unreachable code");
+                    // END Android-changed: Unreachable code
+                }
+                else
+                {
+                    throw new InvalidKeyException("Algorithm requires a PBE key suitable for PKCS12");
+                }
+            }
+            else
+            {
+                param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS12, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
+            }
+            if (param instanceof ParametersWithIV)
+            {
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (key instanceof PBKDF1Key)
+        {
+            PBKDF1Key k = (PBKDF1Key)key;
+
+            if (params instanceof PBEParameterSpec)
+            {
+                pbeSpec = (PBEParameterSpec)params;
+            }
+            if (k instanceof PBKDF1KeyWithParameters && pbeSpec == null)
+            {
+                pbeSpec = new PBEParameterSpec(((PBKDF1KeyWithParameters)k).getSalt(), ((PBKDF1KeyWithParameters)k).getIterationCount());
+            }
+
+            param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS5S1, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
+            if (param instanceof ParametersWithIV)
+            {
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+        else if (key instanceof BCPBEKey)
+        {
+            BCPBEKey k = (BCPBEKey)key;
+
+            if (k.getOID() != null)
+            {
+                pbeAlgorithm = k.getOID().getId();
+            }
+            else
+            {
+                pbeAlgorithm = k.getAlgorithm();
+            }
+
+            if (k.getParam() != null)
+            {
+                param = adjustParameters(params, k.getParam());
+            }
+            else if (params instanceof PBEParameterSpec)
+            {
+                pbeSpec = (PBEParameterSpec)params;
+                // BEGIN Android-added: Allow PBE keys with only passwords.
+                // At this point, k.getParam() == null, so the key hasn't been generated.  If
+                // the parameters have non-default values, recreate the BCPBEKey from algorithm
+                // parameters as to generate the key.
+                if ((pbeSpec.getSalt().length != 0) && (pbeSpec.getIterationCount() > 0)) {
+                    k = new BCPBEKey(k.getAlgorithm(), k.getOID(), k.getType(), k.getDigest(),
+                            k.getKeySize(), k.getIvSize(),
+                            new PBEKeySpec(
+                                    k.getPassword(), pbeSpec.getSalt(), pbeSpec.getIterationCount(),
+                                    k.getKeySize()),
+                            null /* CipherParameters */);
+                }
+                // END Android-added: Allow PBE keys with only passwords.
+                param = PBE.Util.makePBEParameters(k, params, cipher.getUnderlyingCipher().getAlgorithmName());
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+            }
+
+            if (param instanceof ParametersWithIV)
+            {
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else if (key instanceof PBEKey)
+        {
+            PBEKey k = (PBEKey)key;
+            pbeSpec = (PBEParameterSpec)params;
+            if (k instanceof PKCS12KeyWithParameters && pbeSpec == null)
+            {
+                pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
+            }
+
+            param = PBE.Util.makePBEParameters(k.getEncoded(), scheme, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
+            if (param instanceof ParametersWithIV)
+            {
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        // BEGIN Android-changed: Unsupported algorithm
+        // else if (!(key instanceof RepeatedSecretKeySpec))
+        else
+        // END Android-changed: Unsupported algorithms
+        {
+            if (scheme == PKCS5S1 || scheme == PKCS5S1_UTF8 || scheme == PKCS5S2 || scheme == PKCS5S2_UTF8)
+            {
+                throw new InvalidKeyException("Algorithm requires a PBE key");
+            }
+            param = new KeyParameter(key.getEncoded());
+        }
+        // BEGIN Android-removed: Unreachable
+        // else
+        // {
+        //    param = null;
+        // }
+        // END Android-removed: Unreachable
+
+        if (params instanceof AEADParameterSpec)
+        {
+            if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher))
+            {
+                throw new InvalidAlgorithmParameterException("AEADParameterSpec can only be used with AEAD modes.");
+            }
+
+            AEADParameterSpec aeadSpec = (AEADParameterSpec)params;
+
+            KeyParameter keyParam;
+            if (param instanceof ParametersWithIV)
+            {
+                keyParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+            }
+            else
+            {
+                keyParam = (KeyParameter)param;
+            }
+            param = aeadParams = new AEADParameters(keyParam, aeadSpec.getMacSizeInBits(), aeadSpec.getNonce(), aeadSpec.getAssociatedData());
+        }
+        else if (params instanceof IvParameterSpec)
+        {
+            if (ivLength != 0)
+            {
+                IvParameterSpec p = (IvParameterSpec)params;
+
+                if (p.getIV().length != ivLength && !(cipher instanceof AEADGenericBlockCipher) && fixedIv)
+                {
+                    throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
+                }
+
+                if (param instanceof ParametersWithIV)
+                {
+                    param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), p.getIV());
+                }
+                else
+                {
+                    param = new ParametersWithIV(param, p.getIV());
+                }
+                ivParam = (ParametersWithIV)param;
+            }
+            else
+            {
+                if (modeName != null && modeName.equals("ECB"))
+                {
+                    throw new InvalidAlgorithmParameterException("ECB mode does not use an IV");
+                }
+            }
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (params instanceof GOST28147ParameterSpec)
+        {
+            GOST28147ParameterSpec    gost28147Param = (GOST28147ParameterSpec)params;
+
+            param = new ParametersWithSBox(
+                       new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox());
+
+            if (gost28147Param.getIV() != null && ivLength != 0)
+            {
+                if (param instanceof ParametersWithIV)
+                {
+                    param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), gost28147Param.getIV());
+                }
+                else
+                {
+                    param = new ParametersWithIV(param, gost28147Param.getIV());
+                }
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else if (params instanceof RC2ParameterSpec)
+        {
+            RC2ParameterSpec    rc2Param = (RC2ParameterSpec)params;
+
+            param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
+
+            if (rc2Param.getIV() != null && ivLength != 0)
+            {
+                if (param instanceof ParametersWithIV)
+                {
+                    param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), rc2Param.getIV());
+                }
+                else
+                {
+                    param = new ParametersWithIV(param, rc2Param.getIV());
+                }
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else if (params instanceof RC5ParameterSpec)
+        {
+            RC5ParameterSpec    rc5Param = (RC5ParameterSpec)params;
+
+            param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
+            if (baseEngine.getAlgorithmName().startsWith("RC5"))
+            {
+                if (baseEngine.getAlgorithmName().equals("RC5-32"))
+                {
+                    if (rc5Param.getWordSize() != 32)
+                    {
+                        throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + ".");
+                    }
+                }
+                else if (baseEngine.getAlgorithmName().equals("RC5-64"))
+                {
+                    if (rc5Param.getWordSize() != 64)
+                    {
+                        throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + ".");
+                    }
+                }
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5.");
+            }
+            if ((rc5Param.getIV() != null) && (ivLength != 0))
+            {
+                if (param instanceof ParametersWithIV)
+                {
+                    param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), rc5Param.getIV());
+                }
+                else
+                {
+                    param = new ParametersWithIV(param, rc5Param.getIV());
+                }
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+        else if (gcmSpecClass != null && gcmSpecClass.isInstance(params))
+        {
+            if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher))
+            {
+                throw new InvalidAlgorithmParameterException("GCMParameterSpec can only be used with AEAD modes.");
+            }
+
+            try
+            {
+                Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
+                Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
+
+                KeyParameter keyParam;
+                if (param instanceof ParametersWithIV)
+                {
+                    keyParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+                }
+                else
+                {
+                    keyParam = (KeyParameter)param;
+                }
+                param = aeadParams = new AEADParameters(keyParam, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+            }
+            catch (Exception e)
+            {
+                throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec.");
+            }
+        }
+        else if (params != null && !(params instanceof PBEParameterSpec))
+        {
+            throw new InvalidAlgorithmParameterException("unknown parameter type.");
+        }
+
+        if ((ivLength != 0) && !(param instanceof ParametersWithIV) && !(param instanceof AEADParameters))
+        {
+            SecureRandom    ivRandom = random;
+
+            if (ivRandom == null)
+            {
+                ivRandom = CryptoServicesRegistrar.getSecureRandom();
+            }
+
+            if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+            {
+                byte[]  iv = new byte[ivLength];
+
+                // BEGIN Android-changed: For PBE keys with no IV, log and use IV of 0
+                // These keys were accepted in BC 1.52 (and treated as having an IV of 0) but
+                // rejected outright in BC 1.54 (even if an IV was passed in params).  We
+                // want the eventual state to be that an IV can be passed in params, but the key
+                // is rejected otherwise.  For now, log that these will be rejected in a future
+                // release.  See b/27995180 for historical details.
+                // ivRandom.nextBytes(iv);
+                if (!isBCPBEKeyWithoutIV(key)) {
+                    ivRandom.nextBytes(iv);
+                } else {
+                    // TODO(b/70275132): Change to rejecting these keys
+                    System.err.println(" ******** DEPRECATED FUNCTIONALITY ********");
+                    System.err.println(" * You have initialized a cipher with a PBE key with no IV and");
+                    System.err.println(" * have not provided an IV in the AlgorithmParameterSpec.  This");
+                    System.err.println(" * configuration is deprecated.  The cipher will be initialized");
+                    System.err.println(" * with an all-zero IV, but in a future release this call will");
+                    System.err.println(" * throw an exception.");
+                    new InvalidAlgorithmParameterException("No IV set when using PBE key")
+                            .printStackTrace(System.err);
+                }
+                // END Android-changed: For PBE keys with no IV, log and use IV of 0
+                param = new ParametersWithIV(param, iv);
+                ivParam = (ParametersWithIV)param;
+            }
+            else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
+            {
+                // BEGIN Android-changed: For PBE keys with no IV, log and use IV of 0
+                // These keys were accepted in BC 1.52 (and treated as having an IV of 0) but
+                // rejected outright in BC 1.54 (even if an IV was passed in params).  We
+                // want the eventual state to be that an IV can be passed in params, but the key
+                // is rejected otherwise.  For now, log that these will be rejected in a future
+                // release.  See b/27995180 for historical details.
+                // throw new InvalidAlgorithmParameterException("no IV set when one expected");
+                if (!isBCPBEKeyWithoutIV(key)) {
+                    throw new InvalidAlgorithmParameterException("no IV set when one expected");
+                } else {
+                    // TODO(b/70275132): Change to rejecting these keys
+                    System.err.println(" ******** DEPRECATED FUNCTIONALITY ********");
+                    System.err.println(" * You have initialized a cipher with a PBE key with no IV and");
+                    System.err.println(" * have not provided an IV in the AlgorithmParameterSpec.  This");
+                    System.err.println(" * configuration is deprecated.  The cipher will be initialized");
+                    System.err.println(" * with an all-zero IV, but in a future release this call will");
+                    System.err.println(" * throw an exception.");
+                    new InvalidAlgorithmParameterException("No IV set when using PBE key")
+                            .printStackTrace(System.err);
+                    // Mimic behaviour in 1.52 by using an IV of 0's
+                    param = new ParametersWithIV(param, new byte[ivLength]);
+                    ivParam = (ParametersWithIV)param;
+                }
+                // END Android-changed: For PBE keys with no IV, log and use IV of 0
+            }
+        }
+
+
+
+        if (random != null && padded)
+        {
+            param = new ParametersWithRandom(param, random);
+        }
+
+        try
+        {
+            switch (opmode)
+            {
+            case Cipher.ENCRYPT_MODE:
+            case Cipher.WRAP_MODE:
+                cipher.init(true, param);
+                break;
+            case Cipher.DECRYPT_MODE:
+            case Cipher.UNWRAP_MODE:
+                cipher.init(false, param);
+                break;
+            default:
+                throw new InvalidParameterException("unknown opmode " + opmode + " passed");
+            }
+
+            if (cipher instanceof AEADGenericBlockCipher && aeadParams == null)
+            {
+                AEADBlockCipher aeadCipher = ((AEADGenericBlockCipher)cipher).cipher;
+
+                aeadParams = new AEADParameters((KeyParameter)ivParam.getParameters(), aeadCipher.getMac().length * 8, ivParam.getIV());
+            }
+        }
+        catch (final Exception e)
+        {
+            throw new InvalidKeyOrParametersException(e.getMessage(), e);
+        }
+    }
+
+    private CipherParameters adjustParameters(AlgorithmParameterSpec params, CipherParameters param)
+    {
+        CipherParameters key;
+
+        if (param instanceof ParametersWithIV)
+        {
+            key = ((ParametersWithIV)param).getParameters();
+            if (params instanceof IvParameterSpec)
+            {
+                IvParameterSpec iv = (IvParameterSpec)params;
+
+                ivParam = new ParametersWithIV(key, iv.getIV());
+                param = ivParam;
+            }
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            else if (params instanceof GOST28147ParameterSpec)
+            {
+                // need to pick up IV and SBox.
+                GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
+
+                param = new ParametersWithSBox(param, gost28147Param.getSbox());
+
+                if (gost28147Param.getIV() != null && ivLength != 0)
+                {
+                    ivParam = new ParametersWithIV(key, gost28147Param.getIV());
+                    param = ivParam;
+                }
+            }
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+        else
+        {
+            if (params instanceof IvParameterSpec)
+            {
+                IvParameterSpec iv = (IvParameterSpec)params;
+
+                ivParam = new ParametersWithIV(param, iv.getIV());
+                param = ivParam;
+            }
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            else if (params instanceof GOST28147ParameterSpec)
+            {
+                // need to pick up IV and SBox.
+                GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
+
+                param = new ParametersWithSBox(param, gost28147Param.getSbox());
+
+                if (gost28147Param.getIV() != null && ivLength != 0)
+                {
+                    param = new ParametersWithIV(param, gost28147Param.getIV());
+                }
+            }
+            */
+            // END Android-removed: Unsupported algorithms
+        }
+        return param;
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        AlgorithmParameters params,
+        SecureRandom        random) 
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec  paramSpec = null;
+
+        if (params != null)
+        {
+            for (int i = 0; i != availableSpecs.length; i++)
+            {
+                if (availableSpecs[i] == null)
+                {
+                    continue;
+                }
+
+                try
+                {
+                    paramSpec = params.getParameterSpec(availableSpecs[i]);
+                    break;
+                }
+                catch (Exception e)
+                {
+                    // try again if possible
+                }
+            }
+
+            if (paramSpec == null)
+            {
+                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+            }
+        }
+
+        engineInit(opmode, key, paramSpec, random);
+        
+        engineParams = params;
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        SecureRandom        random) 
+        throws InvalidKeyException
+    {
+        try
+        {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+    }
+
+    protected void engineUpdateAAD(byte[] input, int offset, int length)
+    {
+        cipher.updateAAD(input, offset, length);
+    }
+
+    protected void engineUpdateAAD(ByteBuffer bytebuffer)
+    {
+        int offset = bytebuffer.arrayOffset() + bytebuffer.position();
+        int length = bytebuffer.limit() - bytebuffer.position();
+        engineUpdateAAD(bytebuffer.array(), offset, length);
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        int     length = cipher.getUpdateOutputSize(inputLen);
+
+        if (length > 0)
+        {
+                byte[]  out = new byte[length];
+
+                int len = cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+                if (len == 0)
+                {
+                    return null;
+                }
+                else if (len != out.length)
+                {
+                    byte[]  tmp = new byte[len];
+
+                    System.arraycopy(out, 0, tmp, 0, len);
+
+                    return tmp;
+                }
+
+                return out;
+        }
+
+        cipher.processBytes(input, inputOffset, inputLen, null, 0);
+
+        return null;
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset)
+        throws ShortBufferException
+    {
+        if (outputOffset + cipher.getUpdateOutputSize(inputLen) > output.length)
+        {
+            throw new ShortBufferException("output buffer too short for input.");
+        }
+
+        try
+        {
+            return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+        }
+        catch (DataLengthException e)
+        {
+            // should never occur
+            throw new IllegalStateException(e.toString());
+        }
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        int     len = 0;
+        byte[]  tmp = new byte[engineGetOutputSize(inputLen)];
+
+        if (inputLen != 0)
+        {
+            len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
+        }
+
+        try
+        {
+            len += cipher.doFinal(tmp, len);
+        }
+        catch (DataLengthException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+
+        if (len == tmp.length)
+        {
+            return tmp;
+        }
+
+        byte[]  out = new byte[len];
+
+        System.arraycopy(tmp, 0, out, 0, len);
+
+        return out;
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset)
+        throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+    {
+        int     len = 0;
+
+        if (outputOffset + engineGetOutputSize(inputLen) > output.length)
+        {
+            throw new ShortBufferException("output buffer too short for input.");
+        }
+
+        try
+        {
+            if (inputLen != 0)
+            {
+                len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+            }
+
+            return (len + cipher.doFinal(output, outputOffset + len));
+        }
+        catch (OutputLengthException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+        catch (DataLengthException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+    }
+
+    private boolean isAEADModeName(
+        String modeName)
+    {
+        // Android-changed: Unsupported modes
+        // return "CCM".equals(modeName) || "EAX".equals(modeName) || "GCM".equals(modeName) || "OCB".equals(modeName);
+        return "CCM".equals(modeName) || "GCM".equals(modeName);
+    }
+
+    /*
+     * The ciphers that inherit from us.
+     */
+
+    static private interface GenericBlockCipher
+    {
+        public void init(boolean forEncryption, CipherParameters params)
+            throws IllegalArgumentException;
+
+        public boolean wrapOnNoPadding();
+
+        public String getAlgorithmName();
+
+        public com.android.internal.org.bouncycastle.crypto.BlockCipher getUnderlyingCipher();
+
+        public int getOutputSize(int len);
+
+        public int getUpdateOutputSize(int len);
+
+        public void updateAAD(byte[] input, int offset, int length);
+
+        public int processByte(byte in, byte[] out, int outOff)
+            throws DataLengthException;
+
+        public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+            throws DataLengthException;
+
+        public int doFinal(byte[] out, int outOff)
+            throws IllegalStateException,
+            BadPaddingException;
+    }
+
+    private static class BufferedGenericBlockCipher
+        implements GenericBlockCipher
+    {
+        private BufferedBlockCipher cipher;
+
+        BufferedGenericBlockCipher(BufferedBlockCipher cipher)
+        {
+            this.cipher = cipher;
+        }
+
+        BufferedGenericBlockCipher(com.android.internal.org.bouncycastle.crypto.BlockCipher cipher)
+        {
+            this.cipher = new PaddedBufferedBlockCipher(cipher);
+        }
+
+        BufferedGenericBlockCipher(com.android.internal.org.bouncycastle.crypto.BlockCipher cipher, BlockCipherPadding padding)
+        {
+            this.cipher = new PaddedBufferedBlockCipher(cipher, padding);
+        }
+
+        public void init(boolean forEncryption, CipherParameters params)
+            throws IllegalArgumentException
+        {
+            cipher.init(forEncryption, params);
+        }
+
+        public boolean wrapOnNoPadding()
+        {
+            return !(cipher instanceof CTSBlockCipher);
+        }
+
+        public String getAlgorithmName()
+        {
+            return cipher.getUnderlyingCipher().getAlgorithmName();
+        }
+
+        public com.android.internal.org.bouncycastle.crypto.BlockCipher getUnderlyingCipher()
+        {
+            return cipher.getUnderlyingCipher();
+        }
+
+        public int getOutputSize(int len)
+        {
+            return cipher.getOutputSize(len);
+        }
+
+        public int getUpdateOutputSize(int len)
+        {
+            return cipher.getUpdateOutputSize(len);
+        }
+
+        public void updateAAD(byte[] input, int offset, int length)
+        {
+            throw new UnsupportedOperationException("AAD is not supported in the current mode.");
+        }
+
+        public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+        {
+            return cipher.processByte(in, out, outOff);
+        }
+
+        public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+        {
+            return cipher.processBytes(in, inOff, len, out, outOff);
+        }
+
+        public int doFinal(byte[] out, int outOff) throws IllegalStateException, BadPaddingException
+        {
+            try
+            {
+                return cipher.doFinal(out, outOff);
+            }
+            catch (InvalidCipherTextException e)
+            {
+                throw new BadPaddingException(e.getMessage());
+            }
+        }
+    }
+
+    private static class AEADGenericBlockCipher
+        implements GenericBlockCipher
+    {
+        private static final Constructor aeadBadTagConstructor;
+
+        static {
+            Class aeadBadTagClass = ClassUtil.loadClass(BaseBlockCipher.class, "javax.crypto.AEADBadTagException");
+            if (aeadBadTagClass != null)
+            {
+                aeadBadTagConstructor = findExceptionConstructor(aeadBadTagClass);
+            }
+            else
+            {
+                aeadBadTagConstructor = null;
+            }
+        }
+
+        private static Constructor findExceptionConstructor(Class clazz)
+        {
+            try
+            {
+                return clazz.getConstructor(new Class[]{String.class});
+            }
+            catch (Exception e)
+            {
+                return null;
+            }
+        }
+
+        private AEADBlockCipher cipher;
+
+        AEADGenericBlockCipher(AEADBlockCipher cipher)
+        {
+            this.cipher = cipher;
+        }
+
+        public void init(boolean forEncryption, CipherParameters params)
+            throws IllegalArgumentException
+        {
+            cipher.init(forEncryption, params);
+        }
+
+        public String getAlgorithmName()
+        {
+            return cipher.getUnderlyingCipher().getAlgorithmName();
+        }
+
+        public boolean wrapOnNoPadding()
+        {
+            return false;
+        }
+
+        public com.android.internal.org.bouncycastle.crypto.BlockCipher getUnderlyingCipher()
+        {
+            return cipher.getUnderlyingCipher();
+        }
+
+        public int getOutputSize(int len)
+        {
+            return cipher.getOutputSize(len);
+        }
+
+        public int getUpdateOutputSize(int len)
+        {
+            return cipher.getUpdateOutputSize(len);
+        }
+
+        public void updateAAD(byte[] input, int offset, int length)
+        {
+            cipher.processAADBytes(input, offset, length);
+        }
+
+        public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+        {
+            return cipher.processByte(in, out, outOff);
+        }
+
+        public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+        {
+            return cipher.processBytes(in, inOff, len, out, outOff);
+        }
+
+        public int doFinal(byte[] out, int outOff) throws IllegalStateException, BadPaddingException
+        {
+            try
+            {
+                return cipher.doFinal(out, outOff);
+            }
+            catch (InvalidCipherTextException e)
+            {
+                if (aeadBadTagConstructor != null)
+                {
+                    BadPaddingException aeadBadTag = null;
+                    try
+                    {
+                        aeadBadTag = (BadPaddingException)aeadBadTagConstructor
+                                .newInstance(new Object[]{e.getMessage()});
+                    }
+                    catch (Exception i)
+                    {
+                        // Shouldn't happen, but fall through to BadPaddingException
+                    }
+                    if (aeadBadTag != null)
+                    {
+                        throw aeadBadTag;
+                    }
+                }
+                throw new BadPaddingException(e.getMessage());
+            }
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java
new file mode 100644
index 0000000..64e09b9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java
@@ -0,0 +1,87 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.KeyGeneratorSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.android.internal.org.bouncycastle.crypto.CipherKeyGenerator;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.KeyGenerationParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BaseKeyGenerator
+    extends KeyGeneratorSpi
+{
+    protected String                algName;
+    protected int                   keySize;
+    protected int                   defaultKeySize;
+    protected CipherKeyGenerator    engine;
+
+    protected boolean               uninitialised = true;
+
+    protected BaseKeyGenerator(
+        String algName,
+        int defaultKeySize,
+        CipherKeyGenerator engine)
+    {
+        this.algName = algName;
+        this.keySize = this.defaultKeySize = defaultKeySize;
+        this.engine = engine;
+    }
+
+    protected void engineInit(
+        AlgorithmParameterSpec  params,
+        SecureRandom            random)
+    throws InvalidAlgorithmParameterException
+    {
+        throw new InvalidAlgorithmParameterException("Not Implemented");
+    }
+
+    protected void engineInit(
+        SecureRandom    random)
+    {
+        if (random != null)
+        {
+            engine.init(new KeyGenerationParameters(random, defaultKeySize));
+            uninitialised = false;
+        }
+    }
+
+    protected void engineInit(
+        int             keySize,
+        SecureRandom    random)
+    {
+        try
+        {
+            if (random == null)
+            {
+                random = CryptoServicesRegistrar.getSecureRandom();
+            }
+            engine.init(new KeyGenerationParameters(random, keySize));
+            uninitialised = false;
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw new InvalidParameterException(e.getMessage());
+        }
+    }
+
+    protected SecretKey engineGenerateKey()
+    {
+        if (uninitialised)
+        {
+            engine.init(new KeyGenerationParameters(CryptoServicesRegistrar.getSecureRandom(), defaultKeySize));
+            uninitialised = false;
+        }
+
+        return new SecretKeySpec(engine.generateKey(), algName);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
new file mode 100644
index 0000000..2d109ed
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
@@ -0,0 +1,294 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.lang.reflect.Method;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.crypto.MacSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.PBEKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.Mac;
+import com.android.internal.org.bouncycastle.crypto.macs.HMac;
+import com.android.internal.org.bouncycastle.crypto.params.AEADParameters;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.params.RC2Parameters;
+// import org.bouncycastle.crypto.params.SkeinParameters;
+import com.android.internal.org.bouncycastle.jcajce.PKCS12Key;
+import com.android.internal.org.bouncycastle.jcajce.spec.AEADParameterSpec;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jcajce.spec.SkeinParameterSpec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BaseMac
+    extends MacSpi implements PBE
+{
+    private static final Class gcmSpecClass = ClassUtil.loadClass(BaseMac.class, "javax.crypto.spec.GCMParameterSpec");
+
+    private Mac macEngine;
+
+    private int scheme = PKCS12;
+    private int pbeHash = SHA1;
+    private int keySize = 160;
+
+    protected BaseMac(
+        Mac macEngine)
+    {
+        this.macEngine = macEngine;
+    }
+
+    protected BaseMac(
+        Mac macEngine,
+        int scheme,
+        int pbeHash,
+        int keySize)
+    {
+        this.macEngine = macEngine;
+        this.scheme = scheme;
+        this.pbeHash = pbeHash;
+        this.keySize = keySize;
+    }
+
+    protected void engineInit(
+        Key                     key,
+        AlgorithmParameterSpec  params)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        if (key == null)
+        {
+            throw new InvalidKeyException("key is null");
+        }
+
+        if (key instanceof PKCS12Key)
+        {
+            SecretKey k;
+            PBEParameterSpec pbeSpec;
+
+            try
+            {
+                k = (SecretKey)key;
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeyException("PKCS12 requires a SecretKey/PBEKey");
+            }
+
+            try
+            {
+                pbeSpec = (PBEParameterSpec)params;
+            }
+            catch (Exception e)
+            {
+                throw new InvalidAlgorithmParameterException("PKCS12 requires a PBEParameterSpec");
+            }
+
+            if (k instanceof PBEKey && pbeSpec == null)
+            {
+                pbeSpec = new PBEParameterSpec(((PBEKey)k).getSalt(), ((PBEKey)k).getIterationCount());
+            }
+
+            int digest = SHA1;
+            int keySize = 160;
+            // BEGIN Android-removed: Unsupported algorithms
+            // if (macEngine.getAlgorithmName().startsWith("GOST"))
+            // {
+            //     digest = GOST3411;
+            //     keySize = 256;
+            // }
+            // END Android-removed: Unsupported algorithms
+            // Android-changed: Adjust for missing if
+            // else if (macEngine instanceof HMac)
+            if (macEngine instanceof HMac)
+            {
+                if (!macEngine.getAlgorithmName().startsWith("SHA-1"))
+                {
+                    if (macEngine.getAlgorithmName().startsWith("SHA-224"))
+                    {
+                        digest = SHA224;
+                        keySize = 224;
+                    }
+                    else if (macEngine.getAlgorithmName().startsWith("SHA-256"))
+                    {
+                        digest = SHA256;
+                        keySize = 256;
+                    }
+                    else if (macEngine.getAlgorithmName().startsWith("SHA-384"))
+                    {
+                        digest = SHA384;
+                        keySize = 384;
+                    }
+                    else if (macEngine.getAlgorithmName().startsWith("SHA-512"))
+                    {
+                        digest = SHA512;
+                        keySize = 512;
+                    }
+                    // BEGIN Android-removed: Unsupported algorithms
+                    // else if (macEngine.getAlgorithmName().startsWith("RIPEMD160"))
+                    // {
+                    //     digest = RIPEMD160;
+                    //     keySize = 160;
+                    // }
+                    // END Android-removed: Unsupported algorithms
+                    else
+                    {
+                        throw new InvalidAlgorithmParameterException("no PKCS12 mapping for HMAC: " + macEngine.getAlgorithmName());
+                    }
+                }
+            }
+            // TODO: add correct handling for other digests
+            param = PBE.Util.makePBEMacParameters(k, PKCS12, digest, keySize, pbeSpec);
+        }
+        else if (key instanceof BCPBEKey)
+        {
+            BCPBEKey k = (BCPBEKey)key;
+
+            if (k.getParam() != null)
+            {
+                param = k.getParam();
+            }
+            else if (params instanceof PBEParameterSpec)
+            {
+                param = PBE.Util.makePBEMacParameters(k, params);
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+            }
+        }
+        else
+        {
+            if (params instanceof PBEParameterSpec)
+            {
+                throw new InvalidAlgorithmParameterException("inappropriate parameter type: " + params.getClass().getName());
+            }
+            param = new KeyParameter(key.getEncoded());
+        }
+
+        KeyParameter keyParam;
+        if (param instanceof ParametersWithIV)
+        {
+            keyParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+        }
+        else
+        {
+            keyParam = (KeyParameter)param;
+        }
+
+        if (params instanceof AEADParameterSpec)
+        {
+            AEADParameterSpec aeadSpec = (AEADParameterSpec)params;
+
+            param = new AEADParameters(keyParam, aeadSpec.getMacSizeInBits(), aeadSpec.getNonce(), aeadSpec.getAssociatedData());
+        }
+        else if (params instanceof IvParameterSpec)
+        {
+            param = new ParametersWithIV(keyParam, ((IvParameterSpec)params).getIV());
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (params instanceof RC2ParameterSpec)
+        {
+            param = new ParametersWithIV(new RC2Parameters(keyParam.getKey(), ((RC2ParameterSpec)params).getEffectiveKeyBits()), ((RC2ParameterSpec)params).getIV());
+        }
+        else if (params instanceof SkeinParameterSpec)
+        {
+            param = new SkeinParameters.Builder(copyMap(((SkeinParameterSpec)params).getParameters())).setKey(keyParam.getKey()).build();
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+        else if (params == null)
+        {
+            param = new KeyParameter(key.getEncoded());
+        }
+        else if (gcmSpecClass != null && gcmSpecClass.isAssignableFrom(params.getClass()))
+        {
+            try
+            {
+                Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
+                Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
+
+                param = new AEADParameters(keyParam, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+            }
+            catch (Exception e)
+            {
+                throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec.");
+            }
+        }
+        else if (!(params instanceof PBEParameterSpec))
+        {
+            throw new InvalidAlgorithmParameterException("unknown parameter type: " + params.getClass().getName());
+        }
+
+        try
+        {
+            macEngine.init(param);
+        }
+        catch (Exception e)
+        {
+            throw new InvalidAlgorithmParameterException("cannot initialize MAC: " + e.getMessage());
+        }
+    }
+
+    protected int engineGetMacLength() 
+    {
+        return macEngine.getMacSize();
+    }
+
+    protected void engineReset() 
+    {
+        macEngine.reset();
+    }
+
+    protected void engineUpdate(
+        byte    input) 
+    {
+        macEngine.update(input);
+    }
+
+    protected void engineUpdate(
+        byte[]  input,
+        int     offset,
+        int     len) 
+    {
+        macEngine.update(input, offset, len);
+    }
+
+    protected byte[] engineDoFinal() 
+    {
+        byte[]  out = new byte[engineGetMacLength()];
+
+        macEngine.doFinal(out, 0);
+
+        return out;
+    }
+
+    private static Hashtable copyMap(Map paramsMap)
+    {
+        Hashtable newTable = new Hashtable();
+
+        Iterator keys = paramsMap.keySet().iterator();
+        while (keys.hasNext())
+        {
+            Object key = keys.next();
+            newTable.put(key, paramsMap.get(key));
+        }
+
+        return newTable;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java
new file mode 100644
index 0000000..0265e6a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java
@@ -0,0 +1,97 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.lang.reflect.Constructor;
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BaseSecretKeyFactory
+    extends SecretKeyFactorySpi
+    implements PBE
+{
+    protected String                algName;
+    protected ASN1ObjectIdentifier   algOid;
+
+    protected BaseSecretKeyFactory(
+        String algName,
+        ASN1ObjectIdentifier algOid)
+    {
+        this.algName = algName;
+        this.algOid = algOid;
+    }
+
+    protected SecretKey engineGenerateSecret(
+        KeySpec keySpec)
+    throws InvalidKeySpecException
+    {
+        if (keySpec instanceof SecretKeySpec)
+        {
+            return new SecretKeySpec(((SecretKeySpec)keySpec).getEncoded(), algName);
+        }
+
+        throw new InvalidKeySpecException("Invalid KeySpec");
+    }
+
+    protected KeySpec engineGetKeySpec(
+        SecretKey key,
+        Class keySpec)
+    throws InvalidKeySpecException
+    {
+        if (keySpec == null)
+        {
+            throw new InvalidKeySpecException("keySpec parameter is null");
+        }
+        if (key == null)
+        {
+            throw new InvalidKeySpecException("key parameter is null");
+        }
+        
+        if (SecretKeySpec.class.isAssignableFrom(keySpec))
+        {
+            return new SecretKeySpec(key.getEncoded(), algName);
+        }
+
+        try
+        {
+            Class[] parameters = { byte[].class };
+
+            Constructor c = keySpec.getConstructor(parameters);
+            Object[]    p = new Object[1];
+
+            p[0] = key.getEncoded();
+
+            return (KeySpec)c.newInstance(p);
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeySpecException(e.toString());
+        }
+    }
+
+    protected SecretKey engineTranslateKey(
+        SecretKey key)
+    throws InvalidKeyException
+    {
+        if (key == null)
+        {
+            throw new InvalidKeyException("key parameter is null");
+        }
+        
+        if (!key.getAlgorithm().equalsIgnoreCase(algName))
+        {
+            throw new InvalidKeyException("Key not of type " + algName + ".");
+        }
+
+        return new SecretKeySpec(key.getEncoded(), algName);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
new file mode 100644
index 0000000..852d289
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
@@ -0,0 +1,441 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+// Android-removed: Unsupported algorithms
+// import javax.crypto.spec.RC2ParameterSpec;
+// import javax.crypto.spec.RC5ParameterSpec;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.DataLengthException;
+import com.android.internal.org.bouncycastle.crypto.StreamCipher;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+import com.android.internal.org.bouncycastle.jcajce.PKCS12Key;
+import com.android.internal.org.bouncycastle.jcajce.PKCS12KeyWithParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BaseStreamCipher
+    extends BaseWrapCipher
+    implements PBE
+{
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        // Android-removed: Unsupported algorithms
+                                        // RC2ParameterSpec.class,
+                                        // RC5ParameterSpec.class,
+                                        IvParameterSpec.class,
+                                        PBEParameterSpec.class
+                                    };
+
+    private StreamCipher       cipher;
+    private int keySizeInBits;
+    private int digest;
+    private ParametersWithIV   ivParam;
+
+    private int                     ivLength = 0;
+
+    private PBEParameterSpec        pbeSpec = null;
+    private String                  pbeAlgorithm = null;
+
+    protected BaseStreamCipher(
+        StreamCipher engine,
+        int ivLength)
+    {
+        this(engine, ivLength, -1, -1);
+    }
+
+    protected BaseStreamCipher(
+        StreamCipher engine,
+        int ivLength,
+        int keySizeInBits,
+        int digest)
+    {
+        cipher = engine;
+        this.ivLength = ivLength;
+        this.keySizeInBits = keySizeInBits;
+        this.digest = digest;
+    }
+
+    protected int engineGetBlockSize()
+    {
+        return 0;
+    }
+
+    protected byte[] engineGetIV()
+    {
+        return (ivParam != null) ? ivParam.getIV() : null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key)
+    {
+        return key.getEncoded().length * 8;
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen)
+    {
+        return inputLen;
+    }
+
+    protected AlgorithmParameters engineGetParameters()
+    {
+        if (engineParams == null)
+        {
+            if (pbeSpec != null)
+            {
+                try
+                {
+                    AlgorithmParameters engineParams = createParametersInstance(pbeAlgorithm);
+                    engineParams.init(pbeSpec);
+
+                    return engineParams;
+                }
+                catch (Exception e)
+                {
+                    return null;
+                }
+            }
+            else if (ivParam != null)
+            {
+                String  name = cipher.getAlgorithmName();
+
+                if (name.indexOf('/') >= 0)
+                {
+                    name = name.substring(0, name.indexOf('/'));
+                }
+                if (name.startsWith("ChaCha7539"))
+                {
+                    name = "ChaCha7539";
+                }
+                else if (name.startsWith("Grain"))
+                {
+                    name = "Grainv1";
+                }
+                else if (name.startsWith("HC"))
+                {
+                    int endIndex = name.indexOf('-');
+                    name = name.substring(0, endIndex) + name.substring(endIndex + 1);
+                }
+
+                try
+                {
+                    engineParams = createParametersInstance(name);
+                    engineParams.init(new IvParameterSpec(ivParam.getIV()));
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
+        }
+
+        return engineParams;
+    }
+
+    /**
+     * should never be called.
+     */
+    protected void engineSetMode(
+        String  mode)
+        throws NoSuchAlgorithmException
+    {
+        if (!(mode.equalsIgnoreCase("ECB") || mode.equals("NONE")))
+        {
+            throw new NoSuchAlgorithmException("can't support mode " + mode);
+        }
+    }
+
+    /**
+     * should never be called.
+     */
+    protected void engineSetPadding(
+        String  padding)
+    throws NoSuchPaddingException
+    {
+        if (!padding.equalsIgnoreCase("NoPadding"))
+        {
+            throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+        }
+    }
+
+    protected void engineInit(
+        int                     opmode,
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        this.pbeSpec = null;
+        this.pbeAlgorithm = null;
+
+        this.engineParams = null;
+
+        //
+        // basic key check
+        //
+        if (!(key instanceof SecretKey))
+        {
+            throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
+        }
+
+        if (key instanceof PKCS12Key)
+        {
+            PKCS12Key k = (PKCS12Key)key;
+            pbeSpec = (PBEParameterSpec)params;
+            if (k instanceof PKCS12KeyWithParameters && pbeSpec == null)
+            {
+                pbeSpec = new PBEParameterSpec(((PKCS12KeyWithParameters)k).getSalt(), ((PKCS12KeyWithParameters)k).getIterationCount());
+            }
+
+            param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS12, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
+        }
+        else if (key instanceof BCPBEKey)
+        {
+            BCPBEKey k = (BCPBEKey)key;
+
+            if (k.getOID() != null)
+            {
+                pbeAlgorithm = k.getOID().getId();
+            }
+            else
+            {
+                pbeAlgorithm = k.getAlgorithm();
+            }
+
+            if (k.getParam() != null)
+            {
+                param = k.getParam();
+                pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
+            }
+            else if (params instanceof PBEParameterSpec)
+            {
+                param = PBE.Util.makePBEParameters(k, params, cipher.getAlgorithmName());
+                pbeSpec = (PBEParameterSpec)params;
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+            }
+            
+            if (k.getIvSize() != 0)
+            {
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else if (params == null)
+        {
+            if (digest > 0)
+            {
+                throw new InvalidKeyException("Algorithm requires a PBE key");
+            }
+            param = new KeyParameter(key.getEncoded());
+        }
+        else if (params instanceof IvParameterSpec)
+        {
+            param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+            ivParam = (ParametersWithIV)param;
+        }
+        else
+        {
+            throw new InvalidAlgorithmParameterException("unknown parameter type.");
+        }
+
+        if ((ivLength != 0) && !(param instanceof ParametersWithIV))
+        {
+            SecureRandom    ivRandom = random;
+
+            if (ivRandom == null)
+            {
+                ivRandom = CryptoServicesRegistrar.getSecureRandom();
+            }
+
+            if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+            {
+                byte[]  iv = new byte[ivLength];
+
+                ivRandom.nextBytes(iv);
+                param = new ParametersWithIV(param, iv);
+                ivParam = (ParametersWithIV)param;
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("no IV set when one expected");
+            }
+        }
+
+        try
+        {
+            switch (opmode)
+            {
+            case Cipher.ENCRYPT_MODE:
+            case Cipher.WRAP_MODE:
+                cipher.init(true, param);
+                break;
+            case Cipher.DECRYPT_MODE:
+            case Cipher.UNWRAP_MODE:
+                cipher.init(false, param);
+                break;
+            default:
+                throw new InvalidParameterException("unknown opmode " + opmode + " passed");
+            }
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        AlgorithmParameters params,
+        SecureRandom        random) 
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec  paramSpec = null;
+
+        if (params != null)
+        {
+            for (int i = 0; i != availableSpecs.length; i++)
+            {
+                try
+                {
+                    paramSpec = params.getParameterSpec(availableSpecs[i]);
+                    break;
+                }
+                catch (Exception e)
+                {
+                    continue;
+                }
+            }
+
+            if (paramSpec == null)
+            {
+                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+            }
+        }
+
+        engineInit(opmode, key, paramSpec, random);
+        engineParams = params;
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        SecureRandom        random) 
+        throws InvalidKeyException
+    {
+        try
+        {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        byte[]  out = new byte[inputLen];
+
+        cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+        return out;
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+        throws ShortBufferException 
+    {
+        if (outputOffset + inputLen > output.length)
+        {
+            throw new ShortBufferException("output buffer too short for input.");
+        }
+
+        try
+        {
+            cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+
+            return inputLen;
+        }
+        catch (DataLengthException e)
+        {
+            // should never happen
+            throw new IllegalStateException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        if (inputLen != 0)
+        {
+            byte[] out = engineUpdate(input, inputOffset, inputLen);
+
+            cipher.reset();
+            
+            return out;
+        }
+
+        cipher.reset();
+        
+        return new byte[0];
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset)
+        throws ShortBufferException
+    {
+        if (outputOffset + inputLen > output.length)
+        {
+            throw new ShortBufferException("output buffer too short for input.");
+        }
+
+        if (inputLen != 0)
+        {
+            cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+        }
+
+        cipher.reset();
+        
+        return inputLen;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
new file mode 100644
index 0000000..ebd3bc5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
@@ -0,0 +1,617 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+// Android-removed: Unsupported algorithms
+// import javax.crypto.spec.RC2ParameterSpec;
+// import javax.crypto.spec.RC5ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.android.internal.org.bouncycastle.crypto.Wrapper;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithRandom;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.params.ParametersWithSBox;
+// import org.bouncycastle.crypto.params.ParametersWithUKM;
+// import org.bouncycastle.jcajce.spec.GOST28147WrapParameterSpec;
+// Android-changed: Use default provider for JCA algorithms instead of BC
+// Was: import org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class BaseWrapCipher
+    extends CipherSpi
+    implements PBE
+{
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        // Android-removed: Unsupported algorithms
+                                        // GOST28147WrapParameterSpec.class,
+                                        PBEParameterSpec.class,
+                                        // Android-removed: Unsupported algorithms
+                                        // RC2ParameterSpec.class,
+                                        // RC5ParameterSpec.class
+                                        IvParameterSpec.class
+                                    };
+
+    protected int                     pbeType = PKCS12;
+    protected int                     pbeHash = SHA1;
+    protected int                     pbeKeySize;
+    protected int                     pbeIvSize;
+
+    protected AlgorithmParameters     engineParams = null;
+
+    protected Wrapper                 wrapEngine = null;
+
+    private int                       ivSize;
+    private byte[]                    iv;
+
+    private ErasableOutputStream wrapStream = null;
+    private boolean                   forWrapping;
+
+    // Android-changed: Use default provider for JCA algorithms instead of BC
+    // Was: private final JcaJceHelper helper = new BCJcaJceHelper();
+    private final JcaJceHelper helper = new DefaultJcaJceHelper();
+
+    protected BaseWrapCipher()
+    {
+    }
+
+    protected BaseWrapCipher(
+        Wrapper wrapEngine)
+    {
+        this(wrapEngine, 0);
+    }
+
+    protected BaseWrapCipher(
+        Wrapper wrapEngine,
+        int ivSize)
+    {
+        this.wrapEngine = wrapEngine;
+        this.ivSize = ivSize;
+    }
+
+    protected int engineGetBlockSize()
+    {
+        return 0;
+    }
+
+    protected byte[] engineGetIV()
+    {
+        return Arrays.clone(iv);
+    }
+
+    protected int engineGetKeySize(
+        Key     key)
+    {
+        return key.getEncoded().length * 8;
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen)
+    {
+        return -1;
+    }
+
+    protected AlgorithmParameters engineGetParameters()
+    {
+        if (engineParams == null)
+        {
+            if (iv != null)
+            {
+                String  name = wrapEngine.getAlgorithmName();
+
+                if (name.indexOf('/') >= 0)
+                {
+                    name = name.substring(0, name.indexOf('/'));
+                }
+
+                try
+                {
+                    engineParams = createParametersInstance(name);
+                    engineParams.init(new IvParameterSpec(iv));
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
+        }
+
+        return engineParams;
+    }
+
+    protected final AlgorithmParameters createParametersInstance(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return helper.createAlgorithmParameters(algorithm);
+    }
+
+    protected void engineSetMode(
+        String  mode)
+        throws NoSuchAlgorithmException
+    {
+        throw new NoSuchAlgorithmException("can't support mode " + mode);
+    }
+
+    protected void engineSetPadding(
+        String  padding)
+    throws NoSuchPaddingException
+    {
+        throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+    }
+
+    protected void engineInit(
+        int                     opmode,
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random)
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        if (key instanceof BCPBEKey)
+        {
+            BCPBEKey k = (BCPBEKey)key;
+
+            if (params instanceof PBEParameterSpec)
+            {
+                param = PBE.Util.makePBEParameters(k, params, wrapEngine.getAlgorithmName());
+            }
+            else if (k.getParam() != null)
+            {
+                param = k.getParam();
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+            }
+        }
+        else
+        {
+            param = new KeyParameter(key.getEncoded());
+        }
+
+        if (params instanceof IvParameterSpec)
+        {
+            IvParameterSpec ivSpec = (IvParameterSpec)params;
+            this.iv = ivSpec.getIV();
+            param = new ParametersWithIV(param, iv);
+        }
+
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        if (params instanceof GOST28147WrapParameterSpec)
+        {
+            GOST28147WrapParameterSpec spec = (GOST28147WrapParameterSpec) params;
+
+            byte[] sBox = spec.getSBox();
+            if (sBox != null)
+            {
+                param = new ParametersWithSBox(param, sBox);
+            }
+            param = new ParametersWithUKM(param, spec.getUKM());
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+
+        if (param instanceof KeyParameter && ivSize != 0)
+        {
+            if (opmode == Cipher.WRAP_MODE || opmode == Cipher.ENCRYPT_MODE)
+            {
+                iv = new byte[ivSize];
+                random.nextBytes(iv);
+                param = new ParametersWithIV(param, iv);
+            }
+        }
+
+        if (random != null)
+        {
+            param = new ParametersWithRandom(param, random);
+        }
+
+        try
+        {
+            switch (opmode)
+            {
+            case Cipher.WRAP_MODE:
+                wrapEngine.init(true, param);
+                this.wrapStream = null;
+                this.forWrapping = true;
+                break;
+            case Cipher.UNWRAP_MODE:
+                wrapEngine.init(false, param);
+                this.wrapStream = null;
+                this.forWrapping = false;
+                break;
+            case Cipher.ENCRYPT_MODE:
+                wrapEngine.init(true, param);
+                this.wrapStream = new ErasableOutputStream();
+                this.forWrapping = true;
+                break;
+            case Cipher.DECRYPT_MODE:
+                wrapEngine.init(false, param);
+                this.wrapStream = new ErasableOutputStream();
+                this.forWrapping = false;
+                break;
+            default:
+                throw new InvalidParameterException("Unknown mode parameter passed to init.");
+            }
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeyOrParametersException(e.getMessage(), e);
+        }
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        AlgorithmParameters params,
+        SecureRandom        random)
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec  paramSpec = null;
+
+        if (params != null)
+        {
+            for (int i = 0; i != availableSpecs.length; i++)
+            {
+                try
+                {
+                    paramSpec = params.getParameterSpec(availableSpecs[i]);
+                    break;
+                }
+                catch (Exception e)
+                {
+                    // try next spec
+                }
+            }
+
+            if (paramSpec == null)
+            {
+                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+            }
+        }
+
+        engineParams = params;
+        engineInit(opmode, key, paramSpec, random);
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        SecureRandom        random)
+        throws InvalidKeyException
+    {
+        try
+        {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            throw new InvalidKeyOrParametersException(e.getMessage(), e);
+        }
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen)
+    {
+        if (wrapStream == null)
+        {
+            throw new IllegalStateException("not supported in a wrapping mode");
+        }
+
+        wrapStream.write(input, inputOffset, inputLen);
+
+        return null;
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset)
+        throws ShortBufferException
+    {
+        if (wrapStream == null)
+        {
+            throw new IllegalStateException("not supported in a wrapping mode");
+        }
+
+        wrapStream.write(input, inputOffset, inputLen);
+
+        return 0;
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen)
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        if (wrapStream == null)
+        {
+            throw new IllegalStateException("not supported in a wrapping mode");
+        }
+
+        wrapStream.write(input, inputOffset, inputLen);
+
+        try
+        {
+            if (forWrapping)
+            {
+                try
+                {
+                    return wrapEngine.wrap(wrapStream.getBuf(), 0, wrapStream.size());
+                }
+                catch (Exception e)
+                {
+                    throw new IllegalBlockSizeException(e.getMessage());
+                }
+            }
+            else
+            {
+                try
+                {
+                    return wrapEngine.unwrap(wrapStream.getBuf(), 0, wrapStream.size());
+                }
+                catch (InvalidCipherTextException e)
+                {
+                    throw new BadPaddingException(e.getMessage());
+                }
+            }
+        }
+        finally
+        {
+            wrapStream.erase();
+        }
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset)
+        throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+    {
+        if (wrapStream == null)
+        {
+            throw new IllegalStateException("not supported in a wrapping mode");
+        }
+
+        wrapStream.write(input, inputOffset, inputLen);
+
+        try
+        {
+            byte[] enc;
+
+            if (forWrapping)
+            {
+                try
+                {
+                    enc = wrapEngine.wrap(wrapStream.getBuf(), 0, wrapStream.size());
+                }
+                catch (Exception e)
+                {
+                    throw new IllegalBlockSizeException(e.getMessage());
+                }
+            }
+            else
+            {
+                try
+                {
+                    enc = wrapEngine.unwrap(wrapStream.getBuf(), 0, wrapStream.size());
+                }
+                catch (InvalidCipherTextException e)
+                {
+                    throw new BadPaddingException(e.getMessage());
+                }
+            }
+
+            if (outputOffset + enc.length > output.length)
+            {
+                throw new ShortBufferException("output buffer too short for input.");
+            }
+
+            System.arraycopy(enc, 0, output, outputOffset, enc.length);
+
+            return enc.length;
+        }
+        finally
+        {
+            wrapStream.erase();
+        }
+    }
+
+    protected byte[] engineWrap(
+        Key     key)
+    throws IllegalBlockSizeException, InvalidKeyException
+    {
+        byte[] encoded = key.getEncoded();
+        if (encoded == null)
+        {
+            throw new InvalidKeyException("Cannot wrap key, null encoding.");
+        }
+
+        try
+        {
+            if (wrapEngine == null)
+            {
+                return engineDoFinal(encoded, 0, encoded.length);
+            }
+            else
+            {
+                return wrapEngine.wrap(encoded, 0, encoded.length);
+            }
+        }
+        catch (BadPaddingException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+    }
+
+    protected Key engineUnwrap(
+        byte[]  wrappedKey,
+        String  wrappedKeyAlgorithm,
+        int     wrappedKeyType)
+    throws InvalidKeyException, NoSuchAlgorithmException
+    {
+        byte[] encoded;
+        try
+        {
+            if (wrapEngine == null)
+            {
+                encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+            }
+            else
+            {
+                encoded = wrapEngine.unwrap(wrappedKey, 0, wrappedKey.length);
+            }
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+        catch (BadPaddingException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+        catch (IllegalBlockSizeException e2)
+        {
+            throw new InvalidKeyException(e2.getMessage());
+        }
+
+        if (wrappedKeyType == Cipher.SECRET_KEY)
+        {
+            return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+        }
+        else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
+        {
+            /*
+             * The caller doesn't know the algorithm as it is part of
+             * the encrypted data.
+             */
+            try
+            {
+                PrivateKeyInfo       in = PrivateKeyInfo.getInstance(encoded);
+
+                PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
+
+                if (privKey != null)
+                {
+                    return privKey;
+                }
+                else
+                {
+                    throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
+                }
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeyException("Invalid key encoding.");
+            }
+        }
+        else
+        {
+            try
+            {
+                KeyFactory kf = helper.createKeyFactory(wrappedKeyAlgorithm);
+
+                if (wrappedKeyType == Cipher.PUBLIC_KEY)
+                {
+                    return kf.generatePublic(new X509EncodedKeySpec(encoded));
+                }
+                else if (wrappedKeyType == Cipher.PRIVATE_KEY)
+                {
+                    return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+                }
+            }
+            catch (NoSuchProviderException e)
+            {
+                throw new InvalidKeyException("Unknown key type " + e.getMessage());
+            }
+            catch (InvalidKeySpecException e2)
+            {
+                throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+            }
+
+            throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+        }
+    }
+
+    protected static final class ErasableOutputStream
+        extends ByteArrayOutputStream
+    {
+        public ErasableOutputStream()
+        {
+        }
+
+        public byte[] getBuf()
+        {
+            return buf;
+        }
+
+        public void erase()
+        {
+            Arrays.fill(this.buf, (byte)0);
+            reset();
+        }
+    }
+
+    protected static class InvalidKeyOrParametersException
+        extends InvalidKeyException
+    {
+        private final Throwable cause;
+
+        InvalidKeyOrParametersException(String msg, Throwable cause)
+        {
+             super(msg);
+            this.cause = cause;
+        }
+
+        public Throwable getCause()
+        {
+            return cause;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BlockCipherProvider.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BlockCipherProvider.java
new file mode 100644
index 0000000..330d51b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/BlockCipherProvider.java
@@ -0,0 +1,12 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import com.android.internal.org.bouncycastle.crypto.BlockCipher;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface BlockCipherProvider
+{
+    BlockCipher get();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/ClassUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/ClassUtil.java
new file mode 100644
index 0000000..5582be7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/ClassUtil.java
@@ -0,0 +1,49 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ClassUtil
+{
+    public static Class loadClass(Class sourceClass, final String className)
+    {
+        try
+        {
+            ClassLoader loader = sourceClass.getClassLoader();
+
+            if (loader != null)
+            {
+                return loader.loadClass(className);
+            }
+            else
+            {
+                return (Class)AccessController.doPrivileged(new PrivilegedAction()
+                {
+                    public Object run()
+                    {
+                        try
+                        {
+                            return Class.forName(className);
+                        }
+                        catch (Exception e)
+                        {
+                            // ignore - maybe log?
+                        }
+
+                        return null;
+                    }
+                });
+            }
+        }
+        catch (ClassNotFoundException e)
+        {
+            // ignore - maybe log?
+        }
+
+        return null;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java
new file mode 100644
index 0000000..c9990ae
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java
@@ -0,0 +1,122 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class IvAlgorithmParameters
+    extends BaseAlgorithmParameters
+{
+    private byte[] iv;
+
+    protected byte[] engineGetEncoded()
+        throws IOException
+    {
+        return engineGetEncoded("ASN.1");
+    }
+
+    protected byte[] engineGetEncoded(
+        String format)
+        throws IOException
+    {
+        if (isASN1FormatString(format))
+        {
+            return new DEROctetString(engineGetEncoded("RAW")).getEncoded();
+        }
+
+        if (format.equals("RAW"))
+        {
+            return Arrays.clone(iv);
+        }
+
+        return null;
+    }
+
+    protected AlgorithmParameterSpec localEngineGetParameterSpec(
+        Class paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (paramSpec == IvParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
+        {
+            return new IvParameterSpec(iv);
+        }
+
+        throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object.");
+    }
+
+    protected void engineInit(
+        AlgorithmParameterSpec paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (!(paramSpec instanceof IvParameterSpec))
+        {
+            throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object");
+        }
+
+        this.iv = ((IvParameterSpec)paramSpec).getIV();
+    }
+
+    protected void engineInit(
+        byte[] params)
+        throws IOException
+    {
+        //
+        // check that we don't have a DER encoded octet string
+        //
+        if ((params.length % 8) != 0
+            && params[0] == 0x04 && params[1] == params.length - 2)
+        {
+            ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(params);
+
+            params = oct.getOctets();
+        }
+
+        this.iv = Arrays.clone(params);
+    }
+
+    protected void engineInit(
+        byte[] params,
+        String format)
+        throws IOException
+    {
+        if (isASN1FormatString(format))
+        {
+            try
+            {
+                ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(params);
+
+                engineInit(oct.getOctets());
+            }
+            catch (Exception e)
+            {
+                throw new IOException("Exception decoding: " + e);
+            }
+
+            return;
+        }
+
+        if (format.equals("RAW"))
+        {
+            engineInit(params);
+            return;
+        }
+
+        throw new IOException("Unknown parameters format in IV parameters object");
+    }
+
+    protected String engineToString()
+    {
+        return "IV Parameters";
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
new file mode 100644
index 0000000..d631b65
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
@@ -0,0 +1,541 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+// BEGIN Android-added: Needed for compatibility helper
+import java.lang.reflect.Method;
+// END Android-added: Needed for compatibility helper
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.SecretKey;
+// BEGIN Android-added: Allow IVs specified in parameters.
+import javax.crypto.spec.IvParameterSpec;
+// END Android-added: Allow IVs specified in parameters.
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+import com.android.internal.org.bouncycastle.crypto.PBEParametersGenerator;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.crypto.digests.GOST3411Digest;
+// import org.bouncycastle.crypto.digests.MD2Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// import org.bouncycastle.crypto.digests.TigerDigest;
+import com.android.internal.org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import com.android.internal.org.bouncycastle.crypto.params.DESParameters;
+import com.android.internal.org.bouncycastle.crypto.params.KeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.ParametersWithIV;
+// BEGIN Android-changed: Use Android digests
+// import org.bouncycastle.crypto.util.DigestFactory;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END Android-changed: Use Android digests
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface PBE
+{
+    //
+    // PBE Based encryption constants - by default we do PKCS12 with SHA-1
+    //
+    static final int        MD5          = 0;
+    static final int        SHA1         = 1;
+    // Android-removed: Unsupported algorithms
+    // static final int        RIPEMD160    = 2;
+    // static final int        TIGER        = 3;
+    static final int        SHA256       = 4;
+    // Android-removed: Unsupported algorithms
+    // static final int        MD2          = 5;
+    // static final int        GOST3411     = 6;
+    static final int        SHA224       = 7;
+    static final int        SHA384       = 8;
+    static final int        SHA512       = 9;
+    static final int        SHA3_224     = 10;
+    static final int        SHA3_256     = 11;
+    static final int        SHA3_384     = 12;
+    static final int        SHA3_512     = 13;
+
+    static final int        PKCS5S1      = 0;
+    static final int        PKCS5S2      = 1;
+    static final int        PKCS12       = 2;
+    static final int        OPENSSL      = 3;
+    static final int        PKCS5S1_UTF8 = 4;
+    static final int        PKCS5S2_UTF8 = 5;
+
+    /**
+     * uses the appropriate mixer to generate the key and IV if necessary.
+     */
+    static class Util
+    {
+        static private PBEParametersGenerator makePBEGenerator(
+            int                     type,
+            int                     hash)
+        {
+            PBEParametersGenerator  generator;
+    
+            if (type == PKCS5S1 || type == PKCS5S1_UTF8)
+            {
+                switch (hash)
+                {
+                // Android-removed: Unsupported algorithms
+                // case MD2:
+                //     generator = new PKCS5S1ParametersGenerator(new MD2Digest());
+                //     break;
+                case MD5:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS5S1ParametersGenerator(DigestFactory.createMD5());
+                    generator = new PKCS5S1ParametersGenerator(AndroidDigestFactory.getMD5());
+                    break;
+                case SHA1:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS5S1ParametersGenerator(DigestFactory.createSHA1());
+                    generator = new PKCS5S1ParametersGenerator(AndroidDigestFactory.getSHA1());
+                    break;
+                default:
+                    throw new IllegalStateException("PKCS5 scheme 1 only supports MD2, MD5 and SHA1.");
+                }
+            }
+            else if (type == PKCS5S2 || type == PKCS5S2_UTF8)
+            {
+                switch (hash)
+                {
+                // Android-removed: Unsupported algorithms
+                // case MD2:
+                //     generator = new PKCS5S2ParametersGenerator(new MD2Digest());
+                //     break;
+                case MD5:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS5S2ParametersGenerator(DigestFactory.createMD5());
+                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getMD5());
+                    break;
+                case SHA1:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA1());
+                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA1());
+                    break;
+                // BEGIN Android-removed: Unsupported algorithms
+                /*
+                case RIPEMD160:
+                    generator = new PKCS5S2ParametersGenerator(new RIPEMD160Digest());
+                    break;
+                case TIGER:
+                    generator = new PKCS5S2ParametersGenerator(new TigerDigest());
+                    break;
+                */
+                // END Android-removed: Unsupported algorithms
+                case SHA256:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA256());
+                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA256());
+                    break;
+                // Android-removed: Unsupported algorithms
+                // case GOST3411:
+                //     generator = new PKCS5S2ParametersGenerator(new GOST3411Digest());
+                //     break;
+                case SHA224:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA224());
+                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA224());
+                    break;
+                case SHA384:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA384());
+                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA384());
+                    break;
+                case SHA512:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA512());
+                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA512());
+                    break;
+                // BEGIN Android-removed: Unsupported algorithms
+                /*
+                case SHA3_224:
+                    generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA3_224());
+                    break;
+                case SHA3_256:
+                     generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA3_256());
+                     break;
+                case SHA3_384:
+                    generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA3_384());
+                    break;
+                case SHA3_512:
+                    generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA3_512());
+                    break;
+                */
+                // END Android-removed: Unsupported algorithms
+                default:
+                    throw new IllegalStateException("unknown digest scheme for PBE PKCS5S2 encryption.");
+                }
+            }
+            else if (type == PKCS12)
+            {
+                switch (hash)
+                {
+                // Android-removed: Unsupported algorithms
+                // case MD2:
+                //     generator = new PKCS12ParametersGenerator(new MD2Digest());
+                //     break;
+                case MD5:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS12ParametersGenerator(DigestFactory.createMD5());
+                    generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getMD5());
+                    break;
+                case SHA1:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS12ParametersGenerator(DigestFactory.createSHA1());
+                    generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA1());
+                    break;
+                // BEGIN Android-removed: Unsupported algorithms
+                /*
+                case RIPEMD160:
+                    generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
+                    break;
+                case TIGER:
+                    generator = new PKCS12ParametersGenerator(new TigerDigest());
+                    break;
+                */
+                // END Android-removed: Unsupported algorithms
+                case SHA256:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS12ParametersGenerator(DigestFactory.createSHA256());
+                    generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA256());
+                    break;
+                // Android-removed: Unsupported algorithms
+                // case GOST3411:
+                //     generator = new PKCS12ParametersGenerator(new GOST3411Digest());
+                //     break;
+                case SHA224:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS12ParametersGenerator(DigestFactory.createSHA224());
+                    generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA224());
+                    break;
+                case SHA384:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS12ParametersGenerator(DigestFactory.createSHA384());
+                    generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA384());
+                    break;
+                case SHA512:
+                    // Android-changed: Use Android digests
+                    // generator = new PKCS12ParametersGenerator(DigestFactory.createSHA512());
+                    generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA512());
+                    break;
+                default:
+                    throw new IllegalStateException("unknown digest scheme for PBE encryption.");
+                }
+            }
+            else
+            {
+                generator = new OpenSSLPBEParametersGenerator();
+            }
+    
+            return generator;
+        }
+
+        /**
+         * construct a key and iv (if necessary) suitable for use with a
+         * Cipher.
+         */
+        public static CipherParameters makePBEParameters(
+            byte[] pbeKey,
+            int scheme,
+            int digest,
+            int keySize,
+            int ivSize,
+            AlgorithmParameterSpec spec,
+            String targetAlgorithm)
+            throws InvalidAlgorithmParameterException
+        {
+            if ((spec == null) || !(spec instanceof PBEParameterSpec))
+            {
+                throw new InvalidAlgorithmParameterException("Need a PBEParameter spec with a PBE key.");
+            }
+
+            PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
+            PBEParametersGenerator  generator = makePBEGenerator(scheme, digest);
+            byte[]                  key = pbeKey;
+            CipherParameters        param;
+
+//            if (pbeKey.shouldTryWrongPKCS12())
+//            {
+//                key = new byte[2];
+//            }
+
+            generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
+
+            if (ivSize != 0)
+            {
+                param = generator.generateDerivedParameters(keySize, ivSize);
+                // BEGIN Android-added: Allow IVs specified in parameters.
+                // PKCS5S2 doesn't specify that the IV must be generated from the password. If the
+                // IV is passed as a parameter, use it.
+                AlgorithmParameterSpec parameterSpecFromPBEParameterSpec =
+                        getParameterSpecFromPBEParameterSpec(pbeParam);
+                if ((scheme == PKCS5S2 || scheme == PKCS5S2_UTF8)
+                        && parameterSpecFromPBEParameterSpec instanceof IvParameterSpec) {
+                    ParametersWithIV parametersWithIV = (ParametersWithIV) param;
+                    IvParameterSpec ivParameterSpec =
+                            (IvParameterSpec) parameterSpecFromPBEParameterSpec;
+                    param = new ParametersWithIV(
+                            (KeyParameter) parametersWithIV.getParameters(),
+                            ivParameterSpec.getIV());
+                }
+                // END Android-added: Allow IVs specified in parameters.
+            }
+            else
+            {
+                param = generator.generateDerivedParameters(keySize);
+            }
+
+            if (targetAlgorithm.startsWith("DES"))
+            {
+                if (param instanceof ParametersWithIV)
+                {
+                    KeyParameter    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+
+                    DESParameters.setOddParity(kParam.getKey());
+                }
+                else
+                {
+                    KeyParameter    kParam = (KeyParameter)param;
+
+                    DESParameters.setOddParity(kParam.getKey());
+                }
+            }
+
+            return param;
+        }
+
+        /**
+         * construct a key and iv (if necessary) suitable for use with a 
+         * Cipher.
+         */
+        public static CipherParameters makePBEParameters(
+            BCPBEKey pbeKey,
+            AlgorithmParameterSpec spec,
+            String targetAlgorithm)
+        {
+            if ((spec == null) || !(spec instanceof PBEParameterSpec))
+            {
+                throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+            }
+    
+            PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
+            PBEParametersGenerator  generator = makePBEGenerator(pbeKey.getType(), pbeKey.getDigest());
+            byte[]                  key = pbeKey.getEncoded();
+            CipherParameters        param;
+    
+            if (pbeKey.shouldTryWrongPKCS12())
+            {
+                key = new byte[2];
+            }
+            
+            generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
+
+            if (pbeKey.getIvSize() != 0)
+            {
+                param = generator.generateDerivedParameters(pbeKey.getKeySize(), pbeKey.getIvSize());
+                // BEGIN Android-added: Allow IVs specified in parameters.
+                // PKCS5S2 doesn't specify that the IV must be generated from the password. If the
+                // IV is passed as a parameter, use it.
+                AlgorithmParameterSpec parameterSpecFromPBEParameterSpec =
+                        getParameterSpecFromPBEParameterSpec(pbeParam);
+                if ((pbeKey.getType() == PKCS5S2 || pbeKey.getType() == PKCS5S2_UTF8)
+                        && parameterSpecFromPBEParameterSpec instanceof IvParameterSpec) {
+                    ParametersWithIV parametersWithIV = (ParametersWithIV) param;
+                    IvParameterSpec ivParameterSpec =
+                            (IvParameterSpec) parameterSpecFromPBEParameterSpec;
+                    param = new ParametersWithIV(
+                            (KeyParameter) parametersWithIV.getParameters(),
+                            ivParameterSpec.getIV());
+                }
+                // END Android-added: Allow IVs specified in parameters.
+            }
+            else
+            {
+                param = generator.generateDerivedParameters(pbeKey.getKeySize());
+            }
+
+            if (targetAlgorithm.startsWith("DES"))
+            {
+                if (param instanceof ParametersWithIV)
+                {
+                    KeyParameter    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+
+                    DESParameters.setOddParity(kParam.getKey());
+                }
+                else
+                {
+                    KeyParameter    kParam = (KeyParameter)param;
+
+                    DESParameters.setOddParity(kParam.getKey());
+                }
+            }
+
+            return param;
+        }
+
+        /**
+         * generate a PBE based key suitable for a MAC algorithm, the
+         * key size is chosen according the MAC size, or the hashing algorithm,
+         * whichever is greater.
+         */
+        public static CipherParameters makePBEMacParameters(
+            BCPBEKey pbeKey,
+            AlgorithmParameterSpec spec)
+        {
+            if ((spec == null) || !(spec instanceof PBEParameterSpec))
+            {
+                throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+            }
+    
+            PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
+            PBEParametersGenerator  generator = makePBEGenerator(pbeKey.getType(), pbeKey.getDigest());
+            byte[]                  key = pbeKey.getEncoded();
+            CipherParameters        param;
+            
+            generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
+
+            param = generator.generateDerivedMacParameters(pbeKey.getKeySize());
+
+            return param;
+        }
+
+        /**
+         * generate a PBE based key suitable for a MAC algorithm, the
+         * key size is chosen according the MAC size, or the hashing algorithm,
+         * whichever is greater.
+         */
+        public static CipherParameters makePBEMacParameters(
+            PBEKeySpec keySpec,
+            int type,
+            int hash,
+            int keySize)
+        {
+            PBEParametersGenerator  generator = makePBEGenerator(type, hash);
+            byte[]                  key;
+            CipherParameters        param;
+
+            key = convertPassword(type, keySpec);
+
+            generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
+
+            param = generator.generateDerivedMacParameters(keySize);
+
+            for (int i = 0; i != key.length; i++)
+            {
+                key[i] = 0;
+            }
+
+            return param;
+        }
+
+        /**
+         * construct a key and iv (if necessary) suitable for use with a 
+         * Cipher.
+         */
+        public static CipherParameters makePBEParameters(
+            PBEKeySpec keySpec,
+            int type,
+            int hash,
+            int keySize,
+            int ivSize)
+        {    
+            PBEParametersGenerator  generator = makePBEGenerator(type, hash);
+            byte[]                  key;
+            CipherParameters        param;
+
+            key = convertPassword(type, keySpec);
+
+            generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
+    
+            if (ivSize != 0)
+            {
+                param = generator.generateDerivedParameters(keySize, ivSize);
+            }
+            else
+            {
+                param = generator.generateDerivedParameters(keySize);
+            }
+    
+            for (int i = 0; i != key.length; i++)
+            {
+                key[i] = 0;
+            }
+    
+            return param;
+        }
+
+        /**
+         * generate a PBE based key suitable for a MAC algorithm, the
+         * key size is chosen according the MAC size, or the hashing algorithm,
+         * whichever is greater.
+         */
+        public static CipherParameters makePBEMacParameters(
+            SecretKey key,
+            int type,
+            int hash,
+            int keySize,
+            PBEParameterSpec pbeSpec)
+        {
+            PBEParametersGenerator  generator = makePBEGenerator(type, hash);
+            CipherParameters        param;
+    
+            byte[] keyBytes = key.getEncoded();
+            
+            generator.init(key.getEncoded(), pbeSpec.getSalt(), pbeSpec.getIterationCount());
+
+            param = generator.generateDerivedMacParameters(keySize);
+
+            for (int i = 0; i != keyBytes.length; i++)
+            {
+                keyBytes[i] = 0;
+            }
+    
+            return param;
+        }
+
+        // BEGIN Android-added: Add helper for 1.8 compatibility.
+        /**
+         * Invokes the method {@link PBEParameterSpec#getParameterSpec()} via reflection.
+         *
+         * Needed as the method was introduced in Java 1.8 and Bouncycastle level is 1.5.
+         *
+         * @return the parameter spec, or null if the method is not available.
+         */
+        public static AlgorithmParameterSpec getParameterSpecFromPBEParameterSpec(
+                PBEParameterSpec pbeParameterSpec) {
+            try {
+                Method getParameterSpecMethod = PBE.class.getClassLoader()
+                        .loadClass("javax.crypto.spec.PBEParameterSpec")
+                        .getMethod("getParameterSpec");
+                return (AlgorithmParameterSpec) getParameterSpecMethod.invoke(pbeParameterSpec);
+            } catch (Exception e) {
+                return null;
+            }
+        }
+        // END Android-added: Add helper for 1.8 compatibility.
+
+
+        private static byte[] convertPassword(int type, PBEKeySpec keySpec)
+        {
+            byte[] key;
+
+            if (type == PKCS12)
+            {
+                key = PBEParametersGenerator.PKCS12PasswordToBytes(keySpec.getPassword());
+            }
+            else if (type == PKCS5S2_UTF8 || type == PKCS5S1_UTF8)
+            {
+                key = PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(keySpec.getPassword());
+            }
+            else
+            {
+                key = PBEParametersGenerator.PKCS5PasswordToBytes(keySpec.getPassword());
+            }
+            return key;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java
new file mode 100644
index 0000000..3c6d521
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java
@@ -0,0 +1,72 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.PBEKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.crypto.CipherParameters;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PBESecretKeyFactory
+    extends BaseSecretKeyFactory
+    implements PBE
+{
+    private boolean forCipher;
+    private int scheme;
+    private int digest;
+    private int keySize;
+    private int ivSize;
+
+    public PBESecretKeyFactory(
+        String algorithm,
+        ASN1ObjectIdentifier oid,
+        boolean forCipher,
+        int scheme,
+        int digest,
+        int keySize,
+        int ivSize)
+    {
+        super(algorithm, oid);
+
+        this.forCipher = forCipher;
+        this.scheme = scheme;
+        this.digest = digest;
+        this.keySize = keySize;
+        this.ivSize = ivSize;
+    }
+
+    protected SecretKey engineGenerateSecret(
+        KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (keySpec instanceof PBEKeySpec)
+        {
+            PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+            CipherParameters param;
+
+            if (pbeSpec.getSalt() == null)
+            {
+                return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+            }
+
+            if (forCipher)
+            {
+                param = PBE.Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+            }
+            else
+            {
+                param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+            }
+
+            return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+        }
+
+        throw new InvalidKeySpecException("Invalid KeySpec");
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/AlgorithmProvider.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/AlgorithmProvider.java
new file mode 100644
index 0000000..2d3f152
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/AlgorithmProvider.java
@@ -0,0 +1,12 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.util;
+
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class AlgorithmProvider
+{
+    public abstract void configure(ConfigurableProvider provider);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java
new file mode 100644
index 0000000..f602b3d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java
@@ -0,0 +1,62 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.util;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class AsymmetricAlgorithmProvider
+    extends AlgorithmProvider
+{
+    protected void addSignatureAlgorithm(
+        ConfigurableProvider provider,
+        String algorithm,
+        String className,
+        ASN1ObjectIdentifier oid)
+    {
+        provider.addAlgorithm("Signature." + algorithm, className);
+        provider.addAlgorithm("Alg.Alias.Signature." + oid, algorithm);
+        provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, algorithm);
+    }
+
+    protected void addSignatureAlgorithm(
+        ConfigurableProvider provider,
+        String digest,
+        String algorithm,
+        String className,
+        ASN1ObjectIdentifier oid)
+    {
+        String mainName = digest + "WITH" + algorithm;
+        String jdk11Variation1 = digest + "with" + algorithm;
+        String jdk11Variation2 = digest + "With" + algorithm;
+        String alias = digest + "/" + algorithm;
+
+        provider.addAlgorithm("Signature." + mainName, className);
+        provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation1, mainName);
+        provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation2, mainName);
+        provider.addAlgorithm("Alg.Alias.Signature." + alias, mainName);
+        provider.addAlgorithm("Alg.Alias.Signature." + oid, mainName);
+        provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, mainName);
+    }
+
+    protected void registerOid(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name, AsymmetricKeyInfoConverter keyFactory)
+    {
+        provider.addAlgorithm("Alg.Alias.KeyFactory." + oid, name);
+        provider.addAlgorithm("Alg.Alias.KeyPairGenerator." + oid, name);
+
+        provider.addKeyInfoConverter(oid, keyFactory);
+    }
+
+    protected void registerOidAlgorithmParameters(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name)
+    {
+        provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + oid, name);
+    }
+
+    protected void registerOidAlgorithmParameterGenerator(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name)
+    {
+        provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + oid, name);
+        provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + oid, name);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java
new file mode 100644
index 0000000..0d1a6dd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java
@@ -0,0 +1,21 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.util;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface AsymmetricKeyInfoConverter
+{
+    PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+        throws IOException;
+
+    PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+        throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/BadBlockException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/BadBlockException.java
new file mode 100644
index 0000000..f9c2bbf
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/BadBlockException.java
@@ -0,0 +1,25 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.util;
+
+import javax.crypto.BadPaddingException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BadBlockException
+    extends BadPaddingException
+{
+    private final Throwable cause;
+
+    public BadBlockException(String msg, Throwable cause)
+    {
+        super(msg);
+
+        this.cause = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/DigestFactory.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/DigestFactory.java
new file mode 100644
index 0000000..0a431a3
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/DigestFactory.java
@@ -0,0 +1,238 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.util;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+// BEGIN Android-added: Use Android digests
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END Android-added: Use Android digests
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DigestFactory
+{
+    private static Set md5 = new HashSet();
+    private static Set sha1 = new HashSet();
+    private static Set sha224 = new HashSet();
+    private static Set sha256 = new HashSet();
+    private static Set sha384 = new HashSet();
+    private static Set sha512 = new HashSet();
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    private static Set sha512_224 = new HashSet();
+    private static Set sha512_256 = new HashSet();
+    private static Set sha3_224 = new HashSet();
+    private static Set sha3_256 = new HashSet();
+    private static Set sha3_384 = new HashSet();
+    private static Set sha3_512 = new HashSet();
+    */
+    // END Android-removed: Unsupported algorithms
+
+    private static Map oids = new HashMap();
+    
+    static
+    {
+        md5.add("MD5");
+        md5.add(PKCSObjectIdentifiers.md5.getId());
+        
+        sha1.add("SHA1");
+        sha1.add("SHA-1");
+        sha1.add(OIWObjectIdentifiers.idSHA1.getId());
+        
+        sha224.add("SHA224");
+        sha224.add("SHA-224");
+        sha224.add(NISTObjectIdentifiers.id_sha224.getId());
+        
+        sha256.add("SHA256");
+        sha256.add("SHA-256");
+        sha256.add(NISTObjectIdentifiers.id_sha256.getId());
+        
+        sha384.add("SHA384");
+        sha384.add("SHA-384");
+        sha384.add(NISTObjectIdentifiers.id_sha384.getId());
+        
+        sha512.add("SHA512");
+        sha512.add("SHA-512");
+        sha512.add(NISTObjectIdentifiers.id_sha512.getId()); 
+
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        sha512_224.add("SHA512(224)");
+        sha512_224.add("SHA-512(224)");
+        sha512_224.add(NISTObjectIdentifiers.id_sha512_224.getId());
+
+        sha512_256.add("SHA512(256)");
+        sha512_256.add("SHA-512(256)");
+        sha512_256.add(NISTObjectIdentifiers.id_sha512_256.getId());
+
+        sha3_224.add("SHA3-224");
+        sha3_224.add(NISTObjectIdentifiers.id_sha3_224.getId());
+
+        sha3_256.add("SHA3-256");
+        sha3_256.add(NISTObjectIdentifiers.id_sha3_256.getId());
+
+        sha3_384.add("SHA3-384");
+        sha3_384.add(NISTObjectIdentifiers.id_sha3_384.getId());
+
+        sha3_512.add("SHA3-512");
+        sha3_512.add(NISTObjectIdentifiers.id_sha3_512.getId());
+        */
+        // END Android-removed: Unsupported algorithms
+
+
+        oids.put("MD5", PKCSObjectIdentifiers.md5);
+        oids.put(PKCSObjectIdentifiers.md5.getId(), PKCSObjectIdentifiers.md5);
+        
+        oids.put("SHA1", OIWObjectIdentifiers.idSHA1);
+        oids.put("SHA-1", OIWObjectIdentifiers.idSHA1);
+        oids.put(OIWObjectIdentifiers.idSHA1.getId(), OIWObjectIdentifiers.idSHA1);
+        
+        oids.put("SHA224", NISTObjectIdentifiers.id_sha224);
+        oids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+        oids.put(NISTObjectIdentifiers.id_sha224.getId(), NISTObjectIdentifiers.id_sha224);
+        
+        oids.put("SHA256", NISTObjectIdentifiers.id_sha256);
+        oids.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+        oids.put(NISTObjectIdentifiers.id_sha256.getId(), NISTObjectIdentifiers.id_sha256);
+        
+        oids.put("SHA384", NISTObjectIdentifiers.id_sha384);
+        oids.put("SHA-384", NISTObjectIdentifiers.id_sha384);
+        oids.put(NISTObjectIdentifiers.id_sha384.getId(), NISTObjectIdentifiers.id_sha384);
+        
+        oids.put("SHA512", NISTObjectIdentifiers.id_sha512);
+        oids.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+        oids.put(NISTObjectIdentifiers.id_sha512.getId(), NISTObjectIdentifiers.id_sha512);
+
+        oids.put("SHA512(224)", NISTObjectIdentifiers.id_sha512_224);
+        oids.put("SHA-512(224)", NISTObjectIdentifiers.id_sha512_224);
+        oids.put(NISTObjectIdentifiers.id_sha512_224.getId(), NISTObjectIdentifiers.id_sha512_224);
+
+        oids.put("SHA512(256)", NISTObjectIdentifiers.id_sha512_256);
+        oids.put("SHA-512(256)", NISTObjectIdentifiers.id_sha512_256);
+        oids.put(NISTObjectIdentifiers.id_sha512_256.getId(), NISTObjectIdentifiers.id_sha512_256);
+
+        oids.put("SHA3-224", NISTObjectIdentifiers.id_sha3_224);
+        oids.put(NISTObjectIdentifiers.id_sha3_224.getId(), NISTObjectIdentifiers.id_sha3_224);
+
+        oids.put("SHA3-256", NISTObjectIdentifiers.id_sha3_256);
+        oids.put(NISTObjectIdentifiers.id_sha3_256.getId(), NISTObjectIdentifiers.id_sha3_256);
+
+        oids.put("SHA3-384", NISTObjectIdentifiers.id_sha3_384);
+        oids.put(NISTObjectIdentifiers.id_sha3_384.getId(), NISTObjectIdentifiers.id_sha3_384);
+
+        oids.put("SHA3-512", NISTObjectIdentifiers.id_sha3_512);
+        oids.put(NISTObjectIdentifiers.id_sha3_512.getId(), NISTObjectIdentifiers.id_sha3_512);
+    }
+    
+    public static Digest getDigest(
+        String digestName) 
+    {
+        digestName = Strings.toUpperCase(digestName);
+        
+        if (sha1.contains(digestName))
+        {
+            // Android-changed: Use Android digests
+            // return org.bouncycastle.crypto.util.DigestFactory.createSHA1();
+            return AndroidDigestFactory.getSHA1();
+        }
+        if (md5.contains(digestName))
+        {
+            // Android-changed: Use Android digests
+            // return org.bouncycastle.crypto.util.DigestFactory.createMD5();
+            return AndroidDigestFactory.getMD5();
+        }
+        if (sha224.contains(digestName))
+        {
+            // Android-changed: Use Android digests
+            // return org.bouncycastle.crypto.util.DigestFactory.createSHA224();
+            return AndroidDigestFactory.getSHA224();
+        }
+        if (sha256.contains(digestName))
+        {
+            // Android-changed: Use Android digests
+            // return org.bouncycastle.crypto.util.DigestFactory.createSHA256();
+            return AndroidDigestFactory.getSHA256();
+        }
+        if (sha384.contains(digestName))
+        {
+            // Android-changed: Use Android digests
+            // return org.bouncycastle.crypto.util.DigestFactory.createSHA384();
+            return AndroidDigestFactory.getSHA384();
+        }
+        if (sha512.contains(digestName))
+        {
+            // Android-changed: Use Android digests
+            // return org.bouncycastle.crypto.util.DigestFactory.createSHA512();
+            return AndroidDigestFactory.getSHA512();
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        if (sha512_224.contains(digestName))
+        {
+            return org.bouncycastle.crypto.util.DigestFactory.createSHA512_224();
+        }
+        if (sha512_256.contains(digestName))
+        {
+            return org.bouncycastle.crypto.util.DigestFactory.createSHA512_256();
+        }
+
+        if (sha3_224.contains(digestName))
+        {
+            return org.bouncycastle.crypto.util.DigestFactory.createSHA3_224();
+        }
+        if (sha3_256.contains(digestName))
+        {
+            return org.bouncycastle.crypto.util.DigestFactory.createSHA3_256();
+        }
+        if (sha3_384.contains(digestName))
+        {
+            return org.bouncycastle.crypto.util.DigestFactory.createSHA3_384();
+        }
+        if (sha3_512.contains(digestName))
+        {
+            return org.bouncycastle.crypto.util.DigestFactory.createSHA3_512();
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+
+        return null;
+    }
+    
+    public static boolean isSameDigest(
+        String digest1,
+        String digest2)
+    {
+        return (sha1.contains(digest1) && sha1.contains(digest2))
+            || (sha224.contains(digest1) && sha224.contains(digest2))
+            || (sha256.contains(digest1) && sha256.contains(digest2))
+            || (sha384.contains(digest1) && sha384.contains(digest2))
+            || (sha512.contains(digest1) && sha512.contains(digest2))
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            || (sha512_224.contains(digest1) && sha512_224.contains(digest2))
+            || (sha512_256.contains(digest1) && sha512_256.contains(digest2))
+            || (sha3_224.contains(digest1) && sha3_224.contains(digest2))
+            || (sha3_256.contains(digest1) && sha3_256.contains(digest2))
+            || (sha3_384.contains(digest1) && sha3_384.contains(digest2))
+            || (sha3_512.contains(digest1) && sha3_512.contains(digest2))
+            */
+            // END Android-removed: Unsupported algorithms
+            || (md5.contains(digest1) && md5.contains(digest2));
+    }
+    
+    public static ASN1ObjectIdentifier getOID(
+        String digestName)
+    {
+        return (ASN1ObjectIdentifier)oids.get(digestName);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java
new file mode 100644
index 0000000..de70c7c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java
@@ -0,0 +1,44 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.provider.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.util.Integers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecretKeyUtil
+{
+    private static Map keySizes = new HashMap();
+
+    static
+    {
+        keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192));
+
+        keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128));
+        keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192));
+        keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256));
+
+        keySizes.put(NTTObjectIdentifiers.id_camellia128_cbc, Integers.valueOf(128));
+        keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192));
+        keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256));
+    }
+
+    public static int getKeySize(ASN1ObjectIdentifier oid)
+    {
+        Integer size = (Integer)keySizes.get(oid);
+
+        if (size != null)
+        {
+            return size.intValue();
+        }
+
+        return -1;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/AEADParameterSpec.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/AEADParameterSpec.java
new file mode 100644
index 0000000..e641e6b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/AEADParameterSpec.java
@@ -0,0 +1,75 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.spec;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * ParameterSpec for AEAD modes which allows associated data to be added via an algorithm parameter spec.In normal
+ * circumstances you would only want to use this if you had to work with the pre-JDK1.7 Cipher class as associated
+ * data is ignored for the purposes of returning a Cipher's parameters.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AEADParameterSpec
+    extends IvParameterSpec
+{
+    private final byte[] associatedData;
+    private final int macSizeInBits;
+
+    /**
+     * Base constructor.
+     *
+     * @param nonce nonce/iv to be used
+     * @param macSizeInBits macSize in bits
+     */
+    public AEADParameterSpec(byte[] nonce, int macSizeInBits)
+    {
+        this(nonce, macSizeInBits, null);
+    }
+
+    /**
+     * Base constructor with prepended associated data.
+     *
+     * @param nonce nonce/iv to be used
+     * @param macSizeInBits macSize in bits
+     * @param associatedData associated data to be prepended to the cipher stream.
+     */
+    public AEADParameterSpec(byte[] nonce, int macSizeInBits, byte[] associatedData)
+    {
+        super(nonce);
+
+        this.macSizeInBits = macSizeInBits;
+        this.associatedData = Arrays.clone(associatedData);
+    }
+
+    /**
+     * Return the size of the MAC associated with this parameter spec.
+     *
+     * @return the MAC size in bits.
+     */
+    public int getMacSizeInBits()
+    {
+        return macSizeInBits;
+    }
+
+    /**
+     * Return the associated data associated with this parameter spec.
+     *
+     * @return the associated data, null if there isn't any.
+     */
+    public byte[] getAssociatedData()
+    {
+        return Arrays.clone(associatedData);
+    }
+
+    /**
+     * Return the nonce (same as IV) associated with this parameter spec.
+     *
+     * @return the nonce/IV.
+     */
+    public byte[] getNonce()
+    {
+        return getIV();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/DHDomainParameterSpec.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/DHDomainParameterSpec.java
new file mode 100644
index 0000000..e59e506
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/DHDomainParameterSpec.java
@@ -0,0 +1,131 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.spec;
+
+import java.math.BigInteger;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHValidationParameters;
+
+/**
+ * Extension class for DHParameterSpec that wraps a DHDomainParameters object and provides the q domain parameter.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHDomainParameterSpec
+    extends DHParameterSpec
+{
+    private final BigInteger q;
+    private final BigInteger j;
+    private final int m;
+
+    private DHValidationParameters validationParameters;
+
+    /**
+     * Base constructor - use the values in an existing set of domain parameters.
+     *
+     * @param domainParameters the Diffie-Hellman domain parameters to wrap.
+     */
+    public DHDomainParameterSpec(DHParameters domainParameters)
+    {
+        this(domainParameters.getP(), domainParameters.getQ(), domainParameters.getG(), domainParameters.getJ(), domainParameters.getM(), domainParameters.getL());
+        this.validationParameters = domainParameters.getValidationParameters();
+    }
+
+    /**
+     * Minimal constructor for parameters able to be used to verify a public key, or use with MQV.
+     *
+     * @param p the prime p defining the Galois field.
+     * @param g the generator of the multiplicative subgroup of order g.
+     * @param q specifies the prime factor of p - 1
+     */
+    public DHDomainParameterSpec(BigInteger p, BigInteger q, BigInteger g)
+    {
+        this(p, q, g, null, 0);
+    }
+
+    /**
+     * Minimal constructor for parameters able to be used to verify a public key, or use with MQV, and a private value length.
+     *
+     * @param p the prime p defining the Galois field.
+     * @param g the generator of the multiplicative subgroup of order g.
+     * @param q specifies the prime factor of p - 1
+     * @param l the maximum bit length for the private value.
+     */
+    public DHDomainParameterSpec(BigInteger p, BigInteger q, BigInteger g, int l)
+    {
+        this(p, q, g, null, l);
+    }
+
+    /**
+     * X9.42 parameters with private value length.
+     *
+     * @param p the prime p defining the Galois field.
+     * @param g the generator of the multiplicative subgroup of order g.
+     * @param q specifies the prime factor of p - 1
+     * @param j optionally specifies the value that satisfies the equation p = jq+1
+     * @param l the maximum bit length for the private value.
+     */
+    public DHDomainParameterSpec(BigInteger p, BigInteger q, BigInteger g, BigInteger j, int l)
+    {
+        this(p, q, g, j, 0, l);
+    }
+
+    /**
+     * Base constructor - the full domain parameter set.
+     *
+     * @param p the prime p defining the Galois field.
+     * @param g the generator of the multiplicative subgroup of order g.
+     * @param q specifies the prime factor of p - 1
+     * @param j optionally specifies the value that satisfies the equation p = jq+1
+     * @param m the minimum bit length for the private value.
+     * @param l the maximum bit length for the private value.
+     */
+    public DHDomainParameterSpec(BigInteger p, BigInteger q, BigInteger g, BigInteger j, int m, int l)
+    {
+        super(p, g, l);
+        this.q = q;
+        this.j = j;
+        this.m = m;
+    }
+
+    /**
+     * Return the Q value for the domain parameter set.
+     *
+     * @return the value Q.
+     */
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    /**
+     * Return the J value for the domain parameter set if available.
+     *
+     * @return the value J, null otherwise.
+     */
+    public BigInteger getJ()
+    {
+        return j;
+    }
+
+    /**
+     * Return the minimum bitlength for a private value to be generated from these parameters, 0 if not set.
+     *
+     * @return minimum bitlength for private value.
+     */
+    public int getM()
+    {
+        return m;
+    }
+
+    /**
+     * Return the DHDomainParameters object we represent.
+     *
+     * @return the internal DHDomainParameters.
+     */
+    public DHParameters getDomainParameters()
+    {
+        return new DHParameters(getP(), getG(), q, m, getL(), j, validationParameters);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java
new file mode 100644
index 0000000..f6128f3
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java
@@ -0,0 +1,56 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.spec;
+
+import javax.crypto.spec.PBEKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * Extension of PBEKeySpec which takes into account the PRF algorithm setting available in PKCS#5 PBKDF2.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PBKDF2KeySpec
+    extends PBEKeySpec
+{
+    private static final AlgorithmIdentifier defaultPRF = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA1, DERNull.INSTANCE);
+
+    private AlgorithmIdentifier prf;
+
+    /**
+     * Base constructor.
+     *
+     * @param password password to use as the seed of the PBE key generator.
+     * @param salt salt to use in the generator,
+     * @param iterationCount iteration count to use in the generator.
+     * @param keySize size of the key to be generated (in bits).
+     * @param prf identifier and parameters for the PRF algorithm to use.
+     */
+    public PBKDF2KeySpec(char[] password, byte[] salt, int iterationCount, int keySize, AlgorithmIdentifier prf)
+    {
+        super(password, salt, iterationCount, keySize);
+
+        this.prf = prf;
+    }
+
+    /**
+     * Return true if this spec is for the default PRF (HmacSHA1), false otherwise.
+     *
+     * @return true if this spec uses the default PRF, false otherwise.
+     */
+    public boolean isDefaultPrf()
+    {
+        return defaultPRF.equals(prf);
+    }
+
+    /**
+     * Return an AlgorithmIdentifier representing the PRF.
+     *
+     * @return the PRF's AlgorithmIdentifier.
+     */
+    public AlgorithmIdentifier getPrf()
+    {
+        return prf;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpec.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpec.java
new file mode 100644
index 0000000..1e37d43
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpec.java
@@ -0,0 +1,25 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class UserKeyingMaterialSpec
+    implements AlgorithmParameterSpec
+{
+    private final byte[] userKeyingMaterial;
+
+    public UserKeyingMaterialSpec(byte[] userKeyingMaterial)
+    {
+        this.userKeyingMaterial = Arrays.clone(userKeyingMaterial);
+    }
+
+    public byte[] getUserKeyingMaterial()
+    {
+        return Arrays.clone(userKeyingMaterial);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/AlgorithmParametersUtils.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/AlgorithmParametersUtils.java
new file mode 100644
index 0000000..343e51b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/AlgorithmParametersUtils.java
@@ -0,0 +1,67 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.util;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+
+/**
+ * General JCA/JCE utility methods.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AlgorithmParametersUtils
+{
+
+
+    private AlgorithmParametersUtils()
+    {
+
+    }
+
+    /**
+     * Extract an ASN.1 encodable from an AlgorithmParameters object.
+     *
+     * @param params the object to get the encoding used to create the return value.
+     * @return an ASN.1 object representing the primitives making up the params parameter.
+     * @throws IOException if an encoding cannot be extracted.
+     */
+    public static ASN1Encodable extractParameters(AlgorithmParameters params)
+        throws IOException
+    {
+        // we try ASN.1 explicitly first just in case and then role back to the default.
+        ASN1Encodable asn1Params;
+        try
+        {
+            asn1Params = ASN1Primitive.fromByteArray(params.getEncoded("ASN.1"));
+        }
+        catch (Exception ex)
+        {
+            asn1Params = ASN1Primitive.fromByteArray(params.getEncoded());
+        }
+
+        return asn1Params;
+    }
+
+    /**
+     * Load an AlgorithmParameters object with the passed in ASN.1 encodable - if possible.
+     *
+     * @param params the AlgorithmParameters object to be initialised.
+     * @param sParams the ASN.1 encodable to initialise params with.
+     * @throws IOException if the parameters cannot be initialised.
+     */
+    public static void loadParameters(AlgorithmParameters params, ASN1Encodable sParams)
+        throws IOException
+    {
+        // we try ASN.1 explicitly first just in case and then role back to the default.
+        try
+        {
+            params.init(sParams.toASN1Primitive().getEncoded(), "ASN.1");
+        }
+        catch (Exception ex)
+        {
+            params.init(sParams.toASN1Primitive().getEncoded());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/BCJcaJceHelper.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
new file mode 100644
index 0000000..897f834
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
@@ -0,0 +1,40 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.util;
+
+import java.security.Provider;
+import java.security.Security;
+
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+/**
+ * A JCA/JCE helper that refers to the BC provider for all it's needs.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class BCJcaJceHelper
+    extends ProviderJcaJceHelper
+{
+    private static volatile Provider bcProvider;
+
+    private static synchronized Provider getBouncyCastleProvider()
+    {
+        if (Security.getProvider("BC") != null)
+        {
+            return Security.getProvider("BC");
+        }
+        else if (bcProvider != null)
+        {
+            return bcProvider;
+        }
+        else
+        {
+            bcProvider = new BouncyCastleProvider();
+
+            return bcProvider;
+        }
+    }
+
+    public BCJcaJceHelper()
+    {
+        super(getBouncyCastleProvider());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java
new file mode 100644
index 0000000..550b082
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java
@@ -0,0 +1,108 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.util;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+/**
+ * {@link JcaJceHelper} that obtains all algorithms using the default JCA/JCE mechanism (i.e.
+ * without specifying a provider).
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DefaultJcaJceHelper
+    implements JcaJceHelper
+{
+    public Cipher createCipher(
+        String algorithm)
+        throws NoSuchAlgorithmException, NoSuchPaddingException
+    {
+        return Cipher.getInstance(algorithm);
+    }
+
+    public Mac createMac(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return Mac.getInstance(algorithm);
+    }
+
+    public KeyAgreement createKeyAgreement(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyAgreement.getInstance(algorithm);
+    }
+
+    public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return AlgorithmParameterGenerator.getInstance(algorithm);
+    }
+
+    public AlgorithmParameters createAlgorithmParameters(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return AlgorithmParameters.getInstance(algorithm);
+    }
+
+    public KeyGenerator createKeyGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyGenerator.getInstance(algorithm);
+    }
+
+    public KeyFactory createKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyFactory.getInstance(algorithm);
+    }
+
+    public SecretKeyFactory createSecretKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return SecretKeyFactory.getInstance(algorithm);
+    }
+
+    public KeyPairGenerator createKeyPairGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyPairGenerator.getInstance(algorithm);
+    }
+
+    public MessageDigest createDigest(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return MessageDigest.getInstance(algorithm);
+    }
+
+    public Signature createSignature(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return Signature.getInstance(algorithm);
+    }
+
+    public CertificateFactory createCertificateFactory(String algorithm)
+        throws CertificateException
+    {
+        return CertificateFactory.getInstance(algorithm);
+    }
+
+    public SecureRandom createSecureRandom(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return SecureRandom.getInstance(algorithm);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/JcaJceHelper.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/JcaJceHelper.java
new file mode 100644
index 0000000..6c8f0e4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/JcaJceHelper.java
@@ -0,0 +1,68 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.util;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+/**
+ * Factory interface for instantiating JCA/JCE primitives.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface JcaJceHelper
+{
+    Cipher createCipher(
+        String algorithm)
+        throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException;
+
+    Mac createMac(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    KeyAgreement createKeyAgreement(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    AlgorithmParameters createAlgorithmParameters(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    KeyGenerator createKeyGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    KeyFactory createKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    SecretKeyFactory createSecretKeyFactory(String algorithm)
+           throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    KeyPairGenerator createKeyPairGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    MessageDigest createDigest(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    Signature createSignature(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+
+    CertificateFactory createCertificateFactory(String algorithm)
+        throws NoSuchProviderException, CertificateException;
+
+    SecureRandom createSecureRandom(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/JcaJceUtils.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/JcaJceUtils.java
new file mode 100644
index 0000000..8a60ca9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/JcaJceUtils.java
@@ -0,0 +1,135 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.util;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+
+/**
+ * General JCA/JCE utility methods.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class JcaJceUtils
+{
+    private JcaJceUtils()
+    {
+
+    }
+
+    /**
+     * Extract an ASN.1 encodable from an AlgorithmParameters object.
+     *
+     * @param params the object to get the encoding used to create the return value.
+     * @return an ASN.1 object representing the primitives making up the params parameter.
+     * @throws IOException if an encoding cannot be extracted.
+     * @deprecated use AlgorithmParametersUtils.extractParameters(AlgorithmParameters params)
+     */
+    public static ASN1Encodable extractParameters(AlgorithmParameters params)
+        throws IOException
+    {
+        // we try ASN.1 explicitly first just in case and then role back to the default.
+        ASN1Encodable asn1Params;
+        try
+        {
+            asn1Params = ASN1Primitive.fromByteArray(params.getEncoded("ASN.1"));
+        }
+        catch (Exception ex)
+        {
+            asn1Params = ASN1Primitive.fromByteArray(params.getEncoded());
+        }
+
+        return asn1Params;
+    }
+
+    /**
+     * Load an AlgorithmParameters object with the passed in ASN.1 encodable - if possible.
+     *
+     * @param params the AlgorithmParameters object to be initialised.
+     * @param sParams the ASN.1 encodable to initialise params with.
+     * @throws IOException if the parameters cannot be initialised.
+     * @deprecated use AlgorithmParametersUtils.loadParameters(AlgorithmParameters params, ASN1Encodable sParams)
+     */
+    public static void loadParameters(AlgorithmParameters params, ASN1Encodable sParams)
+        throws IOException
+    {
+        // we try ASN.1 explicitly first just in case and then role back to the default.
+        try
+        {
+            params.init(sParams.toASN1Primitive().getEncoded(), "ASN.1");
+        }
+        catch (Exception ex)
+        {
+            params.init(sParams.toASN1Primitive().getEncoded());
+        }
+    }
+
+    /**
+     * Attempt to find a standard JCA name for the digest represented by the past in OID.
+     *
+     * @param digestAlgOID the OID of the digest algorithm of interest.
+     * @return a string representing the standard name - the OID as a string if none available.
+     * @deprecated use MessageDigestUtils,getDigestName()
+     */
+    public static String getDigestAlgName(
+        ASN1ObjectIdentifier digestAlgOID)
+    {
+        if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+        {
+            return "MD5";
+        }
+        else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+        {
+            return "SHA1";
+        }
+        else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+        {
+            return "SHA224";
+        }
+        else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+        {
+            return "SHA256";
+        }
+        else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+        {
+            return "SHA384";
+        }
+        else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+        {
+            return "SHA512";
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+        {
+            return "RIPEMD128";
+        }
+        else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+        {
+            return "RIPEMD160";
+        }
+        else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+        {
+            return "RIPEMD256";
+        }
+        else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+        {
+            return "GOST3411";
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+        else
+        {
+            return digestAlgOID.getId();
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/MessageDigestUtils.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/MessageDigestUtils.java
new file mode 100644
index 0000000..a8fe3e7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/MessageDigestUtils.java
@@ -0,0 +1,73 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
+// import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
+// import org.bouncycastle.asn1.iso.ISOIECObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class MessageDigestUtils
+{
+    private static Map<ASN1ObjectIdentifier, String> digestOidMap = new HashMap<ASN1ObjectIdentifier, String>();
+
+    static
+    {
+        // BEGIN Android-removed: Unsupported algorithms
+        // digestOidMap.put(PKCSObjectIdentifiers.md2, "MD2");
+        // digestOidMap.put(PKCSObjectIdentifiers.md4, "MD4");
+        // END Android-removed: Unsupported algorithms
+        digestOidMap.put(PKCSObjectIdentifiers.md5, "MD5");
+        digestOidMap.put(OIWObjectIdentifiers.idSHA1, "SHA-1");
+        digestOidMap.put(NISTObjectIdentifiers.id_sha224, "SHA-224");
+        digestOidMap.put(NISTObjectIdentifiers.id_sha256, "SHA-256");
+        digestOidMap.put(NISTObjectIdentifiers.id_sha384, "SHA-384");
+        digestOidMap.put(NISTObjectIdentifiers.id_sha512, "SHA-512");
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        digestOidMap.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD-128");
+        digestOidMap.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD-160");
+        digestOidMap.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD-128");
+        digestOidMap.put(ISOIECObjectIdentifiers.ripemd128, "RIPEMD-128");
+        digestOidMap.put(ISOIECObjectIdentifiers.ripemd160, "RIPEMD-160");
+        digestOidMap.put(CryptoProObjectIdentifiers.gostR3411, "GOST3411");
+        digestOidMap.put(GNUObjectIdentifiers.Tiger_192, "Tiger");
+        digestOidMap.put(ISOIECObjectIdentifiers.whirlpool, "Whirlpool");
+        digestOidMap.put(NISTObjectIdentifiers.id_sha3_224, "SHA3-224");
+        digestOidMap.put(NISTObjectIdentifiers.id_sha3_256, "SHA3-256");
+        digestOidMap.put(NISTObjectIdentifiers.id_sha3_384, "SHA3-384");
+        digestOidMap.put(NISTObjectIdentifiers.id_sha3_512, "SHA3-512");
+        digestOidMap.put(GMObjectIdentifiers.sm3, "SM3");
+        */
+        // END Android-removed: Unsupported algorithms
+    }
+
+    /**
+     * Attempt to find a standard JCA name for the digest represented by the passed in OID.
+     *
+     * @param digestAlgOID the OID of the digest algorithm of interest.
+     * @return a string representing the standard name - the OID as a string if none available.
+     */
+    public static String getDigestName(ASN1ObjectIdentifier digestAlgOID)
+    {
+        String name = (String)digestOidMap.get(digestAlgOID);  // for pre 1.5 JDK
+        if (name != null)
+        {
+            return name;
+        }
+
+        return digestAlgOID.getId();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java
new file mode 100644
index 0000000..dfd0659
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java
@@ -0,0 +1,115 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.util;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+/**
+ * {@link JcaJceHelper} that obtains all algorithms using a specific named provider.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class NamedJcaJceHelper
+    implements JcaJceHelper
+{
+    protected final String providerName;
+
+    public NamedJcaJceHelper(String providerName)
+    {
+        this.providerName = providerName;
+    }
+
+    public Cipher createCipher(
+        String algorithm)
+        throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException
+    {
+        return Cipher.getInstance(algorithm, providerName);
+    }
+
+    public Mac createMac(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return Mac.getInstance(algorithm, providerName);
+    }
+
+    public KeyAgreement createKeyAgreement(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return KeyAgreement.getInstance(algorithm, providerName);
+    }
+
+    public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return AlgorithmParameterGenerator.getInstance(algorithm, providerName);
+    }
+
+    public AlgorithmParameters createAlgorithmParameters(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return AlgorithmParameters.getInstance(algorithm, providerName);
+    }
+
+    public KeyGenerator createKeyGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return KeyGenerator.getInstance(algorithm, providerName);
+    }
+
+    public KeyFactory createKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return KeyFactory.getInstance(algorithm, providerName);
+    }
+
+    public SecretKeyFactory createSecretKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return SecretKeyFactory.getInstance(algorithm, providerName);
+    }
+
+    public KeyPairGenerator createKeyPairGenerator(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return KeyPairGenerator.getInstance(algorithm, providerName);
+    }
+
+    public MessageDigest createDigest(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return MessageDigest.getInstance(algorithm, providerName);
+    }
+
+    public Signature createSignature(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return Signature.getInstance(algorithm, providerName);
+    }
+
+    public CertificateFactory createCertificateFactory(String algorithm)
+        throws CertificateException, NoSuchProviderException
+    {
+        return CertificateFactory.getInstance(algorithm, providerName);
+    }
+
+    public SecureRandom createSecureRandom(String algorithm)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        return SecureRandom.getInstance(algorithm, providerName);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java
new file mode 100644
index 0000000..bba9262
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java
@@ -0,0 +1,115 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jcajce.util;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+/**
+ * {@link JcaJceHelper} that obtains all algorithms from a specific {@link Provider} instance.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ProviderJcaJceHelper
+    implements JcaJceHelper
+{
+    protected final Provider provider;
+
+    public ProviderJcaJceHelper(Provider provider)
+    {
+        this.provider = provider;
+    }
+
+    public Cipher createCipher(
+        String algorithm)
+        throws NoSuchAlgorithmException, NoSuchPaddingException
+    {
+        return Cipher.getInstance(algorithm, provider);
+    }
+
+    public Mac createMac(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return Mac.getInstance(algorithm, provider);
+    }
+
+    public KeyAgreement createKeyAgreement(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyAgreement.getInstance(algorithm, provider);
+    }
+
+    public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return AlgorithmParameterGenerator.getInstance(algorithm, provider);
+    }
+
+    public AlgorithmParameters createAlgorithmParameters(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return AlgorithmParameters.getInstance(algorithm, provider);
+    }
+
+    public KeyGenerator createKeyGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyGenerator.getInstance(algorithm, provider);
+    }
+
+    public KeyFactory createKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyFactory.getInstance(algorithm, provider);
+    }
+
+    public SecretKeyFactory createSecretKeyFactory(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return SecretKeyFactory.getInstance(algorithm, provider);
+    }
+
+    public KeyPairGenerator createKeyPairGenerator(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return KeyPairGenerator.getInstance(algorithm, provider);
+    }
+
+    public MessageDigest createDigest(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return MessageDigest.getInstance(algorithm, provider);
+    }
+
+    public Signature createSignature(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return Signature.getInstance(algorithm, provider);
+    }
+
+    public CertificateFactory createCertificateFactory(String algorithm)
+        throws CertificateException
+    {
+        return CertificateFactory.getInstance(algorithm, provider);
+    }
+
+    public SecureRandom createSecureRandom(String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return SecureRandom.getInstance(algorithm, provider);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/ECNamedCurveTable.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/ECNamedCurveTable.java
new file mode 100644
index 0000000..aabfac9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/ECNamedCurveTable.java
@@ -0,0 +1,78 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+
+/**
+ * a table of locally supported named curves.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECNamedCurveTable
+{
+    /**
+     * return a parameter spec representing the passed in named
+     * curve. The routine returns null if the curve is not present.
+     * 
+     * @param name the name of the curve requested
+     * @return a parameter spec for the curve, null if it is not available.
+     */
+    public static ECNamedCurveParameterSpec getParameterSpec(
+        String  name)
+    {
+        X9ECParameters  ecP = com.android.internal.org.bouncycastle.crypto.ec.CustomNamedCurves.getByName(name);
+        if (ecP == null)
+        {
+            try
+            {
+                ecP = com.android.internal.org.bouncycastle.crypto.ec.CustomNamedCurves.getByOID(new ASN1ObjectIdentifier(name));
+            }
+            catch (IllegalArgumentException e)
+            {
+                // ignore - not an oid
+            }
+
+            if (ecP == null)
+            {
+                ecP = com.android.internal.org.bouncycastle.asn1.x9.ECNamedCurveTable.getByName(name);
+                if (ecP == null)
+                {
+                    try
+                    {
+                        ecP = com.android.internal.org.bouncycastle.asn1.x9.ECNamedCurveTable.getByOID(new ASN1ObjectIdentifier(name));
+                    }
+                    catch (IllegalArgumentException e)
+                    {
+                        // ignore - not an oid
+                    }
+                }
+            }
+        }
+
+        if (ecP == null)
+        {
+            return null;
+        }
+
+        return new ECNamedCurveParameterSpec(
+                                        name,
+                                        ecP.getCurve(),
+                                        ecP.getG(),
+                                        ecP.getN(),
+                                        ecP.getH(),
+                                        ecP.getSeed());
+    }
+
+    /**
+     * return an enumeration of the names of the available curves.
+     *
+     * @return an enumeration of the names of the available curves.
+     */
+    public static Enumeration getNames()
+    {
+        return com.android.internal.org.bouncycastle.asn1.x9.ECNamedCurveTable.getNames();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/PKCS10CertificationRequest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/PKCS10CertificationRequest.java
new file mode 100644
index 0000000..3918d4b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/PKCS10CertificationRequest.java
@@ -0,0 +1,660 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PSSParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.CertificationRequest;
+import com.android.internal.org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Name;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * A class for verifying and creating PKCS10 Certification requests. 
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ *   certificationRequestInfo  CertificationRequestInfo,
+ *   signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+ *   signature                 BIT STRING
+ * }
+ *
+ * CertificationRequestInfo ::= SEQUENCE {
+ *   version             INTEGER { v1(0) } (v1,...),
+ *   subject             Name,
+ *   subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ *   attributes          [0] Attributes{{ CRIAttributes }}
+ *  }
+ *
+ *  Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
+ *
+ *  Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
+ *    type    ATTRIBUTE.&amp;id({IOSet}),
+ *    values  SET SIZE(1..MAX) OF ATTRIBUTE.&amp;Type({IOSet}{\@type})
+ *  }
+ * </pre>
+ * @deprecated use classes in org.bouncycastle.pkcs.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKCS10CertificationRequest
+    extends CertificationRequest
+{
+    private static Hashtable            algorithms = new Hashtable();
+    private static Hashtable            params = new Hashtable();
+    private static Hashtable            keyAlgorithms = new Hashtable();
+    private static Hashtable            oids = new Hashtable();
+    private static Set                  noParams = new HashSet();
+
+    static
+    {
+        // Android-removed: Unsupported algorithms
+        // algorithms.put("MD2WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"));
+        // algorithms.put("MD2WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"));
+        // END Android-removed: Unsupported algorithms
+        algorithms.put("MD5WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("MD5WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("RSAWITHMD5", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("SHA1WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("SHA1WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+        algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+        algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+        algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+        algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+        algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+        algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        algorithms.put("RSAWITHSHA1", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"));
+        // BEGIN Android-removed: Unsupported algorithms
+        // algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+        // algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+        // algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+        // algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+        // algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+        // algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+        // END Android-removed: Unsupported algorithms
+        algorithms.put("SHA1WITHDSA", new ASN1ObjectIdentifier("1.2.840.10040.4.3"));
+        algorithms.put("DSAWITHSHA1", new ASN1ObjectIdentifier("1.2.840.10040.4.3"));
+        algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+        algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+        algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+        algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+        algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+        algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+        algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+        algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+        algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+        algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+        // BEGIN Android-removed: Unsupported algorithms
+        // algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        // algorithms.put("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        // algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // END Android-removed: Unsupported algorithms
+
+        //
+        // reverse mappings
+        //
+        oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
+        oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+        oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
+        oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
+        oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
+        // BEGIN Android-removed: Unsupported algorithms
+        // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+        // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
+        // END Android-removed: Unsupported algorithms
+        
+        oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+        // BEGIN Android-removed: Unsupported algorithms
+        // oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+        // END Android-removed: Unsupported algorithms
+        oids.put(new ASN1ObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
+        oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+        oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA");
+        oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
+        oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
+        
+        //
+        // key types
+        //
+        keyAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+        keyAlgorithms.put(X9ObjectIdentifiers.id_dsa, "DSA");
+        
+        //
+        // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. 
+        // The parameters field SHALL be NULL for RSA based signature algorithms.
+        //
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+        noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+
+        //
+        // RFC 4491
+        //
+        // BEGIN Android-removed: Unsupported algorithms
+        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // END Android-removed: Unsupported algorithms
+        //
+        // explicit params
+        //
+        AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+        params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
+
+        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+        params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+
+        AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
+        params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
+
+        AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE);
+        params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
+
+        AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE);
+        params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
+    }
+
+    private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+    {
+        return new RSASSAPSSparams(
+            hashAlgId,
+            new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+            new ASN1Integer(saltSize),
+            new ASN1Integer(1));
+    }
+
+    private static ASN1Sequence toDERSequence(
+        byte[]  bytes)
+    {
+        try
+        {
+            ASN1InputStream         dIn = new ASN1InputStream(bytes);
+
+            return (ASN1Sequence)dIn.readObject();
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("badly encoded request");
+        }
+    }
+
+    /**
+     * construct a PKCS10 certification request from a DER encoded
+     * byte stream.
+     */
+    public PKCS10CertificationRequest(
+        byte[]  bytes)
+    {
+        super(toDERSequence(bytes));
+    }
+
+    public PKCS10CertificationRequest(
+        ASN1Sequence  sequence)
+    {
+        super(sequence);
+    }
+
+    /**
+     * create a PKCS10 certfication request using the BC provider.
+     */
+    public PKCS10CertificationRequest(
+        String              signatureAlgorithm,
+        X509Name            subject,
+        PublicKey           key,
+        ASN1Set             attributes,
+        PrivateKey          signingKey)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        this(signatureAlgorithm, subject, key, attributes, signingKey, BouncyCastleProvider.PROVIDER_NAME);
+    }
+
+    private static X509Name convertName(
+        X500Principal    name)
+    {
+        try
+        {
+            return new X509Principal(name.getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't convert name");
+        }
+    }
+    
+    /**
+     * create a PKCS10 certfication request using the BC provider.
+     */
+    public PKCS10CertificationRequest(
+        String              signatureAlgorithm,
+        X500Principal       subject,
+        PublicKey           key,
+        ASN1Set             attributes,
+        PrivateKey          signingKey)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, BouncyCastleProvider.PROVIDER_NAME);
+    }
+    
+    /**
+     * create a PKCS10 certfication request using the named provider.
+     */
+    public PKCS10CertificationRequest(
+        String              signatureAlgorithm,
+        X500Principal       subject,
+        PublicKey           key,
+        ASN1Set             attributes,
+        PrivateKey          signingKey,
+        String              provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, provider);
+    }
+    
+    /**
+     * create a PKCS10 certfication request using the named provider.
+     */
+    public PKCS10CertificationRequest(
+        String              signatureAlgorithm,
+        X509Name            subject,
+        PublicKey           key,
+        ASN1Set             attributes,
+        PrivateKey          signingKey,
+        String              provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        String algorithmName = Strings.toUpperCase(signatureAlgorithm);
+        ASN1ObjectIdentifier sigOID = (ASN1ObjectIdentifier)algorithms.get(algorithmName);
+
+        if (sigOID == null)
+        {
+            try
+            {
+                sigOID = new ASN1ObjectIdentifier(algorithmName);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("Unknown signature type requested");
+            }
+        }
+
+        if (subject == null)
+        {
+            throw new IllegalArgumentException("subject must not be null");
+        }
+
+        if (key == null)
+        {
+            throw new IllegalArgumentException("public key must not be null");
+        }
+
+        if (noParams.contains(sigOID))
+        {
+            this.sigAlgId = new AlgorithmIdentifier(sigOID);
+        }
+        else if (params.containsKey(algorithmName))
+        {
+            this.sigAlgId = new AlgorithmIdentifier(sigOID, (ASN1Encodable)params.get(algorithmName));
+        }
+        else
+        {
+            this.sigAlgId = new AlgorithmIdentifier(sigOID, DERNull.INSTANCE);
+        }
+
+        try
+        {
+            ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(key.getEncoded());
+            this.reqInfo = new CertificationRequestInfo(subject, SubjectPublicKeyInfo.getInstance(seq), attributes);
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't encode public key");
+        }
+
+        Signature sig;
+        if (provider == null)
+        {
+            sig = Signature.getInstance(signatureAlgorithm);
+        }
+        else
+        {
+            sig = Signature.getInstance(signatureAlgorithm, provider);
+        }
+
+        sig.initSign(signingKey);
+
+        try
+        {
+            sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("exception encoding TBS cert request - " + e);
+        }
+
+        this.sigBits = new DERBitString(sig.sign());
+    }
+
+    /**
+     * return the public key associated with the certification request -
+     * the public key is created using the BC provider.
+     */
+    public PublicKey getPublicKey()
+        throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException
+    {
+        return getPublicKey(BouncyCastleProvider.PROVIDER_NAME);
+    }
+
+    public PublicKey getPublicKey(
+        String  provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException
+    {
+        SubjectPublicKeyInfo    subjectPKInfo = reqInfo.getSubjectPublicKeyInfo();
+
+        
+        try
+        {
+            X509EncodedKeySpec      xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getOctets());
+            AlgorithmIdentifier     keyAlg = subjectPKInfo.getAlgorithm();
+            try
+            {
+                if (provider == null)
+                {
+                    return KeyFactory.getInstance(keyAlg.getAlgorithm().getId()).generatePublic(xspec);
+                }
+                else
+                {
+                    return KeyFactory.getInstance(keyAlg.getAlgorithm().getId(), provider).generatePublic(xspec);
+                }
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                //
+                // try an alternate
+                //
+                if (keyAlgorithms.get(keyAlg.getAlgorithm()) != null)
+                {
+                    String  keyAlgorithm = (String)keyAlgorithms.get(keyAlg.getAlgorithm());
+                    
+                    if (provider == null)
+                    {
+                        return KeyFactory.getInstance(keyAlgorithm).generatePublic(xspec);
+                    }
+                    else
+                    {
+                        return KeyFactory.getInstance(keyAlgorithm, provider).generatePublic(xspec);
+                    }
+                }
+                
+                throw e;
+            }
+        }
+        catch (InvalidKeySpecException e)
+        {
+            throw new InvalidKeyException("error decoding public key");
+        }
+        catch (IOException e)
+        {
+            throw new InvalidKeyException("error decoding public key");
+        }
+    }
+
+    /**
+     * verify the request using the BC provider.
+     */
+    public boolean verify()
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        return verify(BouncyCastleProvider.PROVIDER_NAME);
+    }
+
+    /**
+     * verify the request using the passed in provider.
+     */
+    public boolean verify(
+        String provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        return verify(this.getPublicKey(provider), provider);
+    }
+
+    /**
+     * verify the request using the passed in public key and the provider..
+     */
+    public boolean verify(
+        PublicKey pubKey,
+        String provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        Signature   sig;
+
+        try
+        {
+            if (provider == null)
+            {
+                sig = Signature.getInstance(getSignatureName(sigAlgId));
+            }
+            else
+            {
+                sig = Signature.getInstance(getSignatureName(sigAlgId), provider);
+            }
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            //
+            // try an alternate
+            //
+            if (oids.get(sigAlgId.getAlgorithm()) != null)
+            {
+                String  signatureAlgorithm = (String)oids.get(sigAlgId.getAlgorithm());
+
+                if (provider == null)
+                {
+                    sig = Signature.getInstance(signatureAlgorithm);
+                }
+                else
+                {
+                    sig = Signature.getInstance(signatureAlgorithm, provider);
+                }
+            }
+            else
+            {
+                throw e;
+            }
+        }
+
+        setSignatureParameters(sig, sigAlgId.getParameters());
+        
+        sig.initVerify(pubKey);
+
+        try
+        {
+            sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException("exception encoding TBS cert request - " + e);
+        }
+
+        return sig.verify(sigBits.getOctets());
+    }
+
+    /**
+     * return a DER encoded byte array representing this object
+     */
+    public byte[] getEncoded()
+    {
+        try
+        {
+            return this.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e.toString());
+        }
+    }
+
+    private void setSignatureParameters(
+        Signature signature,
+        ASN1Encodable params)
+        throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        if (params != null && !DERNull.INSTANCE.equals(params))
+        {
+            AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+
+            try
+            {
+                sigParams.init(params.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+            }
+            catch (IOException e)
+            {
+                throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+            }
+
+            if (signature.getAlgorithm().endsWith("MGF1"))
+            {
+                try
+                {
+                    signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+                }
+                catch (GeneralSecurityException e)
+                {
+                    throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+                }
+            }
+        }
+    }
+
+    static String getSignatureName(
+        AlgorithmIdentifier sigAlgId)
+    {
+        ASN1Encodable params = sigAlgId.getParameters();
+
+        if (params != null && !DERNull.INSTANCE.equals(params))
+        {
+            if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+            {
+                RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+                return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1";
+            }
+        }
+
+        return sigAlgId.getAlgorithm().getId();
+    }
+
+    private static String getDigestAlgName(
+        ASN1ObjectIdentifier digestAlgOID)
+    {
+        if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+        {
+            return "MD5";
+        }
+        else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+        {
+            return "SHA1";
+        }
+        else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+        {
+            return "SHA224";
+        }
+        else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+        {
+            return "SHA256";
+        }
+        else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+        {
+            return "SHA384";
+        }
+        else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+        {
+            return "SHA512";
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+        {
+            return "RIPEMD128";
+        }
+        else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+        {
+            return "RIPEMD160";
+        }
+        else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+        {
+            return "RIPEMD256";
+        }
+        else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+        {
+            return "GOST3411";
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+        else
+        {
+            return digestAlgOID.getId();            
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/PrincipalUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/PrincipalUtil.java
new file mode 100644
index 0000000..9194d85
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/PrincipalUtil.java
@@ -0,0 +1,83 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce;
+
+import java.io.IOException;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.x509.TBSCertList;
+import com.android.internal.org.bouncycastle.asn1.x509.TBSCertificateStructure;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Name;
+
+/**
+ * a utility class that will extract X509Principal objects from X.509 certificates.
+ * <p>
+ * Use this in preference to trying to recreate a principal from a String, not all
+ * DNs are what they should be, so it's best to leave them encoded where they
+ * can be.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PrincipalUtil
+{
+    /**
+     * return the issuer of the given cert as an X509PrincipalObject.
+     */
+    public static X509Principal getIssuerX509Principal(
+        X509Certificate cert)
+        throws CertificateEncodingException
+    {
+        try
+        {
+            TBSCertificateStructure tbsCert = TBSCertificateStructure.getInstance(
+                    ASN1Primitive.fromByteArray(cert.getTBSCertificate()));
+
+            return new X509Principal(X509Name.getInstance(tbsCert.getIssuer()));
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException(e.toString());
+        }
+    }
+
+    /**
+     * return the subject of the given cert as an X509PrincipalObject.
+     */
+    public static X509Principal getSubjectX509Principal(
+        X509Certificate cert)
+        throws CertificateEncodingException
+    {
+        try
+        {
+            TBSCertificateStructure tbsCert = TBSCertificateStructure.getInstance(
+                    ASN1Primitive.fromByteArray(cert.getTBSCertificate()));
+            return new X509Principal(X509Name.getInstance(tbsCert.getSubject()));
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException(e.toString());
+        }
+    }
+    
+    /**
+     * return the issuer of the given CRL as an X509PrincipalObject.
+     */
+    public static X509Principal getIssuerX509Principal(
+        X509CRL crl)
+        throws CRLException
+    {
+        try
+        {
+            TBSCertList tbsCertList = TBSCertList.getInstance(
+                ASN1Primitive.fromByteArray(crl.getTBSCertList()));
+
+            return new X509Principal(X509Name.getInstance(tbsCertList.getIssuer()));
+        }
+        catch (IOException e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/X509Principal.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/X509Principal.java
new file mode 100644
index 0000000..758e770
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/X509Principal.java
@@ -0,0 +1,167 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Name;
+
+/**
+ * a general extension of X509Name with a couple of extra methods and
+ * constructors.
+ * <p>
+ * Objects of this type can be created from certificates and CRLs using the
+ * PrincipalUtil class.
+ * </p>
+ * @see com.android.internal.org.bouncycastle.jce.PrincipalUtil
+ * @deprecated use the X500Name class.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509Principal
+    extends X509Name
+    implements Principal
+{
+    private static ASN1Sequence readSequence(
+        ASN1InputStream aIn)
+        throws IOException
+    {
+        try
+        {
+            return ASN1Sequence.getInstance(aIn.readObject());
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw new IOException("not an ASN.1 Sequence: " + e);
+        }
+    }
+
+    /**
+     * Constructor from an encoded byte array.
+     */
+    public X509Principal(
+        byte[]  bytes)
+        throws IOException
+    {
+        super(readSequence(new ASN1InputStream(bytes)));
+    }
+
+    /**
+     * Constructor from an X509Name object.
+     */
+    public X509Principal(
+        X509Name  name)
+    {
+        super((ASN1Sequence)name.toASN1Primitive());
+    }
+
+     /**
+     * Constructor from an X509Name object.
+     */
+    public X509Principal(
+        X500Name name)
+    {
+        super((ASN1Sequence)name.toASN1Primitive());
+    }
+
+    /**
+     * constructor from a table of attributes.
+     * <p>
+     * it's is assumed the table contains OID/String pairs.
+     */
+    public X509Principal(
+        Hashtable  attributes)
+    {
+        super(attributes);
+    }
+
+    /**
+     * constructor from a table of attributes and a vector giving the
+     * specific ordering required for encoding or conversion to a string.
+     * <p>
+     * it's is assumed the table contains OID/String pairs.
+     */
+    public X509Principal(
+        Vector      ordering,
+        Hashtable   attributes)
+    {
+        super(ordering, attributes);
+    }
+
+    /**
+     * constructor from a vector of attribute values and a vector of OIDs.
+     */
+    public X509Principal(
+        Vector      oids,
+        Vector      values)
+    {
+        super(oids, values);
+    }
+
+    /**
+     * takes an X509 dir name as a string of the format "C=AU,ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes.
+     */
+    public X509Principal(
+        String  dirName)
+    {
+        super(dirName);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU,ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes. If reverse
+     * is false the dir name will be encoded in the order of the (name, value) pairs 
+     * presented, otherwise the encoding will start with the last (name, value) pair
+     * and work back.
+     */
+    public X509Principal(
+        boolean reverse,
+        String  dirName)
+    {
+        super(reverse, dirName);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes. lookUp 
+     * should provide a table of lookups, indexed by lowercase only strings and
+     * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids
+     * will be processed automatically.
+     * <p>
+     * If reverse is true, create the encoded version of the sequence starting
+     * from the last element in the string.
+     */
+    public X509Principal(
+        boolean     reverse,
+        Hashtable   lookUp,
+        String      dirName)
+    {
+        super(reverse, lookUp, dirName);
+    }
+
+    public String getName()
+    {
+        return this.toString();
+    }
+
+    /**
+     * return a DER encoded byte array representing this object
+     */
+    public byte[] getEncoded()
+    {
+        try
+        {
+            return this.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e.toString());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/exception/ExtCertPathBuilderException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/exception/ExtCertPathBuilderException.java
new file mode 100644
index 0000000..4764a41
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/exception/ExtCertPathBuilderException.java
@@ -0,0 +1,33 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.exception;
+
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilderException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ExtCertPathBuilderException
+    extends CertPathBuilderException
+    implements ExtException
+{
+    private Throwable cause;
+
+    public ExtCertPathBuilderException(String message, Throwable cause)
+    {
+        super(message);
+        this.cause = cause;
+    }
+
+    public ExtCertPathBuilderException(String msg, Throwable cause, 
+        CertPath certPath, int index)
+    {
+        super(msg, cause);
+        this.cause = cause;
+    }
+    
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/exception/ExtCertPathValidatorException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/exception/ExtCertPathValidatorException.java
new file mode 100644
index 0000000..65410dc
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/exception/ExtCertPathValidatorException.java
@@ -0,0 +1,34 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.exception;
+
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ExtCertPathValidatorException
+    extends CertPathValidatorException
+    implements ExtException
+{
+
+    private Throwable cause;
+
+    public ExtCertPathValidatorException(String message, Throwable cause)
+    {
+        super(message);
+        this.cause = cause;
+    }
+
+    public ExtCertPathValidatorException(String msg, Throwable cause, 
+        CertPath certPath, int index)
+    {
+        super(msg, cause, certPath, index);
+        this.cause = cause;
+    }
+    
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/exception/ExtException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/exception/ExtException.java
new file mode 100644
index 0000000..642440d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/exception/ExtException.java
@@ -0,0 +1,23 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.exception;
+
+/**
+ * 
+ * This is an extended exception. Java before version 1.4 did not offer the
+ * possibility the attach a cause to an exception. The cause of an exception is
+ * the <code>Throwable</code> object which was thrown and caused the
+ * exception. This interface must be implemented by all exceptions to accomplish
+ * this additional functionality.
+ * @hide This class is not part of the Android public SDK API
+ * 
+ */
+public interface ExtException
+{
+
+    /**
+     * Returns the cause of the exception.
+     * 
+     * @return The cause of the exception.
+     */
+    Throwable getCause();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/BCKeyStore.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/BCKeyStore.java
new file mode 100644
index 0000000..f2a45b0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/BCKeyStore.java
@@ -0,0 +1,16 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.interfaces;
+
+import java.security.SecureRandom;
+
+/**
+ * all BC provider keystores implement this interface.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface BCKeyStore
+{
+    /**
+     * set the random source for the key store
+     */
+    public void setRandom(SecureRandom random);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECKey.java
new file mode 100644
index 0000000..cc8044b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECKey.java
@@ -0,0 +1,17 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.interfaces;
+
+import com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec;
+
+/**
+ * generic interface for an Elliptic Curve Key.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ECKey
+{
+    /**
+     * return a parameter specification representing the EC domain parameters
+     * for the key.
+     */
+    public ECParameterSpec getParameters();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECPointEncoder.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECPointEncoder.java
new file mode 100644
index 0000000..06a1868
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECPointEncoder.java
@@ -0,0 +1,22 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.interfaces;
+
+/**
+ * All BC elliptic curve keys implement this interface. You need to
+ * cast the key to get access to it.
+ * <p>
+ * By default BC keys produce encodings without point compression,
+ * to turn this on call setPointFormat() with "COMPRESSED".
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ECPointEncoder
+{
+    /**
+     * Set the formatting for encoding of points. If the String "UNCOMPRESSED" is passed
+     * in point compression will not be used. If the String "COMPRESSED" is passed point
+     * compression will be used. The default is "UNCOMPRESSED".
+     * 
+     * @param style the style to use.
+     */
+    public void setPointFormat(String style);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECPrivateKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECPrivateKey.java
new file mode 100644
index 0000000..49c8c09
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECPrivateKey.java
@@ -0,0 +1,18 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * interface for Elliptic Curve Private keys.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ECPrivateKey
+    extends ECKey, PrivateKey
+{
+    /**
+     * return the private value D.
+     */
+    public BigInteger getD();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECPublicKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECPublicKey.java
new file mode 100644
index 0000000..5f58c02
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/ECPublicKey.java
@@ -0,0 +1,19 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.interfaces;
+
+import java.security.PublicKey;
+
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * interface for elliptic curve public keys.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ECPublicKey
+    extends ECKey, PublicKey
+{
+    /**
+     * return the public point Q
+     */
+    public ECPoint getQ();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java
new file mode 100644
index 0000000..b97384f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java
@@ -0,0 +1,23 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.interfaces;
+
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * allow us to set attributes on objects that can go into a PKCS12 store.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface PKCS12BagAttributeCarrier
+{
+    void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute);
+
+    ASN1Encodable getBagAttribute(
+        ASN1ObjectIdentifier oid);
+
+    Enumeration getBagAttributeKeys();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/netscape/NetscapeCertRequest.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
new file mode 100644
index 0000000..a77431f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
@@ -0,0 +1,301 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.netscape;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ *
+ * 
+ * Handles NetScape certificate request (KEYGEN), these are constructed as:
+ * <pre>
+ *   SignedPublicKeyAndChallenge ::= SEQUENCE {
+ *     publicKeyAndChallenge    PublicKeyAndChallenge,
+ *     signatureAlgorithm       AlgorithmIdentifier,
+ *     signature                BIT STRING
+ *   }
+ * </pre>
+ *
+ * PublicKey's encoded-format has to be X.509.
+ * @hide This class is not part of the Android public SDK API
+ *
+ **/
+public class NetscapeCertRequest
+    extends ASN1Object
+{
+    AlgorithmIdentifier    sigAlg;
+    AlgorithmIdentifier    keyAlg;
+    byte        sigBits [];
+    String challenge;
+    DERBitString content;
+    PublicKey pubkey ;
+    
+    private static ASN1Sequence getReq(
+        byte[]  r)
+        throws IOException
+    {
+        ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(r));
+
+        return ASN1Sequence.getInstance(aIn.readObject());
+    }
+
+    public NetscapeCertRequest(
+        byte[]  req)
+        throws IOException
+    {
+        this(getReq(req));
+    }
+
+    public NetscapeCertRequest (ASN1Sequence spkac)
+    {
+        try
+        {
+
+            //
+            // SignedPublicKeyAndChallenge ::= SEQUENCE {
+            //    publicKeyAndChallenge    PublicKeyAndChallenge,
+            //    signatureAlgorithm    AlgorithmIdentifier,
+            //    signature        BIT STRING
+            // }
+            //
+            if (spkac.size() != 3)
+            {
+                throw new IllegalArgumentException("invalid SPKAC (size):"
+                        + spkac.size());
+            }
+
+            sigAlg = AlgorithmIdentifier.getInstance(spkac.getObjectAt(1));
+            sigBits = ((DERBitString)spkac.getObjectAt(2)).getOctets();
+
+            //
+            // PublicKeyAndChallenge ::= SEQUENCE {
+            //    spki            SubjectPublicKeyInfo,
+            //    challenge        IA5STRING
+            // }
+            //
+            ASN1Sequence pkac = (ASN1Sequence)spkac.getObjectAt(0);
+
+            if (pkac.size() != 2)
+            {
+                throw new IllegalArgumentException("invalid PKAC (len): "
+                        + pkac.size());
+            }
+
+            challenge = ((DERIA5String)pkac.getObjectAt(1)).getString();
+
+            //this could be dangerous, as ASN.1 decoding/encoding
+            //could potentially alter the bytes
+            content = new DERBitString(pkac);
+
+            SubjectPublicKeyInfo pubkeyinfo = SubjectPublicKeyInfo.getInstance(pkac.getObjectAt(0));
+
+            X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(
+                    pubkeyinfo).getBytes());
+
+            keyAlg = pubkeyinfo.getAlgorithm();
+            pubkey = KeyFactory.getInstance(keyAlg.getAlgorithm().getId())
+                    .generatePublic(xspec);
+
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException(e.toString());
+        }
+    }
+
+    public NetscapeCertRequest(
+        String challenge,
+        AlgorithmIdentifier signing_alg,
+        PublicKey pub_key) throws NoSuchAlgorithmException,
+            InvalidKeySpecException, NoSuchProviderException
+    {
+
+        this.challenge = challenge;
+        sigAlg = signing_alg;
+        pubkey = pub_key;
+
+        ASN1EncodableVector content_der = new ASN1EncodableVector();
+        content_der.add(getKeySpec());
+        //content_der.add(new SubjectPublicKeyInfo(sigAlg, new RSAPublicKeyStructure(pubkey.getModulus(), pubkey.getPublicExponent()).getDERObject()));
+        content_der.add(new DERIA5String(challenge));
+
+        try
+        {
+            content = new DERBitString(new DERSequence(content_der));
+        }
+        catch (IOException e)
+        {
+            throw new InvalidKeySpecException("exception encoding key: " + e.toString());
+        }
+    }
+
+    public String getChallenge()
+    {
+        return challenge;
+    }
+
+    public void setChallenge(String value)
+    {
+        challenge = value;
+    }
+
+    public AlgorithmIdentifier getSigningAlgorithm()
+    {
+        return sigAlg;
+    }
+
+    public void setSigningAlgorithm(AlgorithmIdentifier value)
+    {
+        sigAlg = value;
+    }
+
+    public AlgorithmIdentifier getKeyAlgorithm()
+    {
+        return keyAlg;
+    }
+
+    public void setKeyAlgorithm(AlgorithmIdentifier value)
+    {
+        keyAlg = value;
+    }
+
+    public PublicKey getPublicKey()
+    {
+        return pubkey;
+    }
+
+    public void setPublicKey(PublicKey value)
+    {
+        pubkey = value;
+    }
+
+    public boolean verify(String challenge) throws NoSuchAlgorithmException,
+            InvalidKeyException, SignatureException, NoSuchProviderException
+    {
+        if (!challenge.equals(this.challenge))
+        {
+            return false;
+        }
+
+        //
+        // Verify the signature .. shows the response was generated
+        // by someone who knew the associated private key
+        //
+        Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId());
+        sig.initVerify(pubkey);
+        sig.update(content.getBytes());
+
+        return sig.verify(sigBits);
+    }
+
+    public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException,
+            InvalidKeyException, SignatureException, NoSuchProviderException,
+            InvalidKeySpecException
+    {
+        sign(priv_key, null);
+    }
+
+    public void sign(PrivateKey priv_key, SecureRandom rand)
+            throws NoSuchAlgorithmException, InvalidKeyException,
+            SignatureException, NoSuchProviderException,
+            InvalidKeySpecException
+    {
+        Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId());
+
+        if (rand != null)
+        {
+            sig.initSign(priv_key, rand);
+        }
+        else
+        {
+            sig.initSign(priv_key);
+        }
+
+        ASN1EncodableVector pkac = new ASN1EncodableVector();
+
+        pkac.add(getKeySpec());
+        pkac.add(new DERIA5String(challenge));
+
+        try
+        {
+            sig.update(new DERSequence(pkac).getEncoded(ASN1Encoding.DER));
+        }
+        catch (IOException ioe)
+        {
+            throw new SignatureException(ioe.getMessage());
+        }
+
+        sigBits = sig.sign();
+    }
+
+    private ASN1Primitive getKeySpec() throws NoSuchAlgorithmException,
+            InvalidKeySpecException, NoSuchProviderException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+        ASN1Primitive obj = null;
+        try
+        {
+
+            baos.write(pubkey.getEncoded());
+            baos.close();
+
+            ASN1InputStream derin = new ASN1InputStream(
+                    new ByteArrayInputStream(baos.toByteArray()));
+
+            obj = derin.readObject();
+        }
+        catch (IOException ioe)
+        {
+            throw new InvalidKeySpecException(ioe.getMessage());
+        }
+        return obj;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector spkac = new ASN1EncodableVector();
+        ASN1EncodableVector pkac = new ASN1EncodableVector();
+
+        try
+        {
+            pkac.add(getKeySpec());
+        }
+        catch (Exception e)
+        {
+            //ignore
+        }
+
+        pkac.add(new DERIA5String(challenge));
+
+        spkac.add(new DERSequence(pkac));
+        spkac.add(sigAlg);
+        spkac.add(new DERBitString(sigBits));
+
+        return new DERSequence(spkac);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/AnnotatedException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/AnnotatedException.java
new file mode 100644
index 0000000..d0327fe
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/AnnotatedException.java
@@ -0,0 +1,36 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import com.android.internal.org.bouncycastle.jce.exception.ExtException;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AnnotatedException
+    extends Exception
+    implements ExtException
+{
+    private Throwable _underlyingException;
+
+    public AnnotatedException(String string, Throwable e)
+    {
+        super(string);
+
+        _underlyingException = e;
+    }
+
+    public AnnotatedException(String string)
+    {
+        this(string, null);
+    }
+
+    Throwable getUnderlyingException()
+    {
+        return _underlyingException;
+    }
+
+    public Throwable getCause()
+    {
+        return _underlyingException;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/BouncyCastleProvider.java
new file mode 100644
index 0000000..59e0c56
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -0,0 +1,400 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import com.android.internal.org.bouncycastle.jcajce.provider.symmetric.util.ClassUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+// import org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceCCA2KeyFactorySpi;
+// import org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceKeyFactorySpi;
+// import org.bouncycastle.pqc.jcajce.provider.newhope.NHKeyFactorySpi;
+// import org.bouncycastle.pqc.jcajce.provider.qtesla.QTESLAKeyFactorySpi;
+// import org.bouncycastle.pqc.jcajce.provider.rainbow.RainbowKeyFactorySpi;
+// import org.bouncycastle.pqc.jcajce.provider.sphincs.Sphincs256KeyFactorySpi;
+// import org.bouncycastle.pqc.jcajce.provider.xmss.XMSSKeyFactorySpi;
+// import org.bouncycastle.pqc.jcajce.provider.xmss.XMSSMTKeyFactorySpi;
+
+/**
+ * To add the provider at runtime use:
+ * <pre>
+ * import java.security.Security;
+ * import org.bouncycastle.jce.provider.BouncyCastleProvider;
+ *
+ * Security.addProvider(new BouncyCastleProvider());
+ * </pre>
+ * The provider can also be configured as part of your environment via
+ * static registration by adding an entry to the java.security properties
+ * file (found in $JAVA_HOME/jre/lib/security/java.security, where
+ * $JAVA_HOME is the location of your JDK/JRE distribution). You'll find
+ * detailed instructions in the file but basically it comes down to adding
+ * a line:
+ * <pre>
+ * <code>
+ *    security.provider.&lt;n&gt;=org.bouncycastle.jce.provider.BouncyCastleProvider
+ * </code>
+ * </pre>
+ * Where &lt;n&gt; is the preference you want the provider at (1 being the
+ * most preferred).
+ * <p>Note: JCE algorithm names should be upper-case only so the case insensitive
+ * test for getInstance works.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class BouncyCastleProvider extends Provider
+    implements ConfigurableProvider
+{
+    private static String info = "BouncyCastle Security Provider v1.61";
+
+    public static final String PROVIDER_NAME = "BC";
+
+    public static final ProviderConfiguration CONFIGURATION = new BouncyCastleProviderConfiguration();
+
+    private static final Map keyInfoConverters = new HashMap();
+
+    /*
+     * Configurable symmetric ciphers
+     */
+    private static final String SYMMETRIC_PACKAGE = "com.android.internal.org.bouncycastle.jcajce.provider.symmetric.";
+
+    private static final String[] SYMMETRIC_GENERIC =
+    {
+        // Android-changed: Remove unsupported algorithms, add our own version of PBEv2 AlgParams
+        // "PBEPBKDF1", "PBEPBKDF2", "PBEPKCS12", "TLSKDF", "SCRYPT"
+        "PBEPBKDF2", "PBEPKCS12", "PBES2AlgorithmParameters"
+    };
+
+    private static final String[] SYMMETRIC_MACS =
+    {
+        // Android-removed: Unsupported algorithms
+        // "SipHash", "Poly1305"
+    };
+
+    private static final String[] SYMMETRIC_CIPHERS =
+    {
+        // Android-changed: Unsupported algorithms
+        // "AES", "ARC4", "ARIA", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede",
+        // "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5",
+        // "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "SM4", "TEA", "Twofish", "Threefish",
+        // "VMPC", "VMPCKSA3", "XTEA", "XSalsa20", "OpenSSLPBKDF", "DSTU7624", "GOST3412_2015"
+        "AES", "ARC4", "Blowfish", "DES", "DESede", "RC2", "Twofish",
+    };
+
+     /*
+     * Configurable asymmetric ciphers
+     */
+    private static final String ASYMMETRIC_PACKAGE = "com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.";
+
+    // this one is required for GNU class path - it needs to be loaded first as the
+    // later ones configure it.
+    private static final String[] ASYMMETRIC_GENERIC =
+    {
+        // Android-changed: Unsupported algorithms
+        // "X509", "IES"
+        "X509"
+    };
+
+    private static final String[] ASYMMETRIC_CIPHERS =
+    {
+        // Android-changed: Unsupported algorithms
+        // "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145", "GM", "EdEC"
+        "DSA", "DH", "EC", "RSA",
+    };
+
+    /*
+     * Configurable digests
+     */
+    private static final String DIGEST_PACKAGE = "com.android.internal.org.bouncycastle.jcajce.provider.digest.";
+    private static final String[] DIGESTS =
+    {
+        // Android-changed: Unsupported algorithms
+        // "GOST3411", "Keccak", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224",
+        // "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b", "Blake2s", "DSTU7564"
+        "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512",
+    };
+
+    /*
+     * Configurable keystores
+     */
+    private static final String KEYSTORE_PACKAGE = "com.android.internal.org.bouncycastle.jcajce.provider.keystore.";
+    private static final String[] KEYSTORES =
+    {
+        "BC", "BCFKS", "PKCS12"
+    };
+
+    // Android-removed: Unsupported algorithms
+    // /*
+    //  * Configurable secure random
+    //  */
+    // private static final String SECURE_RANDOM_PACKAGE = "org.bouncycastle.jcajce.provider.drbg.";
+    // private static final String[] SECURE_RANDOMS =
+    // {
+    //     "DRBG"
+    // };
+
+    /**
+     * Construct a new provider.  This should only be required when
+     * using runtime registration of the provider using the
+     * <code>Security.addProvider()</code> mechanism.
+     */
+    public BouncyCastleProvider()
+    {
+        super(PROVIDER_NAME, 1.61, info);
+
+        AccessController.doPrivileged(new PrivilegedAction()
+        {
+            public Object run()
+            {
+                setup();
+                return null;
+            }
+        });
+    }
+
+    private void setup()
+    {
+        loadAlgorithms(DIGEST_PACKAGE, DIGESTS);
+
+        loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_GENERIC);
+
+        loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_MACS);
+
+        loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_CIPHERS);
+
+        loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_GENERIC);
+
+        loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_CIPHERS);
+
+        loadAlgorithms(KEYSTORE_PACKAGE, KEYSTORES);
+
+        // Android-removed: Unsupported algorithms
+        /*
+        loadAlgorithms(SECURE_RANDOM_PACKAGE, SECURE_RANDOMS);
+
+        loadPQCKeys();  // so we can handle certificates containing them.
+        //
+        // X509Store
+        //
+        put("X509Store.CERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertCollection");
+        put("X509Store.ATTRIBUTECERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreAttrCertCollection");
+        put("X509Store.CRL/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCRLCollection");
+        put("X509Store.CERTIFICATEPAIR/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertPairCollection");
+
+        put("X509Store.CERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCerts");
+        put("X509Store.CRL/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCRLs");
+        put("X509Store.ATTRIBUTECERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPAttrCerts");
+        put("X509Store.CERTIFICATEPAIR/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCertPairs");
+        
+        //
+        // X509StreamParser
+        //
+        put("X509StreamParser.CERTIFICATE", "org.bouncycastle.jce.provider.X509CertParser");
+        put("X509StreamParser.ATTRIBUTECERTIFICATE", "org.bouncycastle.jce.provider.X509AttrCertParser");
+        put("X509StreamParser.CRL", "org.bouncycastle.jce.provider.X509CRLParser");
+        put("X509StreamParser.CERTIFICATEPAIR", "org.bouncycastle.jce.provider.X509CertPairParser");
+
+        //
+        // cipher engines
+        //
+        put("Cipher.BROKENPBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithMD5AndDES");
+
+        put("Cipher.BROKENPBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHA1AndDES");
+
+
+        put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish");
+
+        // Certification Path API
+        put("CertPathValidator.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathValidatorSpi");
+        put("CertPathBuilder.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathBuilderSpi");
+        put("CertPathValidator.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi");
+        put("CertPathBuilder.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi");
+        */
+        // END Android-removed: Unsupported algorithms
+        put("CertPathValidator.PKIX", "com.android.internal.org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi");
+        put("CertPathBuilder.PKIX", "com.android.internal.org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi");
+        put("CertStore.Collection", "com.android.internal.org.bouncycastle.jce.provider.CertStoreCollectionSpi");
+        // BEGIN Android-removed: Unsupported algorithms
+        // put("CertStore.LDAP", "org.bouncycastle.jce.provider.X509LDAPCertStoreSpi");
+        // put("CertStore.Multi", "org.bouncycastle.jce.provider.MultiCertStoreSpi");
+        // put("Alg.Alias.CertStore.X509LDAP", "LDAP");
+        // END Android-removed: Unsupported algorithms
+    }
+
+    private void loadAlgorithms(String packageName, String[] names)
+    {
+        for (int i = 0; i != names.length; i++)
+        {
+            Class clazz = ClassUtil.loadClass(BouncyCastleProvider.class, packageName + names[i] + "$Mappings");
+
+            if (clazz != null)
+            {
+                try
+                {
+                    ((AlgorithmProvider)clazz.newInstance()).configure(this);
+                }
+                catch (Exception e)
+                {   // this should never ever happen!!
+                    throw new InternalError("cannot create instance of "
+                        + packageName + names[i] + "$Mappings : " + e);
+                }
+            }
+        }
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    private void loadPQCKeys()
+    {
+        addKeyInfoConverter(PQCObjectIdentifiers.sphincs256, new Sphincs256KeyFactorySpi());
+        addKeyInfoConverter(PQCObjectIdentifiers.newHope, new NHKeyFactorySpi());
+        addKeyInfoConverter(PQCObjectIdentifiers.xmss, new XMSSKeyFactorySpi());
+        addKeyInfoConverter(PQCObjectIdentifiers.xmss_mt, new XMSSMTKeyFactorySpi());
+        addKeyInfoConverter(PQCObjectIdentifiers.mcEliece, new McElieceKeyFactorySpi());
+        addKeyInfoConverter(PQCObjectIdentifiers.mcElieceCca2, new McElieceCCA2KeyFactorySpi());
+        addKeyInfoConverter(PQCObjectIdentifiers.rainbow, new RainbowKeyFactorySpi());
+        addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_I, new QTESLAKeyFactorySpi());
+        addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_III_size, new QTESLAKeyFactorySpi());
+        addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_III_speed, new QTESLAKeyFactorySpi());
+        addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_p_I, new QTESLAKeyFactorySpi());
+        addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_p_III, new QTESLAKeyFactorySpi());
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    public void setParameter(String parameterName, Object parameter)
+    {
+        synchronized (CONFIGURATION)
+        {
+            ((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter);
+        }
+    }
+
+    public boolean hasAlgorithm(String type, String name)
+    {
+        return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name);
+    }
+
+    public void addAlgorithm(String key, String value)
+    {
+        if (containsKey(key))
+        {
+            throw new IllegalStateException("duplicate provider key (" + key + ") found");
+        }
+
+        put(key, value);
+    }
+
+    public void addAlgorithm(String type, ASN1ObjectIdentifier oid, String className)
+    {
+        addAlgorithm(type + "." + oid, className);
+        addAlgorithm(type + ".OID." + oid, className);
+    }
+
+    public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
+    {
+        synchronized (keyInfoConverters)
+        {
+            keyInfoConverters.put(oid, keyInfoConverter);
+        }
+    }
+
+    public void addAttributes(String key, Map<String, String> attributeMap)
+    {
+        for (Iterator it = attributeMap.keySet().iterator(); it.hasNext();)
+        {
+            String attributeName = (String)it.next();
+            String attributeKey = key + " " + attributeName;
+            if (containsKey(attributeKey))
+            {
+                throw new IllegalStateException("duplicate provider attribute key (" + attributeKey + ") found");
+            }
+
+            put(attributeKey, attributeMap.get(attributeName));
+        }
+    }
+
+    private static AsymmetricKeyInfoConverter getAsymmetricKeyInfoConverter(ASN1ObjectIdentifier algorithm)
+    {
+        synchronized (keyInfoConverters)
+        {
+            return (AsymmetricKeyInfoConverter)keyInfoConverters.get(algorithm);
+        }
+    }
+
+    public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+        throws IOException
+    {
+        // Android-added: BC KeyFactories have been removed, so load them the standard way
+        try {
+            return KeyFactory
+                .getInstance(
+                    publicKeyInfo.getAlgorithmId().getAlgorithm().getId())
+                .generatePublic(
+                    new X509EncodedKeySpec(publicKeyInfo.getEncoded()));
+        } catch (java.security.NoSuchAlgorithmException ex) {
+            // Maintaining compatibility with upstream logic: if appropriate algorithm not found
+            // ("converter" in Android-removed section) return null instead of throwing.
+            return null;
+        } catch (java.security.spec.InvalidKeySpecException ex) {
+            throw new IOException(ex);
+        }
+        // Android-removed: see above
+        /*
+        AsymmetricKeyInfoConverter converter = getAsymmetricKeyInfoConverter(publicKeyInfo.getAlgorithm().getAlgorithm());
+
+        if (converter == null)
+        {
+            return null;
+        }
+
+        return converter.generatePublic(publicKeyInfo);
+        */
+    }
+
+    public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
+        throws IOException
+    {
+        // Android-added: BC KeyFactories have been removed, so load them the standard way
+        try {
+            return KeyFactory
+                .getInstance(
+                    privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm().getId())
+                .generatePrivate(
+                    new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded()));
+        } catch (java.security.NoSuchAlgorithmException ex) {
+            // Maintaining compatibility with upstream logic: if appropriate algorithm not found
+            // ("converter" in Android-removed section) return null instead of throwing.
+            return null;
+        } catch (java.security.spec.InvalidKeySpecException ex) {
+            throw new IOException(ex);
+        }
+        // Android-removed: see above
+        /*
+        AsymmetricKeyInfoConverter converter = getAsymmetricKeyInfoConverter(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
+
+        if (converter == null)
+        {
+            return null;
+        }
+
+        return converter.generatePrivate(privateKeyInfo);
+        */
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java
new file mode 100644
index 0000000..f4f165c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java
@@ -0,0 +1,229 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.security.Permission;
+import java.security.spec.DSAParameterSpec;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import com.android.internal.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DSAParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import com.android.internal.org.bouncycastle.jcajce.provider.config.ProviderConfigurationPermission;
+import com.android.internal.org.bouncycastle.jcajce.spec.DHDomainParameterSpec;
+import com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec;
+
+class BouncyCastleProviderConfiguration
+    implements ProviderConfiguration
+{
+    private static Permission BC_EC_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+        BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA);
+    private static Permission BC_EC_PERMISSION = new ProviderConfigurationPermission(
+        BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.EC_IMPLICITLY_CA);
+    private static Permission BC_DH_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+        BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS);
+    private static Permission BC_DH_PERMISSION = new ProviderConfigurationPermission(
+        BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.DH_DEFAULT_PARAMS);
+    private static Permission BC_EC_CURVE_PERMISSION = new ProviderConfigurationPermission(
+        BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.ACCEPTABLE_EC_CURVES);
+    private static Permission BC_ADDITIONAL_EC_CURVE_PERMISSION = new ProviderConfigurationPermission(
+        BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.ADDITIONAL_EC_PARAMETERS);
+
+    private ThreadLocal ecThreadSpec = new ThreadLocal();
+    private ThreadLocal dhThreadSpec = new ThreadLocal();
+
+    private volatile ECParameterSpec ecImplicitCaParams;
+    private volatile Object dhDefaultParams;
+    private volatile Set acceptableNamedCurves = new HashSet();
+    private volatile Map additionalECParameters = new HashMap();
+
+    void setParameter(String parameterName, Object parameter)
+    {
+        SecurityManager securityManager = System.getSecurityManager();
+
+        if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
+        {
+            ECParameterSpec curveSpec;
+
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
+            }
+
+            if (parameter instanceof ECParameterSpec || parameter == null)
+            {
+                curveSpec = (ECParameterSpec)parameter;
+            }
+            else  // assume java.security.spec
+            {
+                curveSpec = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
+            }
+
+            if (curveSpec == null)
+            {
+                ecThreadSpec.remove();
+            }
+            else
+            {
+                ecThreadSpec.set(curveSpec);
+            }
+        }
+        else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
+        {
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_EC_PERMISSION);
+            }
+
+            if (parameter instanceof ECParameterSpec || parameter == null)
+            {
+                ecImplicitCaParams = (ECParameterSpec)parameter;
+            }
+            else  // assume java.security.spec
+            {
+                ecImplicitCaParams = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
+            }
+        }
+        else if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS))
+        {
+            Object dhSpec;
+
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_DH_LOCAL_PERMISSION);
+            }
+
+            if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null)
+            {
+                dhSpec = parameter;
+            }
+            else
+            {
+                throw new IllegalArgumentException("not a valid DHParameterSpec");
+            }
+
+            if (dhSpec == null)
+            {
+                dhThreadSpec.remove();
+            }
+            else
+            {
+                dhThreadSpec.set(dhSpec);
+            }
+        }
+        else if (parameterName.equals(ConfigurableProvider.DH_DEFAULT_PARAMS))
+        {
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_DH_PERMISSION);
+            }
+
+            if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null)
+            {
+                dhDefaultParams = parameter;
+            }
+            else
+            {
+                throw new IllegalArgumentException("not a valid DHParameterSpec or DHParameterSpec[]");
+            }
+        }
+        else if (parameterName.equals(ConfigurableProvider.ACCEPTABLE_EC_CURVES))
+        {
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_EC_CURVE_PERMISSION);
+            }
+
+            this.acceptableNamedCurves = (Set)parameter;
+        }
+        else if (parameterName.equals(ConfigurableProvider.ADDITIONAL_EC_PARAMETERS))
+        {
+            if (securityManager != null)
+            {
+                securityManager.checkPermission(BC_ADDITIONAL_EC_CURVE_PERMISSION);
+            }
+
+            this.additionalECParameters = (Map)parameter;
+        }
+    }
+
+    public ECParameterSpec getEcImplicitlyCa()
+    {
+        ECParameterSpec spec = (ECParameterSpec)ecThreadSpec.get();
+
+        if (spec != null)
+        {
+            return spec;
+        }
+
+        return ecImplicitCaParams;
+    }
+
+    public DHParameterSpec getDHDefaultParameters(int keySize)
+    {
+        Object params = dhThreadSpec.get();
+        if (params == null)
+        {
+            params = dhDefaultParams;
+        }
+
+        if (params instanceof DHParameterSpec)
+        {
+            DHParameterSpec spec = (DHParameterSpec)params;
+
+            if (spec.getP().bitLength() == keySize)
+            {
+                return spec;
+            }
+        }
+        else if (params instanceof DHParameterSpec[])
+        {
+            DHParameterSpec[] specs = (DHParameterSpec[])params;
+
+            for (int i = 0; i != specs.length; i++)
+            {
+                if (specs[i].getP().bitLength() == keySize)
+                {
+                    return specs[i];
+                }
+            }
+        }
+
+        DHParameters dhParams = CryptoServicesRegistrar.getSizedProperty(CryptoServicesRegistrar.Property.DH_DEFAULT_PARAMS, keySize);
+        if (dhParams != null)
+        {
+            return new DHDomainParameterSpec(dhParams);
+        }
+
+        return null;
+    }
+
+    public DSAParameterSpec getDSADefaultParameters(int keySize)
+    {
+        DSAParameters dsaParams = CryptoServicesRegistrar.getSizedProperty(CryptoServicesRegistrar.Property.DSA_DEFAULT_PARAMS, keySize);
+        if (dsaParams != null)
+        {
+            return new DSAParameterSpec(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
+        }
+
+        return null;
+    }
+
+    public Set getAcceptableNamedCurves()
+    {
+        return Collections.unmodifiableSet(acceptableNamedCurves);
+    }
+
+    public Map getAdditionalECParameters()
+    {
+        return Collections.unmodifiableMap(additionalECParameters);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertBlocklist.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertBlocklist.java
new file mode 100644
index 0000000..185f4b6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertBlocklist.java
@@ -0,0 +1,238 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.Closeable;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CertBlocklist {
+    private static final Logger logger = Logger.getLogger(CertBlocklist.class.getName());
+
+    // public for testing
+    public final Set<BigInteger> serialBlocklist;
+    public final Set<byte[]> pubkeyBlocklist;
+
+    public CertBlocklist() {
+        String androidData = System.getenv("ANDROID_DATA");
+        String blocklistRoot = androidData + "/misc/keychain/";
+        // TODO(b/162575432): change these paths to use inclusive language
+        String defaultPubkeyBlocklistPath = blocklistRoot + "pubkey_blacklist.txt";
+        String defaultSerialBlocklistPath = blocklistRoot + "serial_blacklist.txt";
+
+        pubkeyBlocklist = readPublicKeyBlockList(defaultPubkeyBlocklistPath);
+        serialBlocklist = readSerialBlockList(defaultSerialBlocklistPath);
+    }
+
+    /** Test only interface, not for public use */
+    public CertBlocklist(String pubkeyBlocklistPath, String serialBlocklistPath) {
+        pubkeyBlocklist = readPublicKeyBlockList(pubkeyBlocklistPath);
+        serialBlocklist = readSerialBlockList(serialBlocklistPath);
+    }
+
+    private static boolean isHex(String value) {
+        try {
+            new BigInteger(value, 16);
+            return true;
+        } catch (NumberFormatException e) {
+            logger.log(Level.WARNING, "Could not parse hex value " + value, e);
+            return false;
+        }
+    }
+
+    private static boolean isPubkeyHash(String value) {
+        if (value.length() != 40) {
+            logger.log(Level.WARNING, "Invalid pubkey hash length: " + value.length());
+            return false;
+        }
+        return isHex(value);
+    }
+
+    private static String readBlocklist(String path) {
+        try {
+            return readFileAsString(path);
+        } catch (FileNotFoundException ignored) {
+        } catch (IOException e) {
+            logger.log(Level.WARNING, "Could not read blocklist", e);
+        }
+        return "";
+    }
+
+    // From IoUtils.readFileAsString
+    private static String readFileAsString(String path) throws IOException {
+        return readFileAsBytes(path).toString("UTF-8");
+    }
+
+    // Based on IoUtils.readFileAsBytes
+    private static ByteArrayOutputStream readFileAsBytes(String path) throws IOException {
+        RandomAccessFile f = null;
+        try {
+            f = new RandomAccessFile(path, "r");
+            ByteArrayOutputStream bytes = new ByteArrayOutputStream((int) f.length());
+            byte[] buffer = new byte[8192];
+            while (true) {
+                int byteCount = f.read(buffer);
+                if (byteCount == -1) {
+                    return bytes;
+                }
+                bytes.write(buffer, 0, byteCount);
+            }
+        } finally {
+            closeQuietly(f);
+        }
+    }
+
+    // Base on IoUtils.closeQuietly
+    private static void closeQuietly(Closeable closeable) {
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (RuntimeException rethrown) {
+                throw rethrown;
+            } catch (Exception ignored) {
+            }
+        }
+    }
+
+    private static Set<BigInteger> readSerialBlockList(String path) {
+
+        /* Start out with a base set of known bad values.
+         *
+         * WARNING: Do not add short serials to this list!
+         *
+         * Since this currently doesn't compare the serial + issuer, you
+         * should only add serials that have enough entropy here. Short
+         * serials may inadvertently match a certificate that was issued
+         * not in compliance with the Baseline Requirements.
+         */
+        Set<BigInteger> bl = new HashSet<BigInteger>(Arrays.asList(
+            // From http://src.chromium.org/viewvc/chrome/trunk/src/net/base/x509_certificate.cc?revision=78748&view=markup
+            // Not a real certificate. For testing only.
+            new BigInteger("077a59bcd53459601ca6907267a6dd1c", 16),
+            new BigInteger("047ecbe9fca55f7bd09eae36e10cae1e", 16),
+            new BigInteger("d8f35f4eb7872b2dab0692e315382fb0", 16),
+            new BigInteger("b0b7133ed096f9b56fae91c874bd3ac0", 16),
+            new BigInteger("9239d5348f40d1695a745470e1f23f43", 16),
+            new BigInteger("e9028b9578e415dc1a710a2b88154447", 16),
+            new BigInteger("d7558fdaf5f1105bb213282b707729a3", 16),
+            new BigInteger("f5c86af36162f13a64f54f6dc9587c06", 16),
+            new BigInteger("392a434f0e07df1f8aa305de34e0c229", 16),
+            new BigInteger("3e75ced46b693021218830ae86a82a71", 16)
+        ));
+
+        // attempt to augment it with values taken from gservices
+        String serialBlocklist = readBlocklist(path);
+        if (!serialBlocklist.equals("")) {
+            for(String value : serialBlocklist.split(",")) {
+                try {
+                    bl.add(new BigInteger(value, 16));
+                } catch (NumberFormatException e) {
+                    logger.log(Level.WARNING, "Tried to blocklist invalid serial number " + value, e);
+                }
+            }
+        }
+
+        // whether that succeeds or fails, send it on its merry way
+        return Collections.unmodifiableSet(bl);
+    }
+
+    private static Set<byte[]> readPublicKeyBlockList(String path) {
+
+        // start out with a base set of known bad values
+        Set<byte[]> bl = new HashSet<byte[]>(Arrays.asList(
+            // From http://src.chromium.org/viewvc/chrome/branches/782/src/net/base/x509_certificate.cc?r1=98750&r2=98749&pathrev=98750
+            // C=NL, O=DigiNotar, CN=DigiNotar Root CA/emailAddress=info@diginotar.nl
+            "410f36363258f30b347d12ce4863e433437806a8".getBytes(),
+            // Subject: CN=DigiNotar Cyber CA
+            // Issuer: CN=GTE CyberTrust Global Root
+            "ba3e7bd38cd7e1e6b9cd4c219962e59d7a2f4e37".getBytes(),
+            // Subject: CN=DigiNotar Services 1024 CA
+            // Issuer: CN=Entrust.net
+            "e23b8d105f87710a68d9248050ebefc627be4ca6".getBytes(),
+            // Subject: CN=DigiNotar PKIoverheid CA Organisatie - G2
+            // Issuer: CN=Staat der Nederlanden Organisatie CA - G2
+            "7b2e16bc39bcd72b456e9f055d1de615b74945db".getBytes(),
+            // Subject: CN=DigiNotar PKIoverheid CA Overheid en Bedrijven
+            // Issuer: CN=Staat der Nederlanden Overheid CA
+            "e8f91200c65cee16e039b9f883841661635f81c5".getBytes(),
+            // From http://src.chromium.org/viewvc/chrome?view=rev&revision=108479
+            // Subject: O=Digicert Sdn. Bhd.
+            // Issuer: CN=GTE CyberTrust Global Root
+            "0129bcd5b448ae8d2496d1c3e19723919088e152".getBytes(),
+            // Subject: CN=e-islem.kktcmerkezbankasi.org/emailAddress=ileti@kktcmerkezbankasi.org
+            // Issuer: CN=T\xC3\x9CRKTRUST Elektronik Sunucu Sertifikas\xC4\xB1 Hizmetleri
+            "5f3ab33d55007054bc5e3e5553cd8d8465d77c61".getBytes(),
+            // Subject: CN=*.EGO.GOV.TR 93
+            // Issuer: CN=T\xC3\x9CRKTRUST Elektronik Sunucu Sertifikas\xC4\xB1 Hizmetleri
+            "783333c9687df63377efceddd82efa9101913e8e".getBytes(),
+            // Subject: Subject: C=FR, O=DG Tr\xC3\xA9sor, CN=AC DG Tr\xC3\xA9sor SSL
+            // Issuer: C=FR, O=DGTPE, CN=AC DGTPE Signature Authentification
+            "3ecf4bbbe46096d514bb539bb913d77aa4ef31bf".getBytes()
+        ));
+
+        // attempt to augment it with values taken from gservices
+        String pubkeyBlocklist = readBlocklist(path);
+        if (!pubkeyBlocklist.equals("")) {
+            for (String value : pubkeyBlocklist.split(",")) {
+                value = value.trim();
+                if (isPubkeyHash(value)) {
+                    bl.add(value.getBytes());
+                } else {
+                    logger.log(Level.WARNING, "Tried to blocklist invalid pubkey " + value);
+                }
+            }
+        }
+
+        return bl;
+    }
+
+    public boolean isPublicKeyBlockListed(PublicKey publicKey) {
+        byte[] encoded = publicKey.getEncoded();
+        Digest digest = AndroidDigestFactory.getSHA1();
+        digest.update(encoded, 0, encoded.length);
+        byte[] out = new byte[digest.getDigestSize()];
+        digest.doFinal(out, 0);
+        for (byte[] blocklisted : pubkeyBlocklist) {
+            if (Arrays.equals(blocklisted, Hex.encode(out))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean isSerialNumberBlockListed(BigInteger serial) {
+        return serialBlocklist.contains(serial);
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
new file mode 100644
index 0000000..606b7a0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
@@ -0,0 +1,1378 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.PolicyQualifierInfo;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509CRLSelector;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated;
+import com.android.internal.org.bouncycastle.asn1.ASN1GeneralizedTime;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1OutputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.isismtt.ISISMTTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x500.style.RFC4519Style;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.CRLDistPoint;
+import com.android.internal.org.bouncycastle.asn1.x509.CRLReason;
+import com.android.internal.org.bouncycastle.asn1.x509.DistributionPoint;
+import com.android.internal.org.bouncycastle.asn1.x509.DistributionPointName;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralNames;
+import com.android.internal.org.bouncycastle.asn1.x509.PolicyInformation;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.jcajce.PKIXCRLStore;
+import com.android.internal.org.bouncycastle.jcajce.PKIXCRLStoreSelector;
+import com.android.internal.org.bouncycastle.jcajce.PKIXCertStore;
+import com.android.internal.org.bouncycastle.jcajce.PKIXCertStoreSelector;
+import com.android.internal.org.bouncycastle.jcajce.PKIXExtendedParameters;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.jce.exception.ExtCertPathValidatorException;
+import com.android.internal.org.bouncycastle.util.Selector;
+import com.android.internal.org.bouncycastle.util.Store;
+import com.android.internal.org.bouncycastle.util.StoreException;
+import com.android.internal.org.bouncycastle.x509.X509AttributeCertificate;
+import com.android.internal.org.bouncycastle.x509.extension.X509ExtensionUtil;
+
+class CertPathValidatorUtilities
+{
+    protected static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
+    protected static final String CERTIFICATE_POLICIES = Extension.certificatePolicies.getId();
+    protected static final String BASIC_CONSTRAINTS = Extension.basicConstraints.getId();
+    protected static final String POLICY_MAPPINGS = Extension.policyMappings.getId();
+    protected static final String SUBJECT_ALTERNATIVE_NAME = Extension.subjectAlternativeName.getId();
+    protected static final String NAME_CONSTRAINTS = Extension.nameConstraints.getId();
+    protected static final String KEY_USAGE = Extension.keyUsage.getId();
+    protected static final String INHIBIT_ANY_POLICY = Extension.inhibitAnyPolicy.getId();
+    protected static final String ISSUING_DISTRIBUTION_POINT = Extension.issuingDistributionPoint.getId();
+    protected static final String DELTA_CRL_INDICATOR = Extension.deltaCRLIndicator.getId();
+    protected static final String POLICY_CONSTRAINTS = Extension.policyConstraints.getId();
+    protected static final String FRESHEST_CRL = Extension.freshestCRL.getId();
+    protected static final String CRL_DISTRIBUTION_POINTS = Extension.cRLDistributionPoints.getId();
+    protected static final String AUTHORITY_KEY_IDENTIFIER = Extension.authorityKeyIdentifier.getId();
+
+    protected static final String ANY_POLICY = "2.5.29.32.0";
+
+    protected static final String CRL_NUMBER = Extension.cRLNumber.getId();
+
+    /*
+    * key usage bits
+    */
+    protected static final int KEY_CERT_SIGN = 5;
+    protected static final int CRL_SIGN = 6;
+
+    protected static final String[] crlReasons = new String[]{
+        "unspecified",
+        "keyCompromise",
+        "cACompromise",
+        "affiliationChanged",
+        "superseded",
+        "cessationOfOperation",
+        "certificateHold",
+        "unknown",
+        "removeFromCRL",
+        "privilegeWithdrawn",
+        "aACompromise"};
+
+    /**
+     * Search the given Set of TrustAnchor's for one that is the
+     * issuer of the given X509 certificate. Uses the default provider
+     * for signature verification.
+     *
+     * @param cert         the X509 certificate
+     * @param trustAnchors a Set of TrustAnchor's
+     * @return the <code>TrustAnchor</code> object if found or
+     *         <code>null</code> if not.
+     * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+     * on the given certificate has thrown an exception.
+     */
+    protected static TrustAnchor findTrustAnchor(
+        X509Certificate cert,
+        Set trustAnchors)
+        throws AnnotatedException
+    {
+        return findTrustAnchor(cert, trustAnchors, null);
+    }
+
+    /**
+     * Search the given Set of TrustAnchor's for one that is the
+     * issuer of the given X509 certificate. Uses the specified
+     * provider for signature verification, or the default provider
+     * if null.
+     *
+     * @param cert         the X509 certificate
+     * @param trustAnchors a Set of TrustAnchor's
+     * @param sigProvider  the provider to use for signature verification
+     * @return the <code>TrustAnchor</code> object if found or
+     *         <code>null</code> if not.
+     * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+     * on the given certificate has thrown an exception.
+     */
+    protected static TrustAnchor findTrustAnchor(
+        X509Certificate cert,
+        Set trustAnchors,
+        String sigProvider)
+        throws AnnotatedException
+    {
+        TrustAnchor trust = null;
+        PublicKey trustPublicKey = null;
+        Exception invalidKeyEx = null;
+
+        X509CertSelector certSelectX509 = new X509CertSelector();
+        X500Name certIssuer = PrincipalUtils.getEncodedIssuerPrincipal(cert);
+
+        try
+        {
+            certSelectX509.setSubject(certIssuer.getEncoded());
+        }
+        catch (IOException ex)
+        {
+            throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
+        }
+
+        Iterator iter = trustAnchors.iterator();
+        while (iter.hasNext() && trust == null)
+        {
+            trust = (TrustAnchor)iter.next();
+            if (trust.getTrustedCert() != null)
+            {
+                if (certSelectX509.match(trust.getTrustedCert()))
+                {
+                    trustPublicKey = trust.getTrustedCert().getPublicKey();
+                }
+                else
+                {
+                    trust = null;
+                }
+            }
+            else if (trust.getCAName() != null
+                && trust.getCAPublicKey() != null)
+            {
+                try
+                {
+                    X500Name caName = PrincipalUtils.getCA(trust);
+                    if (certIssuer.equals(caName))
+                    {
+                        trustPublicKey = trust.getCAPublicKey();
+                    }
+                    else
+                    {
+                        trust = null;
+                    }
+                }
+                catch (IllegalArgumentException ex)
+                {
+                    trust = null;
+                }
+            }
+            else
+            {
+                trust = null;
+            }
+
+            if (trustPublicKey != null)
+            {
+                try
+                {
+                    verifyX509Certificate(cert, trustPublicKey, sigProvider);
+                }
+                catch (Exception ex)
+                {
+                    invalidKeyEx = ex;
+                    trust = null;
+                    trustPublicKey = null;
+                }
+            }
+        }
+
+        if (trust == null && invalidKeyEx != null)
+        {
+            throw new AnnotatedException("TrustAnchor found but certificate validation failed.", invalidKeyEx);
+        }
+
+        return trust;
+    }
+
+    static boolean isIssuerTrustAnchor(
+        X509Certificate cert,
+        Set trustAnchors,
+        String sigProvider)
+        throws AnnotatedException
+    {
+        try
+        {
+            return findTrustAnchor(cert, trustAnchors, sigProvider) != null;
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+    }
+
+    static List<PKIXCertStore> getAdditionalStoresFromAltNames(
+        byte[] issuerAlternativeName,
+        Map<GeneralName, PKIXCertStore> altNameCertStoreMap)
+        throws CertificateParsingException
+    {
+        // if in the IssuerAltName extension an URI
+        // is given, add an additional X.509 store
+        if (issuerAlternativeName != null)
+        {
+            GeneralNames issuerAltName = GeneralNames.getInstance(ASN1OctetString.getInstance(issuerAlternativeName).getOctets());
+
+            GeneralName[] names = issuerAltName.getNames();
+            List<PKIXCertStore>  stores = new ArrayList<PKIXCertStore>();
+
+            for (int i = 0; i != names.length; i++)
+            {
+                GeneralName altName = names[i];
+
+                PKIXCertStore altStore = altNameCertStoreMap.get(altName);
+
+                if (altStore != null)
+                {
+                    stores.add(altStore);
+                }
+            }
+
+            return stores;
+        }
+        else
+        {
+            return Collections.EMPTY_LIST;
+        }
+    }
+
+    protected static Date getValidDate(PKIXExtendedParameters paramsPKIX)
+    {
+        Date validDate = paramsPKIX.getDate();
+
+        if (validDate == null)
+        {
+            validDate = new Date();
+        }
+
+        return validDate;
+    }
+
+    protected static boolean isSelfIssued(X509Certificate cert)
+    {
+        return cert.getSubjectDN().equals(cert.getIssuerDN());
+    }
+
+
+    /**
+     * Extract the value of the given extension, if it exists.
+     *
+     * @param ext The extension object.
+     * @param oid The object identifier to obtain.
+     * @throws AnnotatedException if the extension cannot be read.
+     */
+    protected static ASN1Primitive getExtensionValue(
+        java.security.cert.X509Extension ext,
+        String oid)
+        throws AnnotatedException
+    {
+        byte[] bytes = ext.getExtensionValue(oid);
+        if (bytes == null)
+        {
+            return null;
+        }
+
+        return getObject(oid, bytes);
+    }
+
+    private static ASN1Primitive getObject(
+        String oid,
+        byte[] ext)
+        throws AnnotatedException
+    {
+        try
+        {
+            ASN1InputStream aIn = new ASN1InputStream(ext);
+            ASN1OctetString octs = (ASN1OctetString)aIn.readObject();
+
+            aIn = new ASN1InputStream(octs.getOctets());
+            return aIn.readObject();
+        }
+        catch (Exception e)
+        {
+            throw new AnnotatedException("exception processing extension " + oid, e);
+        }
+    }
+
+    protected static AlgorithmIdentifier getAlgorithmIdentifier(
+        PublicKey key)
+        throws CertPathValidatorException
+    {
+        try
+        {
+            ASN1InputStream aIn = new ASN1InputStream(key.getEncoded());
+
+            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
+
+            return info.getAlgorithm();
+        }
+        catch (Exception e)
+        {
+            throw new ExtCertPathValidatorException("Subject public key cannot be decoded.", e);
+        }
+    }
+
+    // crl checking
+
+
+    //
+    // policy checking
+    // 
+
+    protected static final Set getQualifierSet(ASN1Sequence qualifiers)
+        throws CertPathValidatorException
+    {
+        Set pq = new HashSet();
+
+        if (qualifiers == null)
+        {
+            return pq;
+        }
+
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+        Enumeration e = qualifiers.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            try
+            {
+                aOut.writeObject((ASN1Encodable)e.nextElement());
+
+                pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
+            }
+            catch (IOException ex)
+            {
+                throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
+            }
+
+            bOut.reset();
+        }
+
+        return pq;
+    }
+
+    protected static PKIXPolicyNode removePolicyNode(
+        PKIXPolicyNode validPolicyTree,
+        List[] policyNodes,
+        PKIXPolicyNode _node)
+    {
+        PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
+
+        if (validPolicyTree == null)
+        {
+            return null;
+        }
+
+        if (_parent == null)
+        {
+            for (int j = 0; j < policyNodes.length; j++)
+            {
+                policyNodes[j] = new ArrayList();
+            }
+
+            return null;
+        }
+        else
+        {
+            _parent.removeChild(_node);
+            removePolicyNodeRecurse(policyNodes, _node);
+
+            return validPolicyTree;
+        }
+    }
+
+    private static void removePolicyNodeRecurse(
+        List[] policyNodes,
+        PKIXPolicyNode _node)
+    {
+        policyNodes[_node.getDepth()].remove(_node);
+
+        if (_node.hasChildren())
+        {
+            Iterator _iter = _node.getChildren();
+            while (_iter.hasNext())
+            {
+                PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next();
+                removePolicyNodeRecurse(policyNodes, _child);
+            }
+        }
+    }
+
+
+    protected static boolean processCertD1i(
+        int index,
+        List[] policyNodes,
+        ASN1ObjectIdentifier pOid,
+        Set pq)
+    {
+        List policyNodeVec = policyNodes[index - 1];
+
+        for (int j = 0; j < policyNodeVec.size(); j++)
+        {
+            PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
+            Set expectedPolicies = node.getExpectedPolicies();
+
+            if (expectedPolicies.contains(pOid.getId()))
+            {
+                Set childExpectedPolicies = new HashSet();
+                childExpectedPolicies.add(pOid.getId());
+
+                PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
+                    index,
+                    childExpectedPolicies,
+                    node,
+                    pq,
+                    pOid.getId(),
+                    false);
+                node.addChild(child);
+                policyNodes[index].add(child);
+
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    protected static void processCertD1ii(
+        int index,
+        List[] policyNodes,
+        ASN1ObjectIdentifier _poid,
+        Set _pq)
+    {
+        List policyNodeVec = policyNodes[index - 1];
+
+        for (int j = 0; j < policyNodeVec.size(); j++)
+        {
+            PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j);
+
+            if (ANY_POLICY.equals(_node.getValidPolicy()))
+            {
+                Set _childExpectedPolicies = new HashSet();
+                _childExpectedPolicies.add(_poid.getId());
+
+                PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
+                    index,
+                    _childExpectedPolicies,
+                    _node,
+                    _pq,
+                    _poid.getId(),
+                    false);
+                _node.addChild(_child);
+                policyNodes[index].add(_child);
+                return;
+            }
+        }
+    }
+
+    protected static void prepareNextCertB1(
+        int i,
+        List[] policyNodes,
+        String id_p,
+        Map m_idp,
+        X509Certificate cert
+    )
+        throws AnnotatedException, CertPathValidatorException
+    {
+        boolean idp_found = false;
+        Iterator nodes_i = policyNodes[i].iterator();
+        while (nodes_i.hasNext())
+        {
+            PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+            if (node.getValidPolicy().equals(id_p))
+            {
+                idp_found = true;
+                node.expectedPolicies = (Set)m_idp.get(id_p);
+                break;
+            }
+        }
+
+        if (!idp_found)
+        {
+            nodes_i = policyNodes[i].iterator();
+            while (nodes_i.hasNext())
+            {
+                PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+                if (ANY_POLICY.equals(node.getValidPolicy()))
+                {
+                    Set pq = null;
+                    ASN1Sequence policies = null;
+                    try
+                    {
+                        policies = DERSequence.getInstance(getExtensionValue(cert, CERTIFICATE_POLICIES));
+                    }
+                    catch (Exception e)
+                    {
+                        throw new AnnotatedException("Certificate policies cannot be decoded.", e);
+                    }
+                    Enumeration e = policies.getObjects();
+                    while (e.hasMoreElements())
+                    {
+                        PolicyInformation pinfo = null;
+
+                        try
+                        {
+                            pinfo = PolicyInformation.getInstance(e.nextElement());
+                        }
+                        catch (Exception ex)
+                        {
+                            throw new AnnotatedException("Policy information cannot be decoded.", ex);
+                        }
+                        if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+                        {
+                            try
+                            {
+                                pq = getQualifierSet(pinfo.getPolicyQualifiers());
+                            }
+                            catch (CertPathValidatorException ex)
+                            {
+                                throw new ExtCertPathValidatorException(
+                                    "Policy qualifier info set could not be built.", ex);
+                            }
+                            break;
+                        }
+                    }
+                    boolean ci = false;
+                    if (cert.getCriticalExtensionOIDs() != null)
+                    {
+                        ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
+                    }
+
+                    PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+                    if (ANY_POLICY.equals(p_node.getValidPolicy()))
+                    {
+                        PKIXPolicyNode c_node = new PKIXPolicyNode(
+                            new ArrayList(), i,
+                            (Set)m_idp.get(id_p),
+                            p_node, pq, id_p, ci);
+                        p_node.addChild(c_node);
+                        policyNodes[i].add(c_node);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    protected static PKIXPolicyNode prepareNextCertB2(
+        int i,
+        List[] policyNodes,
+        String id_p,
+        PKIXPolicyNode validPolicyTree)
+    {
+        Iterator nodes_i = policyNodes[i].iterator();
+        while (nodes_i.hasNext())
+        {
+            PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+            if (node.getValidPolicy().equals(id_p))
+            {
+                PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+                p_node.removeChild(node);
+                nodes_i.remove();
+                for (int k = (i - 1); k >= 0; k--)
+                {
+                    List nodes = policyNodes[k];
+                    for (int l = 0; l < nodes.size(); l++)
+                    {
+                        PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+                        if (!node2.hasChildren())
+                        {
+                            validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2);
+                            if (validPolicyTree == null)
+                            {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return validPolicyTree;
+    }
+
+    protected static boolean isAnyPolicy(
+        Set policySet)
+    {
+        return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty();
+    }
+
+    /**
+     * Return a Collection of all certificates or attribute certificates found
+     * in the X509Store's that are matching the certSelect criteriums.
+     *
+     * @param certSelect a {@link Selector} object that will be used to select
+     *                   the certificates
+     * @param certStores a List containing only {@link Store} objects. These
+     *                   are used to search for certificates.
+     * @return a Collection of all found {@link X509Certificate}
+     *         May be empty but never <code>null</code>.
+     */
+    protected static Collection findCertificates(PKIXCertStoreSelector certSelect,
+                                                 List certStores)
+        throws AnnotatedException
+    {
+        Set certs = new LinkedHashSet();
+        Iterator iter = certStores.iterator();
+
+        while (iter.hasNext())
+        {
+            Object obj = iter.next();
+
+            // BEGIN Android-removed: Unknown reason
+            /*
+            if (obj instanceof Store)
+            {
+                Store certStore = (Store)obj;
+                try
+                {
+                    certs.addAll(certStore.getMatches(certSelect));
+                }
+                catch (StoreException e)
+                {
+                    throw new AnnotatedException(
+                            "Problem while picking certificates from X.509 store.", e);
+                }
+            }
+            else
+            */
+            // END Android-removed: Unknown reason
+            {
+                CertStore certStore = (CertStore)obj;
+
+                try
+                {
+                    certs.addAll(PKIXCertStoreSelector.getCertificates(certSelect, certStore));
+                }
+                catch (CertStoreException e)
+                {
+                    throw new AnnotatedException(
+                        "Problem while picking certificates from certificate store.",
+                        e);
+                }
+            }
+        }
+        return certs;
+    }
+
+    static List<PKIXCRLStore> getAdditionalStoresFromCRLDistributionPoint(CRLDistPoint crldp, Map<GeneralName, PKIXCRLStore> namedCRLStoreMap)
+        throws AnnotatedException
+    {
+        if (crldp != null)
+        {
+            DistributionPoint dps[] = null;
+            try
+            {
+                dps = crldp.getDistributionPoints();
+            }
+            catch (Exception e)
+            {
+                throw new AnnotatedException(
+                    "Distribution points could not be read.", e);
+            }
+            List<PKIXCRLStore> stores = new ArrayList<PKIXCRLStore>();
+
+            for (int i = 0; i < dps.length; i++)
+            {
+                DistributionPointName dpn = dps[i].getDistributionPoint();
+                // look for URIs in fullName
+                if (dpn != null)
+                {
+                    if (dpn.getType() == DistributionPointName.FULL_NAME)
+                    {
+                        GeneralName[] genNames = GeneralNames.getInstance(
+                            dpn.getName()).getNames();
+
+                        for (int j = 0; j < genNames.length; j++)
+                        {
+                            PKIXCRLStore store = namedCRLStoreMap.get(genNames[j]);
+                            if (store != null)
+                            {
+                                stores.add(store);
+                            }
+                        }
+                    }
+                }
+            }
+
+            return stores;
+        }
+        else
+        {
+            return Collections.EMPTY_LIST;
+        }
+    }
+
+    /**
+     * Add the CRL issuers from the cRLIssuer field of the distribution point or
+     * from the certificate if not given to the issuer criterion of the
+     * <code>selector</code>.
+     * <p>
+     * The <code>issuerPrincipals</code> are a collection with a single
+     * <code>X500Name</code> for <code>X509Certificate</code>s.
+     * </p>
+     * @param dp               The distribution point.
+     * @param issuerPrincipals The issuers of the certificate or attribute
+     *                         certificate which contains the distribution point.
+     * @param selector         The CRL selector.
+     * @throws AnnotatedException if an exception occurs while processing.
+     * @throws ClassCastException if <code>issuerPrincipals</code> does not
+     * contain only <code>X500Name</code>s.
+     */
+    protected static void getCRLIssuersFromDistributionPoint(
+        DistributionPoint dp,
+        Collection issuerPrincipals,
+        X509CRLSelector selector)
+        throws AnnotatedException
+    {
+        List issuers = new ArrayList();
+        // indirect CRL
+        if (dp.getCRLIssuer() != null)
+        {
+            GeneralName genNames[] = dp.getCRLIssuer().getNames();
+            // look for a DN
+            for (int j = 0; j < genNames.length; j++)
+            {
+                if (genNames[j].getTagNo() == GeneralName.directoryName)
+                {
+                    try
+                    {
+                        issuers.add(X500Name.getInstance(genNames[j].getName()
+                            .toASN1Primitive().getEncoded()));
+                    }
+                    catch (IOException e)
+                    {
+                        throw new AnnotatedException(
+                            "CRL issuer information from distribution point cannot be decoded.",
+                            e);
+                    }
+                }
+            }
+        }
+        else
+        {
+            /*
+             * certificate issuer is CRL issuer, distributionPoint field MUST be
+             * present.
+             */
+            if (dp.getDistributionPoint() == null)
+            {
+                throw new AnnotatedException(
+                    "CRL issuer is omitted from distribution point but no distributionPoint field present.");
+            }
+            // add and check issuer principals
+            for (Iterator it = issuerPrincipals.iterator(); it.hasNext(); )
+            {
+                issuers.add(it.next());
+            }
+        }
+        // TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid
+        // distributionPoint
+//        if (dp.getDistributionPoint() != null)
+//        {
+//            // look for nameRelativeToCRLIssuer
+//            if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+//            {
+//                // append fragment to issuer, only one
+//                // issuer can be there, if this is given
+//                if (issuers.size() != 1)
+//                {
+//                    throw new AnnotatedException(
+//                        "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
+//                }
+//                ASN1Encodable relName = dp.getDistributionPoint().getName();
+//                Iterator it = issuers.iterator();
+//                List issuersTemp = new ArrayList(issuers.size());
+//                while (it.hasNext())
+//                {
+//                    Enumeration e = null;
+//                    try
+//                    {
+//                        e = ASN1Sequence.getInstance(
+//                            new ASN1InputStream(((X500Principal) it.next())
+//                                .getEncoded()).readObject()).getObjects();
+//                    }
+//                    catch (IOException ex)
+//                    {
+//                        throw new AnnotatedException(
+//                            "Cannot decode CRL issuer information.", ex);
+//                    }
+//                    ASN1EncodableVector v = new ASN1EncodableVector();
+//                    while (e.hasMoreElements())
+//                    {
+//                        v.add((ASN1Encodable) e.nextElement());
+//                    }
+//                    v.add(relName);
+//                    issuersTemp.add(new X500Principal(new DERSequence(v)
+//                        .getDEREncoded()));
+//                }
+//                issuers.clear();
+//                issuers.addAll(issuersTemp);
+//            }
+//        }
+        Iterator it = issuers.iterator();
+        while (it.hasNext())
+        {
+            try
+            {
+                selector.addIssuerName(((X500Name)it.next()).getEncoded());
+            }
+            catch (IOException ex)
+            {
+                throw new AnnotatedException(
+                    "Cannot decode CRL issuer information.", ex);
+            }
+        }
+    }
+
+    private static BigInteger getSerialNumber(
+        Object cert)
+    {
+        return ((X509Certificate)cert).getSerialNumber();
+    }
+
+    protected static void getCertStatus(
+        Date validDate,
+        X509CRL crl,
+        Object cert,
+        CertStatus certStatus)
+        throws AnnotatedException
+    {
+        X509CRLEntry crl_entry = null;
+
+        boolean isIndirect;
+        try
+        {
+            isIndirect = X509CRLObject.isIndirectCRL(crl);
+        }
+        catch (CRLException exception)
+        {
+            throw new AnnotatedException("Failed check for indirect CRL.", exception);
+        }
+
+        if (isIndirect)
+        {
+            crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+            if (crl_entry == null)
+            {
+                return;
+            }
+
+            X500Principal certificateIssuer = crl_entry.getCertificateIssuer();
+
+            X500Name certIssuer;
+            if (certificateIssuer == null)
+            {
+                certIssuer = PrincipalUtils.getIssuerPrincipal(crl);
+            }
+            else
+            {
+                certIssuer = X500Name.getInstance(certificateIssuer.getEncoded());
+            }
+
+            if (! PrincipalUtils.getEncodedIssuerPrincipal(cert).equals(certIssuer))
+            {
+                return;
+            }
+        }
+        else if (! PrincipalUtils.getEncodedIssuerPrincipal(cert).equals(PrincipalUtils.getIssuerPrincipal(crl)))
+        {
+            return;  // not for our issuer, ignore
+        }
+        else
+        {
+            crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+            if (crl_entry == null)
+            {
+                return;
+            }
+        }
+
+        ASN1Enumerated reasonCode = null;
+        if (crl_entry.hasExtensions())
+        {
+            try
+            {
+                reasonCode = ASN1Enumerated
+                    .getInstance(CertPathValidatorUtilities
+                        .getExtensionValue(crl_entry,
+                            Extension.reasonCode.getId()));
+            }
+            catch (Exception e)
+            {
+                throw new AnnotatedException(
+                    "Reason code CRL entry extension could not be decoded.",
+                    e);
+            }
+        }
+
+        // for reason keyCompromise, caCompromise, aACompromise or
+        // unspecified
+        if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime())
+            || reasonCode == null
+            || reasonCode.getValue().intValue() == 0
+            || reasonCode.getValue().intValue() == 1
+            || reasonCode.getValue().intValue() == 2
+            || reasonCode.getValue().intValue() == 8)
+        {
+
+            // (i) or (j) (1)
+            if (reasonCode != null)
+            {
+                certStatus.setCertStatus(reasonCode.getValue().intValue());
+            }
+            // (i) or (j) (2)
+            else
+            {
+                certStatus.setCertStatus(CRLReason.unspecified);
+            }
+            certStatus.setRevocationDate(crl_entry.getRevocationDate());
+        }
+    }
+
+    /**
+     * Fetches delta CRLs according to RFC 3280 section 5.2.4.
+     *
+     * @param validityDate The date for which the delta CRLs must be valid.
+     * @param completeCRL The complete CRL the delta CRL is for.
+     * @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
+     * @throws AnnotatedException if an exception occurs while picking the delta
+     * CRLs.
+     */
+    protected static Set getDeltaCRLs(Date validityDate,
+                                      X509CRL completeCRL, List<CertStore> certStores, List<PKIXCRLStore> pkixCrlStores)
+        throws AnnotatedException
+    {
+        X509CRLSelector baseDeltaSelect = new X509CRLSelector();
+        // 5.2.4 (a)
+        try
+        {
+            baseDeltaSelect.addIssuerName(PrincipalUtils.getIssuerPrincipal(completeCRL).getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new AnnotatedException("Cannot extract issuer from CRL.", e);
+        }
+
+
+
+        BigInteger completeCRLNumber = null;
+        try
+        {
+            ASN1Primitive derObject = CertPathValidatorUtilities.getExtensionValue(completeCRL,
+                CRL_NUMBER);
+            if (derObject != null)
+            {
+                completeCRLNumber = ASN1Integer.getInstance(derObject).getPositiveValue();
+            }
+        }
+        catch (Exception e)
+        {
+            throw new AnnotatedException(
+                "CRL number extension could not be extracted from CRL.", e);
+        }
+
+        // 5.2.4 (b)
+        byte[] idp = null;
+        try
+        {
+            idp = completeCRL.getExtensionValue(ISSUING_DISTRIBUTION_POINT);
+        }
+        catch (Exception e)
+        {
+            throw new AnnotatedException(
+                "Issuing distribution point extension value could not be read.",
+                e);
+        }
+
+        // 5.2.4 (d)
+
+        baseDeltaSelect.setMinCRLNumber(completeCRLNumber == null ? null : completeCRLNumber
+            .add(BigInteger.valueOf(1)));
+
+        PKIXCRLStoreSelector.Builder selBuilder = new PKIXCRLStoreSelector.Builder(baseDeltaSelect);
+
+        selBuilder.setIssuingDistributionPoint(idp);
+        selBuilder.setIssuingDistributionPointEnabled(true);
+
+        // 5.2.4 (c)
+        selBuilder.setMaxBaseCRLNumber(completeCRLNumber);
+
+        PKIXCRLStoreSelector deltaSelect = selBuilder.build();
+
+        // find delta CRLs
+        Set temp = CRL_UTIL.findCRLs(deltaSelect, validityDate, certStores, pkixCrlStores);
+
+        Set result = new HashSet();
+
+        for (Iterator it = temp.iterator(); it.hasNext(); )
+        {
+            X509CRL crl = (X509CRL)it.next();
+
+            if (isDeltaCRL(crl))
+            {
+                result.add(crl);
+            }
+        }
+
+        return result;
+    }
+
+    private static boolean isDeltaCRL(X509CRL crl)
+    {
+        Set critical = crl.getCriticalExtensionOIDs();
+
+        if (critical == null)
+        {
+            return false;
+        }
+
+        return critical.contains(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+    }
+
+    /**
+     * Fetches complete CRLs according to RFC 3280.
+     *
+     * @param dp          The distribution point for which the complete CRL
+     * @param cert        The <code>X509Certificate</code> for
+     *                    which the CRL should be searched.
+     * @param currentDate The date for which the delta CRLs must be valid.
+     * @param paramsPKIX  The extended PKIX parameters.
+     * @return A <code>Set</code> of <code>X509CRL</code>s with complete
+     *         CRLs.
+     * @throws AnnotatedException if an exception occurs while picking the CRLs
+     * or no CRLs are found.
+     */
+    protected static Set getCompleteCRLs(DistributionPoint dp, Object cert,
+                                         Date currentDate, PKIXExtendedParameters paramsPKIX)
+        throws AnnotatedException
+    {
+        X509CRLSelector baseCrlSelect = new X509CRLSelector();
+
+        try
+        {
+            Set issuers = new HashSet();
+
+            issuers.add(PrincipalUtils.getEncodedIssuerPrincipal(cert));
+
+            CertPathValidatorUtilities.getCRLIssuersFromDistributionPoint(dp, issuers, baseCrlSelect);
+        }
+        catch (AnnotatedException e)
+        {
+            throw new AnnotatedException(
+                "Could not get issuer information from distribution point.", e);
+        }
+
+        if (cert instanceof X509Certificate)
+        {
+            baseCrlSelect.setCertificateChecking((X509Certificate)cert);
+        }
+
+        PKIXCRLStoreSelector crlSelect = new PKIXCRLStoreSelector.Builder(baseCrlSelect).setCompleteCRLEnabled(true).build();
+
+        Date validityDate = currentDate;
+
+        if (paramsPKIX.getDate() != null)
+        {
+            validityDate = paramsPKIX.getDate();
+        }
+
+        Set crls = CRL_UTIL.findCRLs(crlSelect, validityDate, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores());
+
+        checkCRLsNotEmpty(crls, cert);
+
+        return crls;
+    }
+
+    protected static Date getValidCertDateFromValidityModel(
+        PKIXExtendedParameters paramsPKIX, CertPath certPath, int index)
+        throws AnnotatedException
+    {
+        if (paramsPKIX.getValidityModel() == PKIXExtendedParameters.CHAIN_VALIDITY_MODEL)
+        {
+            // if end cert use given signing/encryption/... time
+            if (index <= 0)
+            {
+                return CertPathValidatorUtilities.getValidDate(paramsPKIX);
+                // else use time when previous cert was created
+            }
+            else
+            {
+                if (index - 1 == 0)
+                {
+                    ASN1GeneralizedTime dateOfCertgen = null;
+                    try
+                    {
+                        byte[] extBytes = ((X509Certificate)certPath.getCertificates().get(index - 1)).getExtensionValue(ISISMTTObjectIdentifiers.id_isismtt_at_dateOfCertGen.getId());
+                        if (extBytes != null)
+                        {
+                            dateOfCertgen = ASN1GeneralizedTime.getInstance(ASN1Primitive.fromByteArray(extBytes));
+                        }
+                    }
+                    catch (IOException e)
+                    {
+                        throw new AnnotatedException(
+                            "Date of cert gen extension could not be read.");
+                    }
+                    catch (IllegalArgumentException e)
+                    {
+                        throw new AnnotatedException(
+                            "Date of cert gen extension could not be read.");
+                    }
+                    if (dateOfCertgen != null)
+                    {
+                        try
+                        {
+                            return dateOfCertgen.getDate();
+                        }
+                        catch (ParseException e)
+                        {
+                            throw new AnnotatedException(
+                                "Date from date of cert gen extension could not be parsed.",
+                                e);
+                        }
+                    }
+                    return ((X509Certificate)certPath.getCertificates().get(
+                        index - 1)).getNotBefore();
+                }
+                else
+                {
+                    return ((X509Certificate)certPath.getCertificates().get(
+                        index - 1)).getNotBefore();
+                }
+            }
+        }
+        else
+        {
+            return getValidDate(paramsPKIX);
+        }
+    }
+
+    /**
+     * Return the next working key inheriting DSA parameters if necessary.
+     * <p>
+     * This methods inherits DSA parameters from the indexed certificate or
+     * previous certificates in the certificate chain to the returned
+     * <code>PublicKey</code>. The list is searched upwards, meaning the end
+     * certificate is at position 0 and previous certificates are following.
+     * </p>
+     * <p>
+     * If the indexed certificate does not contain a DSA key this method simply
+     * returns the public key. If the DSA key already contains DSA parameters
+     * the key is also only returned.
+     * </p>
+     *
+     * @param certs The certification path.
+     * @param index The index of the certificate which contains the public key
+     *              which should be extended with DSA parameters.
+     * @return The public key of the certificate in list position
+     *         <code>index</code> extended with DSA parameters if applicable.
+     * @throws AnnotatedException if DSA parameters cannot be inherited.
+     */
+    protected static PublicKey getNextWorkingKey(List certs, int index, JcaJceHelper helper)
+        throws CertPathValidatorException
+    {
+        Certificate cert = (Certificate)certs.get(index);
+        PublicKey pubKey = cert.getPublicKey();
+        if (!(pubKey instanceof DSAPublicKey))
+        {
+            return pubKey;
+        }
+        DSAPublicKey dsaPubKey = (DSAPublicKey)pubKey;
+        if (dsaPubKey.getParams() != null)
+        {
+            return dsaPubKey;
+        }
+        for (int i = index + 1; i < certs.size(); i++)
+        {
+            X509Certificate parentCert = (X509Certificate)certs.get(i);
+            pubKey = parentCert.getPublicKey();
+            if (!(pubKey instanceof DSAPublicKey))
+            {
+                throw new CertPathValidatorException(
+                    "DSA parameters cannot be inherited from previous certificate.");
+            }
+            DSAPublicKey prevDSAPubKey = (DSAPublicKey)pubKey;
+            if (prevDSAPubKey.getParams() == null)
+            {
+                continue;
+            }
+            DSAParams dsaParams = prevDSAPubKey.getParams();
+            DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(
+                dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
+            try
+            {
+                KeyFactory keyFactory = helper.createKeyFactory("DSA");
+                return keyFactory.generatePublic(dsaPubKeySpec);
+            }
+            catch (Exception exception)
+            {
+                throw new RuntimeException(exception.getMessage());
+            }
+        }
+        throw new CertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
+    }
+
+    /**
+     * Find the issuer certificates of a given certificate.
+     *
+     * @param cert       The certificate for which an issuer should be found.
+     * @return A <code>Collection</code> object containing the issuer
+     *         <code>X509Certificate</code>s. Never <code>null</code>.
+     * @throws AnnotatedException if an error occurs.
+     */
+    static Collection findIssuerCerts(
+        X509Certificate cert,
+        List<CertStore> certStores,
+        List<PKIXCertStore> pkixCertStores)
+        throws AnnotatedException
+    {
+        X509CertSelector selector = new X509CertSelector();
+
+        try
+        {
+            selector.setSubject(PrincipalUtils.getIssuerPrincipal(cert).getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new AnnotatedException(
+                           "Subject criteria for certificate selector to find issuer certificate could not be set.", e);
+        }
+
+        try
+        {
+            byte[] akiExtensionValue = cert.getExtensionValue(AUTHORITY_KEY_IDENTIFIER);
+            if (akiExtensionValue != null)
+            {
+                ASN1OctetString aki = ASN1OctetString.getInstance(akiExtensionValue);
+                byte[] authorityKeyIdentifier = AuthorityKeyIdentifier.getInstance(aki.getOctets()).getKeyIdentifier();
+                if (authorityKeyIdentifier != null)
+                {
+                    selector.setSubjectKeyIdentifier(new DEROctetString(authorityKeyIdentifier).getEncoded());
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            // authority key identifier could not be retrieved from target cert, just search without it
+        }
+
+        PKIXCertStoreSelector certSelect = new PKIXCertStoreSelector.Builder(selector).build();
+        Set certs = new LinkedHashSet();
+
+        Iterator iter;
+
+        try
+        {
+            List matches = new ArrayList();
+
+            matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, certStores));
+            matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixCertStores));
+
+            iter = matches.iterator();
+        }
+        catch (AnnotatedException e)
+        {
+            throw new AnnotatedException("Issuer certificate cannot be searched.", e);
+        }
+
+        X509Certificate issuer = null;
+        while (iter.hasNext())
+        {
+            issuer = (X509Certificate)iter.next();
+            // issuer cannot be verified because possible DSA inheritance
+            // parameters are missing
+            certs.add(issuer);
+        }
+        return certs;
+    }
+
+    protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey,
+                                                String sigProvider)
+        throws GeneralSecurityException
+    {
+        if (sigProvider == null)
+        {
+            cert.verify(publicKey);
+        }
+        else
+        {
+            cert.verify(publicKey, sigProvider);
+        }
+    }
+
+    static void checkCRLsNotEmpty(Set crls, Object cert)
+        throws AnnotatedException
+    {
+        if (crls.isEmpty())
+        {
+            if (cert instanceof X509AttributeCertificate)
+            {
+                X509AttributeCertificate aCert = (X509AttributeCertificate)cert;
+
+                throw new AnnotatedException("No CRLs found for issuer \"" + aCert.getIssuer().getPrincipals()[0] + "\"");
+            }
+            else
+            {
+                X509Certificate xCert = (X509Certificate)cert;
+
+                throw new AnnotatedException("No CRLs found for issuer \"" + RFC4519Style.INSTANCE.toString(PrincipalUtils.getIssuerPrincipal(xCert)) + "\"");
+            }
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertStatus.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertStatus.java
new file mode 100644
index 0000000..2b616ac
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertStatus.java
@@ -0,0 +1,47 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.util.Date;
+
+class CertStatus
+{
+    public static final int UNREVOKED = 11;
+
+    public static final int UNDETERMINED = 12;
+
+    int certStatus = UNREVOKED;
+
+    Date revocationDate = null;
+
+    /**
+     * @return Returns the revocationDate.
+     */
+    public Date getRevocationDate()
+    {
+        return revocationDate;
+    }
+
+    /**
+     * @param revocationDate The revocationDate to set.
+     */
+    public void setRevocationDate(Date revocationDate)
+    {
+        this.revocationDate = revocationDate;
+    }
+
+    /**
+     * @return Returns the certStatus.
+     */
+    public int getCertStatus()
+    {
+        return certStatus;
+    }
+
+    /**
+     * @param certStatus The certStatus to set.
+     */
+    public void setCertStatus(int certStatus)
+    {
+        this.certStatus = certStatus;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertStoreCollectionSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertStoreCollectionSpi.java
new file mode 100644
index 0000000..5c29a24
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/CertStoreCollectionSpi.java
@@ -0,0 +1,108 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CRL;
+import java.security.cert.CRLSelector;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertStoreSpi;
+import java.security.cert.Certificate;
+import java.security.cert.CollectionCertStoreParameters;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CertStoreCollectionSpi extends CertStoreSpi
+{
+    private CollectionCertStoreParameters params;
+
+    public CertStoreCollectionSpi(CertStoreParameters params)
+        throws InvalidAlgorithmParameterException
+    {
+        super(params);
+
+        if (!(params instanceof CollectionCertStoreParameters))
+        {
+            throw new InvalidAlgorithmParameterException("com.android.internal.org.bouncycastle.jce.provider.CertStoreCollectionSpi: parameter must be a CollectionCertStoreParameters object\n" +  params.toString());
+        }
+
+        this.params = (CollectionCertStoreParameters)params;
+    }
+
+    public Collection engineGetCertificates(
+        CertSelector selector)
+        throws CertStoreException 
+    {
+        List        col = new ArrayList();
+        Iterator    iter = params.getCollection().iterator();
+
+        if (selector == null)
+        {
+            while (iter.hasNext())
+            {
+                Object obj = iter.next();
+
+                if (obj instanceof Certificate)
+                {
+                    col.add(obj);
+                }
+            }
+        }
+        else
+        {
+            while (iter.hasNext())
+            {
+                Object obj = iter.next();
+
+                if ((obj instanceof Certificate) && selector.match((Certificate)obj))
+                {
+                    col.add(obj);
+                }
+            }
+        }
+        
+        return col;
+    }
+    
+
+    public Collection engineGetCRLs(
+        CRLSelector selector)
+        throws CertStoreException 
+    {
+        List        col = new ArrayList();
+        Iterator    iter = params.getCollection().iterator();
+
+        if (selector == null)
+        {
+            while (iter.hasNext())
+            {
+                Object obj = iter.next();
+
+                if (obj instanceof CRL)
+                {
+                    col.add(obj);
+                }
+            }
+        }
+        else
+        {
+            while (iter.hasNext())
+            {
+                Object obj = iter.next();
+
+                if ((obj instanceof CRL) && selector.match((CRL)obj))
+                {
+                    col.add(obj);
+                }
+            }
+        }
+        
+        return col;
+    }    
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/DHUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/DHUtil.java
new file mode 100644
index 0000000..77ba6b3
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/DHUtil.java
@@ -0,0 +1,52 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import com.android.internal.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.android.internal.org.bouncycastle.crypto.params.DHParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.crypto.params.DHPublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca DH objects
+ * objects into their org.bouncycastle.crypto counterparts.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DHUtil
+{
+    static public AsymmetricKeyParameter generatePublicKeyParameter(
+        PublicKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DHPublicKey)
+        {
+            DHPublicKey    k = (DHPublicKey)key;
+
+            return new DHPublicKeyParameters(k.getY(),
+                new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+        }
+
+        throw new InvalidKeyException("can't identify DH public key.");
+    }
+
+    static public AsymmetricKeyParameter generatePrivateKeyParameter(
+        PrivateKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DHPrivateKey)
+        {
+            DHPrivateKey    k = (DHPrivateKey)key;
+
+            return new DHPrivateKeyParameters(k.getX(),
+                new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+        }
+                        
+        throw new InvalidKeyException("can't identify DH private key.");
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/ExtCRLException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/ExtCRLException.java
new file mode 100644
index 0000000..54b357a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/ExtCRLException.java
@@ -0,0 +1,21 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.security.cert.CRLException;
+
+class ExtCRLException
+    extends CRLException
+{
+    Throwable cause;
+
+    ExtCRLException(String message, Throwable cause)
+    {
+        super(message);
+        this.cause = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEDHPrivateKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
new file mode 100644
index 0000000..18c6e32
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
@@ -0,0 +1,191 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPrivateKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.pkcs.DHParameter;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x9.DHDomainParameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import com.android.internal.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class JCEDHPrivateKey
+    implements DHPrivateKey, PKCS12BagAttributeCarrier
+{
+    static final long serialVersionUID = 311058815616901812L;
+    
+    BigInteger      x;
+
+    private DHParameterSpec dhSpec;
+    private PrivateKeyInfo  info;
+
+    private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected JCEDHPrivateKey()
+    {
+    }
+
+    JCEDHPrivateKey(
+        DHPrivateKey    key)
+    {
+        this.x = key.getX();
+        this.dhSpec = key.getParams();
+    }
+
+    JCEDHPrivateKey(
+        DHPrivateKeySpec    spec)
+    {
+        this.x = spec.getX();
+        this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+    }
+
+    JCEDHPrivateKey(
+        PrivateKeyInfo  info)
+        throws IOException
+    {
+        ASN1Sequence    seq = ASN1Sequence.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+        ASN1Integer      derX = ASN1Integer.getInstance(info.parsePrivateKey());
+        ASN1ObjectIdentifier id = info.getPrivateKeyAlgorithm().getAlgorithm();
+
+        this.info = info;
+        this.x = derX.getValue();
+
+        if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+            DHParameter params = DHParameter.getInstance(seq);
+
+            if (params.getL() != null)
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+            }
+            else
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+            }
+        }
+        else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+            this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown algorithm type: " + id);
+        }
+    }
+
+    JCEDHPrivateKey(
+        DHPrivateKeyParameters  params)
+    {
+        this.x = params.getX();
+        this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+    }
+
+    public String getAlgorithm()
+    {
+        return "DH";
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        try
+        {
+            if (info != null)
+            {
+                return info.getEncoded(ASN1Encoding.DER);
+            }
+
+            PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new ASN1Integer(getX()));
+
+            return info.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+
+    public DHParameterSpec getParams()
+    {
+        return dhSpec;
+    }
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+
+    private void readObject(
+        ObjectInputStream   in)
+        throws IOException, ClassNotFoundException
+    {
+        x = (BigInteger)in.readObject();
+
+        this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+    }
+
+    private void writeObject(
+        ObjectOutputStream  out)
+        throws IOException
+    {
+        out.writeObject(this.getX());
+        out.writeObject(dhSpec.getP());
+        out.writeObject(dhSpec.getG());
+        out.writeInt(dhSpec.getL());
+    }
+
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        ASN1ObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEDHPublicKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEDHPublicKey.java
new file mode 100644
index 0000000..f15f091
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEDHPublicKey.java
@@ -0,0 +1,182 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.pkcs.DHParameter;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.DHDomainParameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class JCEDHPublicKey
+    implements DHPublicKey
+{
+    static final long serialVersionUID = -216691575254424324L;
+    
+    private BigInteger              y;
+    private DHParameterSpec         dhSpec;
+    private SubjectPublicKeyInfo    info;
+    
+    JCEDHPublicKey(
+        DHPublicKeySpec    spec)
+    {
+        this.y = spec.getY();
+        this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+    }
+
+    JCEDHPublicKey(
+        DHPublicKey    key)
+    {
+        this.y = key.getY();
+        this.dhSpec = key.getParams();
+    }
+
+    JCEDHPublicKey(
+        DHPublicKeyParameters  params)
+    {
+        this.y = params.getY();
+        this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+    }
+
+    JCEDHPublicKey(
+        BigInteger        y,
+        DHParameterSpec   dhSpec)
+    {
+        this.y = y;
+        this.dhSpec = dhSpec;
+    }
+
+    JCEDHPublicKey(
+        SubjectPublicKeyInfo    info)
+    {
+        this.info = info;
+
+        ASN1Integer              derY;
+        try
+        {
+            derY = (ASN1Integer)info.parsePublicKey();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("invalid info structure in DH public key");
+        }
+
+        this.y = derY.getValue();
+
+        ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters());
+        ASN1ObjectIdentifier id = info.getAlgorithmId().getAlgorithm();
+
+        // we need the PKCS check to handle older keys marked with the X9 oid.
+        if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement) || isPKCSParam(seq))
+        {
+            DHParameter             params = DHParameter.getInstance(seq);
+
+            if (params.getL() != null)
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+            }
+            else
+            {
+                this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+            }
+        }
+        else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+            this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown algorithm type: " + id);
+        }
+    }
+
+    public String getAlgorithm()
+    {
+        return "DH";
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        if (info != null)
+        {
+            return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+        }
+
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new ASN1Integer(y));
+    }
+
+    public DHParameterSpec getParams()
+    {
+        return dhSpec;
+    }
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+
+    private boolean isPKCSParam(ASN1Sequence seq)
+    {
+        if (seq.size() == 2)
+        {
+            return true;
+        }
+        
+        if (seq.size() > 3)
+        {
+            return false;
+        }
+
+        ASN1Integer l = ASN1Integer.getInstance(seq.getObjectAt(2));
+        ASN1Integer p = ASN1Integer.getInstance(seq.getObjectAt(0));
+
+        if (l.getValue().compareTo(BigInteger.valueOf(p.getValue().bitLength())) > 0)
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    private void readObject(
+        ObjectInputStream   in)
+        throws IOException, ClassNotFoundException
+    {
+        this.y = (BigInteger)in.readObject();
+        this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+    }
+
+    private void writeObject(
+        ObjectOutputStream  out)
+        throws IOException
+    {
+        out.writeObject(this.getY());
+        out.writeObject(dhSpec.getP());
+        out.writeObject(dhSpec.getG());
+        out.writeInt(dhSpec.getL());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEECPrivateKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEECPrivateKey.java
new file mode 100644
index 0000000..092b13e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEECPrivateKey.java
@@ -0,0 +1,475 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.EllipticCurve;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.X962Parameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import com.android.internal.org.bouncycastle.jce.interfaces.ECPointEncoder;
+import com.android.internal.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class JCEECPrivateKey
+    implements ECPrivateKey, com.android.internal.org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+    private String          algorithm = "EC";
+    private BigInteger      d;
+    private ECParameterSpec ecSpec;
+    private boolean         withCompression;
+
+    private DERBitString publicKey;
+
+    private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected JCEECPrivateKey()
+    {
+    }
+
+    public JCEECPrivateKey(
+        ECPrivateKey    key)
+    {
+        this.d = key.getS();
+        this.algorithm = key.getAlgorithm();
+        this.ecSpec = key.getParams();
+    }
+
+    public JCEECPrivateKey(
+        String              algorithm,
+        com.android.internal.org.bouncycastle.jce.spec.ECPrivateKeySpec     spec)
+    {
+        this.algorithm = algorithm;
+        this.d = spec.getD();
+
+        if (spec.getParams() != null) // can be null if implicitlyCA
+        {
+            ECCurve curve = spec.getParams().getCurve();
+            EllipticCurve ellipticCurve;
+
+            ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+        }
+        else
+        {
+            this.ecSpec = null;
+        }
+    }
+
+
+    public JCEECPrivateKey(
+        String              algorithm,
+        ECPrivateKeySpec    spec)
+    {
+        this.algorithm = algorithm;
+        this.d = spec.getS();
+        this.ecSpec = spec.getParams();
+    }
+
+    public JCEECPrivateKey(
+        String             algorithm,
+        JCEECPrivateKey    key)
+    {
+        this.algorithm = algorithm;
+        this.d = key.d;
+        this.ecSpec = key.ecSpec;
+        this.withCompression = key.withCompression;
+        this.attrCarrier = key.attrCarrier;
+        this.publicKey = key.publicKey;
+    }
+
+    public JCEECPrivateKey(
+        String                  algorithm,
+        ECPrivateKeyParameters  params,
+        JCEECPublicKey          pubKey,
+        ECParameterSpec         spec)
+    {
+        this.algorithm = algorithm;
+        this.d = params.getD();
+
+        if (spec == null)
+        {
+            ECDomainParameters dp = params.getParameters();
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                ellipticCurve,
+                EC5Util.convertPoint(dp.getG()),
+                dp.getN(),
+                dp.getH().intValue());
+        }
+        else
+        {
+            this.ecSpec = spec;
+        }
+
+        publicKey = getPublicKeyDetails(pubKey);
+    }
+
+    public JCEECPrivateKey(
+        String                  algorithm,
+        ECPrivateKeyParameters  params,
+        JCEECPublicKey          pubKey,
+        com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec         spec)
+    {
+        this.algorithm = algorithm;
+        this.d = params.getD();
+
+        if (spec == null)
+        {
+            ECDomainParameters dp = params.getParameters();
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                ellipticCurve,
+                EC5Util.convertPoint(dp.getG()),
+                dp.getN(),
+                dp.getH().intValue());
+        }
+        else
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+            
+            this.ecSpec = new ECParameterSpec(
+                ellipticCurve,
+                EC5Util.convertPoint(spec.getG()),
+                spec.getN(),
+                spec.getH().intValue());
+        }
+
+        publicKey = getPublicKeyDetails(pubKey);
+    }
+
+    public JCEECPrivateKey(
+        String                  algorithm,
+        ECPrivateKeyParameters  params)
+    {
+        this.algorithm = algorithm;
+        this.d = params.getD();
+        this.ecSpec = null;
+    }
+
+    JCEECPrivateKey(
+        PrivateKeyInfo      info)
+        throws IOException
+    {
+        populateFromPrivKeyInfo(info);
+    }
+
+    private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+        throws IOException
+    {
+        X962Parameters params = new X962Parameters((ASN1Primitive)info.getPrivateKeyAlgorithm().getParameters());
+
+        if (params.isNamedCurve())
+        {
+            ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+            X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            if (ecP == null) // GOST Curve
+            {
+                ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
+                EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
+
+                ecSpec = new ECNamedCurveSpec(
+                    ECGOST3410NamedCurves.getName(oid),
+                    ellipticCurve,
+                    EC5Util.convertPoint(gParam.getG()),
+                    gParam.getN(),
+                    gParam.getH());
+            }
+            else
+            */
+            // END Android-removed: Unsupported algorithms
+            {
+                EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+                ecSpec = new ECNamedCurveSpec(
+                    ECUtil.getCurveName(oid),
+                    ellipticCurve,
+                    EC5Util.convertPoint(ecP.getG()),
+                    ecP.getN(),
+                    ecP.getH());
+            }
+        }
+        else if (params.isImplicitlyCA())
+        {
+            ecSpec = null;
+        }
+        else
+        {
+            X9ECParameters      ecP = X9ECParameters.getInstance(params.getParameters());
+            EllipticCurve       ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+            this.ecSpec = new ECParameterSpec(
+                ellipticCurve,
+                EC5Util.convertPoint(ecP.getG()),
+                ecP.getN(),
+                ecP.getH().intValue());
+        }
+
+        ASN1Encodable privKey = info.parsePrivateKey();
+        if (privKey instanceof ASN1Integer)
+        {
+            ASN1Integer          derD = ASN1Integer.getInstance(privKey);
+
+            this.d = derD.getValue();
+        }
+        else
+        {
+            ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)privKey);
+
+            this.d = ec.getKey();
+            this.publicKey = ec.getPublicKey();
+        }
+    }
+
+    public String getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        X962Parameters          params;
+
+        if (ecSpec instanceof ECNamedCurveSpec)
+        {
+            ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+            if (curveOid == null)  // guess it's the OID
+            {
+                curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+            }
+            params = new X962Parameters(curveOid);
+        }
+        else if (ecSpec == null)
+        {
+            params = new X962Parameters(DERNull.INSTANCE);
+        }
+        else
+        {
+            ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+            X9ECParameters ecP = new X9ECParameters(
+                curve,
+                EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+                ecSpec.getOrder(),
+                BigInteger.valueOf(ecSpec.getCofactor()),
+                ecSpec.getCurve().getSeed());
+
+            params = new X962Parameters(ecP);
+        }
+        
+        PrivateKeyInfo          info;
+        ECPrivateKeyStructure keyStructure;
+
+        if (publicKey != null)
+        {
+            keyStructure = new ECPrivateKeyStructure(this.getS(), publicKey, params);
+        }
+        else
+        {
+            keyStructure = new ECPrivateKeyStructure(this.getS(), params);
+        }
+
+        try
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            // if (algorithm.equals("ECGOST3410"))
+            // {
+            //     info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+            // }
+            // else
+            // END Android-removed: Unsupported algorithms
+            {
+
+                info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+            }
+
+            return info.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+
+    public ECParameterSpec getParams()
+    {
+        return ecSpec;
+    }
+
+    public com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+    {
+        if (ecSpec == null)
+        {
+            return null;
+        }
+        
+        return EC5Util.convertSpec(ecSpec, withCompression);
+    }
+
+    com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+    {
+        if (ecSpec != null)
+        {
+            return EC5Util.convertSpec(ecSpec, withCompression);
+        }
+
+        return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+    }
+
+    public BigInteger getS()
+    {
+        return d;
+    }
+
+    public BigInteger getD()
+    {
+        return d;
+    }
+    
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable        attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        ASN1ObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    public void setPointFormat(String style)
+    {
+       withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof JCEECPrivateKey))
+        {
+            return false;
+        }
+
+        JCEECPrivateKey other = (JCEECPrivateKey)o;
+
+        return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+    }
+
+    public int hashCode()
+    {
+        return getD().hashCode() ^ engineGetSpec().hashCode();
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = Strings.lineSeparator();
+
+        buf.append("EC Private Key").append(nl);
+        buf.append("             S: ").append(this.d.toString(16)).append(nl);
+
+        return buf.toString();
+
+    }
+
+    private DERBitString getPublicKeyDetails(JCEECPublicKey   pub)
+    {
+        try
+        {
+            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+            return info.getPublicKeyData();
+        }
+        catch (IOException e)
+        {   // should never happen
+            return null;
+        }
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        byte[] enc = (byte[])in.readObject();
+
+        populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+        this.algorithm = (String)in.readObject();
+        this.withCompression = in.readBoolean();
+        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+        attrCarrier.readObject(in);
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.writeObject(this.getEncoded());
+        out.writeObject(algorithm);
+        out.writeBoolean(withCompression);
+
+        attrCarrier.writeObject(out);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEECPublicKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEECPublicKey.java
new file mode 100644
index 0000000..aa96510
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JCEECPublicKey.java
@@ -0,0 +1,526 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.X962Parameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ECPoint;
+import com.android.internal.org.bouncycastle.asn1.x9.X9IntegerConverter;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters;
+import com.android.internal.org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
+import com.android.internal.org.bouncycastle.jce.interfaces.ECPointEncoder;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+import com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.custom.sec.SecP256K1Point;
+import com.android.internal.org.bouncycastle.math.ec.custom.sec.SecP256R1Point;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class JCEECPublicKey
+    implements ECPublicKey, com.android.internal.org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder
+{
+    private String                  algorithm = "EC";
+    private com.android.internal.org.bouncycastle.math.ec.ECPoint q;
+    private ECParameterSpec         ecSpec;
+    private boolean                 withCompression;
+    // Android-removed: Unsupported algorithms
+    // private GOST3410PublicKeyAlgParameters       gostParams;
+
+    public JCEECPublicKey(
+        String              algorithm,
+        JCEECPublicKey      key)
+    {
+        this.algorithm = algorithm;
+        this.q = key.q;
+        this.ecSpec = key.ecSpec;
+        this.withCompression = key.withCompression;
+        // Android-removed: Unsupported algorithms
+        // this.gostParams = key.gostParams;
+    }
+    
+    public JCEECPublicKey(
+        String              algorithm,
+        ECPublicKeySpec     spec)
+    {
+        this.algorithm = algorithm;
+        this.ecSpec = spec.getParams();
+        this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+    }
+
+    public JCEECPublicKey(
+        String              algorithm,
+        com.android.internal.org.bouncycastle.jce.spec.ECPublicKeySpec     spec)
+    {
+        this.algorithm = algorithm;
+        this.q = spec.getQ();
+
+        if (spec.getParams() != null) // can be null if implictlyCa
+        {
+            ECCurve curve = spec.getParams().getCurve();
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+        }
+        else
+        {
+            if (q.getCurve() == null)
+            {
+                com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+                q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger(), false);
+            }               
+            this.ecSpec = null;
+        }
+    }
+    
+    public JCEECPublicKey(
+        String                  algorithm,
+        ECPublicKeyParameters   params,
+        ECParameterSpec         spec)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+        this.q = params.getQ();
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = createSpec(ellipticCurve, dp);
+        }
+        else
+        {
+            this.ecSpec = spec;
+        }
+    }
+
+    public JCEECPublicKey(
+        String                  algorithm,
+        ECPublicKeyParameters   params,
+        com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec         spec)
+    {
+        ECDomainParameters      dp = params.getParameters();
+
+        this.algorithm = algorithm;
+        this.q = params.getQ();
+
+        if (spec == null)
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+            this.ecSpec = createSpec(ellipticCurve, dp);
+        }
+        else
+        {
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+        }
+    }
+
+    /*
+     * called for implicitCA
+     */
+    public JCEECPublicKey(
+        String                  algorithm,
+        ECPublicKeyParameters   params)
+    {
+        this.algorithm = algorithm;
+        this.q = params.getQ();
+        this.ecSpec = null;
+    }
+
+    private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
+    {
+        return new ECParameterSpec(
+            ellipticCurve,
+            EC5Util.convertPoint(dp.getG()),
+            dp.getN(),
+            dp.getH().intValue());
+    }
+
+    public JCEECPublicKey(
+        ECPublicKey     key)
+    {
+        this.algorithm = key.getAlgorithm();
+        this.ecSpec = key.getParams();
+        this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
+    }
+
+    JCEECPublicKey(
+        SubjectPublicKeyInfo    info)
+    {
+        populateFromPubKeyInfo(info);
+    }
+
+    private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+    {
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        if (info.getAlgorithmId().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+        {
+            DERBitString bits = info.getPublicKeyData();
+            ASN1OctetString key;
+            this.algorithm = "ECGOST3410";
+
+            try
+            {
+                key = (ASN1OctetString) ASN1Primitive.fromByteArray(bits.getBytes());
+            }
+            catch (IOException ex)
+            {
+                throw new IllegalArgumentException("error recovering public key");
+            }
+
+            byte[] keyEnc = key.getOctets();
+
+            byte[] x9Encoding = new byte[65];
+            x9Encoding[0] = 0x04;
+            for (int i = 1; i <= 32; ++i)
+            {
+                x9Encoding[i     ] = keyEnc[32 - i];
+                x9Encoding[i + 32] = keyEnc[64 - i];
+            }
+
+            gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters());
+
+            ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
+
+            ECCurve curve = spec.getCurve();
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
+
+            this.q = curve.decodePoint(x9Encoding);
+
+            ecSpec = new ECNamedCurveSpec(
+                ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
+                ellipticCurve,
+                EC5Util.convertPoint(spec.getG()),
+                spec.getN(),
+                spec.getH());
+        }
+        else
+        */
+        // END Android-removed: Unsupported algorithms
+        {
+            X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithmId().getParameters());
+            ECCurve                 curve;
+            EllipticCurve           ellipticCurve;
+
+            if (params.isNamedCurve())
+            {
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+                X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+                curve = ecP.getCurve();
+                ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+                ecSpec = new ECNamedCurveSpec(
+                    ECUtil.getCurveName(oid),
+                    ellipticCurve,
+                    EC5Util.convertPoint(ecP.getG()),
+                    ecP.getN(),
+                    ecP.getH());
+            }
+            else if (params.isImplicitlyCA())
+            {
+                ecSpec = null;
+                curve = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve();
+            }
+            else
+            {
+                X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+
+                curve = ecP.getCurve();
+                ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+                this.ecSpec = new ECParameterSpec(
+                    ellipticCurve,
+                    EC5Util.convertPoint(ecP.getG()),
+                    ecP.getN(),
+                    ecP.getH().intValue());
+            }
+
+            DERBitString    bits = info.getPublicKeyData();
+            byte[]          data = bits.getBytes();
+            ASN1OctetString key = new DEROctetString(data);
+
+            //
+            // extra octet string - one of our old certs...
+            //
+            if (data[0] == 0x04 && data[1] == data.length - 2
+                && (data[2] == 0x02 || data[2] == 0x03))
+            {
+                int qLength = new X9IntegerConverter().getByteLength(curve);
+
+                if (qLength >= data.length - 3)
+                {
+                    try
+                    {
+                        key = (ASN1OctetString) ASN1Primitive.fromByteArray(data);
+                    }
+                    catch (IOException ex)
+                    {
+                        throw new IllegalArgumentException("error recovering public key");
+                    }
+                }
+            }
+            X9ECPoint derQ = new X9ECPoint(curve, key);
+
+            this.q = derQ.getPoint();
+        }
+    }
+
+    public String getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        ASN1Encodable        params;
+        SubjectPublicKeyInfo info;
+
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        if (algorithm.equals("ECGOST3410"))
+        {
+            if (gostParams != null)
+            {
+                params = gostParams;
+            }
+            else
+            {
+                if (ecSpec instanceof ECNamedCurveSpec)
+                {
+                    params = new GOST3410PublicKeyAlgParameters(
+                                   ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
+                                   CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet);
+                }
+                else
+                {   // strictly speaking this may not be applicable...
+                    ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+                    X9ECParameters ecP = new X9ECParameters(
+                        curve,
+                        EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+                        ecSpec.getOrder(),
+                        BigInteger.valueOf(ecSpec.getCofactor()),
+                        ecSpec.getCurve().getSeed());
+
+                    params = new X962Parameters(ecP);
+                }
+            }
+
+            BigInteger      bX = this.q.getAffineXCoord().toBigInteger();
+            BigInteger      bY = this.q.getAffineYCoord().toBigInteger();
+            byte[]          encKey = new byte[64];
+
+            extractBytes(encKey, 0, bX);
+            extractBytes(encKey, 32, bY);
+
+            try
+            {
+                info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), new DEROctetString(encKey));
+            }
+            catch (IOException e)
+            {
+                return null;
+            }
+        }
+        else
+        */
+        // END Android-removed: Unsupported algorithms
+        {
+            if (ecSpec instanceof ECNamedCurveSpec)
+            {
+                ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+                if (curveOid == null)
+                {
+                    curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+                }
+                params = new X962Parameters(curveOid);
+            }
+            else if (ecSpec == null)
+            {
+                params = new X962Parameters(DERNull.INSTANCE);
+            }
+            else
+            {
+                ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+                X9ECParameters ecP = new X9ECParameters(
+                    curve,
+                    EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+                    ecSpec.getOrder(),
+                    BigInteger.valueOf(ecSpec.getCofactor()),
+                    ecSpec.getCurve().getSeed());
+
+                params = new X962Parameters(ecP);
+            }
+
+            ECCurve curve = this.engineGetQ().getCurve();
+            ASN1OctetString p = (ASN1OctetString)
+                new X9ECPoint(curve.createPoint(this.getQ().getAffineXCoord().toBigInteger(), this.getQ().getAffineYCoord().toBigInteger(), withCompression)).toASN1Primitive();
+
+            info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+        }
+
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+    }
+
+    private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
+    {
+        byte[] val = bI.toByteArray();
+        if (val.length < 32)
+        {
+            byte[] tmp = new byte[32];
+            System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
+            val = tmp;
+        }
+
+        for (int i = 0; i != 32; i++)
+        {
+            encKey[offSet + i] = val[val.length - 1 - i];
+        }
+    }
+
+    public ECParameterSpec getParams()
+    {
+        return ecSpec;
+    }
+
+    public com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+    {
+        if (ecSpec == null)     // implictlyCA
+        {
+            return null;
+        }
+
+        return EC5Util.convertSpec(ecSpec, withCompression);
+    }
+
+    public ECPoint getW()
+    {
+        return EC5Util.convertPoint(q);
+    }
+
+    public com.android.internal.org.bouncycastle.math.ec.ECPoint getQ()
+    {
+        if (ecSpec == null)
+        {
+            return q.getDetachedPoint();
+        }
+
+        return q;
+    }
+
+    public com.android.internal.org.bouncycastle.math.ec.ECPoint engineGetQ()
+    {
+        return q;
+    }
+
+    com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+    {
+        if (ecSpec != null)
+        {
+            return EC5Util.convertSpec(ecSpec, withCompression);
+        }
+
+        return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = Strings.lineSeparator();
+
+        buf.append("EC Public Key").append(nl);
+        buf.append("            X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
+        buf.append("            Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
+
+        return buf.toString();
+
+    }
+    
+    public void setPointFormat(String style)
+    {
+       withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof JCEECPublicKey))
+        {
+            return false;
+        }
+
+        JCEECPublicKey other = (JCEECPublicKey)o;
+
+        return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+    }
+
+    public int hashCode()
+    {
+        return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        byte[] enc = (byte[])in.readObject();
+
+        populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+        this.algorithm = (String)in.readObject();
+        this.withCompression = in.readBoolean();
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.writeObject(this.getEncoded());
+        out.writeObject(algorithm);
+        out.writeBoolean(withCompression);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java
new file mode 100644
index 0000000..70599c0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java
@@ -0,0 +1,182 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.DSAParameter;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import com.android.internal.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class JDKDSAPrivateKey
+    implements DSAPrivateKey, PKCS12BagAttributeCarrier
+{
+    private static final long serialVersionUID = -4677259546958385734L;
+
+    BigInteger          x;
+    DSAParams           dsaSpec;
+
+    private PKCS12BagAttributeCarrierImpl   attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    protected JDKDSAPrivateKey()
+    {
+    }
+
+    JDKDSAPrivateKey(
+        DSAPrivateKey    key)
+    {
+        this.x = key.getX();
+        this.dsaSpec = key.getParams();
+    }
+
+    JDKDSAPrivateKey(
+        DSAPrivateKeySpec    spec)
+    {
+        this.x = spec.getX();
+        this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+    }
+
+    JDKDSAPrivateKey(
+        PrivateKeyInfo  info)
+        throws IOException
+    {
+        DSAParameter    params = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+        ASN1Integer      derX = ASN1Integer.getInstance(info.parsePrivateKey());
+
+        this.x = derX.getValue();
+        this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+    }
+
+    JDKDSAPrivateKey(
+        DSAPrivateKeyParameters  params)
+    {
+        this.x = params.getX();
+        this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+    }
+
+    public String getAlgorithm()
+    {
+        return "DSA";
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        try
+        {
+            PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new ASN1Integer(getX()));
+
+            return info.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+
+    public DSAParams getParams()
+    {
+        return dsaSpec;
+    }
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DSAPrivateKey))
+        {
+            return false;
+        }
+        
+        DSAPrivateKey other = (DSAPrivateKey)o;
+        
+        return this.getX().equals(other.getX()) 
+            && this.getParams().getG().equals(other.getParams().getG()) 
+            && this.getParams().getP().equals(other.getParams().getP()) 
+            && this.getParams().getQ().equals(other.getParams().getQ());
+    }
+
+    public int hashCode()
+    {
+        return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+                ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+    }
+    
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        ASN1ObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        this.x = (BigInteger)in.readObject();
+        this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+        
+        attrCarrier.readObject(in);
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.writeObject(x);
+        out.writeObject(dsaSpec.getP());
+        out.writeObject(dsaSpec.getQ());
+        out.writeObject(dsaSpec.getG());
+
+        attrCarrier.writeObject(out);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JDKDSAPublicKey.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JDKDSAPublicKey.java
new file mode 100644
index 0000000..f86d2be
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JDKDSAPublicKey.java
@@ -0,0 +1,181 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPublicKeySpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.DSAParameter;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class JDKDSAPublicKey
+    implements DSAPublicKey
+{
+    private static final long serialVersionUID = 1752452449903495175L;
+
+    private BigInteger      y;
+    private DSAParams       dsaSpec;
+
+    JDKDSAPublicKey(
+        DSAPublicKeySpec    spec)
+    {
+        this.y = spec.getY();
+        this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+    }
+
+    JDKDSAPublicKey(
+        DSAPublicKey    key)
+    {
+        this.y = key.getY();
+        this.dsaSpec = key.getParams();
+    }
+
+    JDKDSAPublicKey(
+        DSAPublicKeyParameters  params)
+    {
+        this.y = params.getY();
+        this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+    }
+
+    JDKDSAPublicKey(
+        BigInteger        y,
+        DSAParameterSpec  dsaSpec)
+    {
+        this.y = y;
+        this.dsaSpec = dsaSpec;
+    }
+
+    JDKDSAPublicKey(
+        SubjectPublicKeyInfo    info)
+    {
+
+        ASN1Integer              derY;
+
+        try
+        {
+            derY = (ASN1Integer)info.parsePublicKey();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("invalid info structure in DSA public key");
+        }
+
+        this.y = derY.getValue();
+
+        if (isNotNull(info.getAlgorithm().getParameters()))
+        {
+            DSAParameter params = DSAParameter.getInstance(info.getAlgorithm().getParameters());
+            
+            this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+        }
+    }
+
+    private boolean isNotNull(ASN1Encodable parameters)
+    {
+        return parameters != null && !DERNull.INSTANCE.equals(parameters);
+    }
+
+    public String getAlgorithm()
+    {
+        return "DSA";
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        try
+        {
+            if (dsaSpec == null)
+            {
+                return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new ASN1Integer(y)).getEncoded(ASN1Encoding.DER);
+            }
+
+            return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new ASN1Integer(y)).getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+
+    public DSAParams getParams()
+    {
+        return dsaSpec;
+    }
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = Strings.lineSeparator();
+
+        buf.append("DSA Public Key").append(nl);
+        buf.append("            y: ").append(this.getY().toString(16)).append(nl);
+
+        return buf.toString();
+    }
+
+    public int hashCode()
+    {
+        return this.getY().hashCode() ^ this.getParams().getG().hashCode() 
+                ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DSAPublicKey))
+        {
+            return false;
+        }
+        
+        DSAPublicKey other = (DSAPublicKey)o;
+        
+        return this.getY().equals(other.getY()) 
+            && this.getParams().getG().equals(other.getParams().getG()) 
+            && this.getParams().getP().equals(other.getParams().getP()) 
+            && this.getParams().getQ().equals(other.getParams().getQ());
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        this.y = (BigInteger)in.readObject();
+        this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.writeObject(y);
+        out.writeObject(dsaSpec.getP());
+        out.writeObject(dsaSpec.getQ());
+        out.writeObject(dsaSpec.getG());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java
new file mode 100644
index 0000000..dd2798f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java
@@ -0,0 +1,53 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.OutputStream;
+import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.ProtectionParameter;
+
+/**
+ * @deprecated use org.bouncycastle.jcajce.config.PKCS12StoreParameter
+ * @hide This class is not part of the Android public SDK API
+ */
+public class JDKPKCS12StoreParameter implements LoadStoreParameter
+{
+    private OutputStream outputStream;
+    private ProtectionParameter protectionParameter;
+    private boolean useDEREncoding;
+
+    public OutputStream getOutputStream()
+    {
+        return outputStream;
+    }
+
+    public ProtectionParameter getProtectionParameter()
+    {
+        return protectionParameter;
+    }
+
+    public boolean isUseDEREncoding()
+    {
+        return useDEREncoding;
+    }
+
+    public void setOutputStream(OutputStream outputStream)
+    {
+        this.outputStream = outputStream;
+    }
+
+    public void setPassword(char[] password)
+    {
+        this.protectionParameter = new KeyStore.PasswordProtection(password);
+    }
+
+    public void setProtectionParameter(ProtectionParameter protectionParameter)
+    {
+        this.protectionParameter = protectionParameter;
+    }
+
+    public void setUseDEREncoding(boolean useDEREncoding)
+    {
+        this.useDEREncoding = useDEREncoding;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PEMUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PEMUtil.java
new file mode 100644
index 0000000..ee709e1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PEMUtil.java
@@ -0,0 +1,98 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.util.encoders.Base64;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PEMUtil
+{
+    private final String _header1;
+    private final String _header2;
+    private final String _footer1;
+    private final String _footer2;
+
+    PEMUtil(
+        String type)
+    {
+        _header1 = "-----BEGIN " + type + "-----";
+        _header2 = "-----BEGIN X509 " + type + "-----";
+        _footer1 = "-----END " + type + "-----";
+        _footer2 = "-----END X509 " + type + "-----";
+    }
+
+    private String readLine(
+        InputStream in)
+        throws IOException
+    {
+        int             c;
+        StringBuffer    l = new StringBuffer();
+
+        do
+        {
+            while (((c = in.read()) != '\r') && c != '\n' && (c >= 0))
+            {
+                if (c == '\r')
+                {
+                    continue;
+                }
+
+                l.append((char)c);
+            }
+        }
+        while (c >= 0 && l.length() == 0);
+
+        if (c < 0)
+        {
+            return null;
+        }
+
+        return l.toString();
+    }
+
+    ASN1Sequence readPEMObject(
+        InputStream  in)
+        throws IOException
+    {
+        String          line;
+        StringBuffer    pemBuf = new StringBuffer();
+
+        while ((line = readLine(in)) != null)
+        {
+            if (line.startsWith(_header1) || line.startsWith(_header2))
+            {
+                break;
+            }
+        }
+
+        while ((line = readLine(in)) != null)
+        {
+            if (line.startsWith(_footer1) || line.startsWith(_footer2))
+            {
+                break;
+            }
+
+            pemBuf.append(line);
+        }
+
+        if (pemBuf.length() != 0)
+        {
+            ASN1Primitive o = new ASN1InputStream(Base64.decode(pemBuf.toString())).readObject();
+            if (!(o instanceof ASN1Sequence))
+            {
+                throw new IOException("malformed PEM data encountered");
+            }
+
+            return (ASN1Sequence)o;
+        }
+
+        return null;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXCRLUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXCRLUtil.java
new file mode 100644
index 0000000..40074b5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXCRLUtil.java
@@ -0,0 +1,134 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import com.android.internal.org.bouncycastle.jcajce.PKIXCRLStore;
+import com.android.internal.org.bouncycastle.jcajce.PKIXCRLStoreSelector;
+import com.android.internal.org.bouncycastle.util.Store;
+import com.android.internal.org.bouncycastle.util.StoreException;
+
+class PKIXCRLUtil
+{
+    public Set findCRLs(PKIXCRLStoreSelector crlselect, Date validityDate, List certStores, List pkixCrlStores)
+        throws AnnotatedException
+    {
+        Set initialSet = new HashSet();
+
+        // get complete CRL(s)
+        try
+        {
+            initialSet.addAll(findCRLs(crlselect, pkixCrlStores));
+            initialSet.addAll(findCRLs(crlselect, certStores));
+        }
+        catch (AnnotatedException e)
+        {
+            throw new AnnotatedException("Exception obtaining complete CRLs.", e);
+        }
+
+        Set finalSet = new HashSet();
+
+        // based on RFC 5280 6.3.3
+        for (Iterator it = initialSet.iterator(); it.hasNext();)
+        {
+            X509CRL crl = (X509CRL)it.next();
+
+            if (crl.getNextUpdate().after(validityDate))
+            {
+                X509Certificate cert = crlselect.getCertificateChecking();
+
+                if (cert != null)
+                {
+                    if (crl.getThisUpdate().before(cert.getNotAfter()))
+                    {
+                        finalSet.add(crl);
+                    }
+                }
+                else
+                {
+                    finalSet.add(crl);
+                }
+            }
+        }
+
+        return finalSet;
+    }
+
+    /**
+     * Return a Collection of all CRLs found in the X509Store's that are
+     * matching the crlSelect criteriums.
+     *
+     * @param crlSelect a {@link com.android.internal.org.bouncycastle.jcajce.PKIXCRLStoreSelector} object that will be used
+     *            to select the CRLs
+     * @param crlStores a List containing only
+     *            {@link Store} objects.
+     *            These are used to search for CRLs
+     *
+     * @return a Collection of all found {@link java.security.cert.X509CRL X509CRL} objects. May be
+     *         empty but never <code>null</code>.
+     */
+    private final Collection findCRLs(PKIXCRLStoreSelector crlSelect,
+        List crlStores) throws AnnotatedException
+    {
+        Set crls = new HashSet();
+        Iterator iter = crlStores.iterator();
+
+        AnnotatedException lastException = null;
+        boolean foundValidStore = false;
+
+        while (iter.hasNext())
+        {
+            Object obj = iter.next();
+
+            // BEGIN Android-removed: Unknown reason
+            /*
+            if (obj instanceof Store)
+            {
+                Store store = (Store)obj;
+
+                try
+                {
+                    crls.addAll(store.getMatches(crlSelect));
+                    foundValidStore = true;
+                }
+                catch (StoreException e)
+                {
+                    lastException = new AnnotatedException(
+                        "Exception searching in X.509 CRL store.", e);
+                }
+            }
+            else
+            */
+            // END Android-removed: Unknown reason
+            {
+                CertStore store = (CertStore)obj;
+
+                try
+                {
+                    crls.addAll(PKIXCRLStoreSelector.getCRLs(crlSelect, store));
+                    foundValidStore = true;
+                }
+                catch (CertStoreException e)
+                {
+                    lastException = new AnnotatedException(
+                        "Exception searching in X.509 CRL store.", e);
+                }
+            }
+        }
+        if (!foundValidStore && lastException != null)
+        {
+            throw lastException;
+        }
+        return crls;
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java
new file mode 100644
index 0000000..88b7f85
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java
@@ -0,0 +1,282 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathBuilderResult;
+import java.security.cert.CertPathBuilderSpi;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXCertPathBuilderResult;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.jcajce.PKIXCertStore;
+import com.android.internal.org.bouncycastle.jcajce.PKIXCertStoreSelector;
+import com.android.internal.org.bouncycastle.jcajce.PKIXExtendedBuilderParameters;
+import com.android.internal.org.bouncycastle.jcajce.PKIXExtendedParameters;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
+import com.android.internal.org.bouncycastle.jce.exception.ExtCertPathBuilderException;
+import com.android.internal.org.bouncycastle.x509.ExtendedPKIXBuilderParameters;
+import com.android.internal.org.bouncycastle.x509.ExtendedPKIXParameters;
+
+/**
+ * Implements the PKIX CertPathBuilding algorithm for BouncyCastle.
+ * 
+ * @see CertPathBuilderSpi
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKIXCertPathBuilderSpi
+    extends CertPathBuilderSpi
+{
+    /**
+     * Build and validate a CertPath using the given parameter.
+     * 
+     * @param params PKIXBuilderParameters object containing all information to
+     *            build the CertPath
+     */
+    public CertPathBuilderResult engineBuild(CertPathParameters params)
+        throws CertPathBuilderException, InvalidAlgorithmParameterException
+    {
+        PKIXExtendedBuilderParameters paramsPKIX;
+        if (params instanceof PKIXBuilderParameters)
+        {
+            PKIXExtendedParameters.Builder paramsPKIXBldr = new PKIXExtendedParameters.Builder((PKIXBuilderParameters)params);
+            PKIXExtendedBuilderParameters.Builder paramsBldrPKIXBldr;
+
+            if (params instanceof ExtendedPKIXParameters)
+            {
+                ExtendedPKIXBuilderParameters extPKIX = (ExtendedPKIXBuilderParameters)params;
+
+                for (Iterator it = extPKIX.getAdditionalStores().iterator(); it.hasNext();)
+                {
+                     paramsPKIXBldr.addCertificateStore((PKIXCertStore)it.next());
+                }
+                paramsBldrPKIXBldr  = new PKIXExtendedBuilderParameters.Builder(paramsPKIXBldr.build());
+
+                paramsBldrPKIXBldr.addExcludedCerts(extPKIX.getExcludedCerts());
+                paramsBldrPKIXBldr.setMaxPathLength(extPKIX.getMaxPathLength());
+            }
+            else
+            {
+                paramsBldrPKIXBldr  = new PKIXExtendedBuilderParameters.Builder((PKIXBuilderParameters)params);
+            }
+
+            paramsPKIX = paramsBldrPKIXBldr.build();
+        }
+        else if (params instanceof PKIXExtendedBuilderParameters)
+        {
+            paramsPKIX = (PKIXExtendedBuilderParameters)params;
+        }
+        else
+        {
+            throw new InvalidAlgorithmParameterException(
+                "Parameters must be an instance of "
+                    + PKIXBuilderParameters.class.getName() + " or "
+                    + PKIXExtendedBuilderParameters.class.getName() + ".");
+        }
+
+        Collection targets;
+        Iterator targetIter;
+        List certPathList = new ArrayList();
+        X509Certificate cert;
+
+        // search target certificates
+
+        PKIXCertStoreSelector certSelect = paramsPKIX.getBaseParameters().getTargetConstraints();
+
+        try
+        {
+            targets = CertPathValidatorUtilities.findCertificates(certSelect, paramsPKIX.getBaseParameters().getCertificateStores());
+            targets.addAll(CertPathValidatorUtilities.findCertificates(certSelect, paramsPKIX.getBaseParameters().getCertStores()));
+        }
+        catch (AnnotatedException e)
+        {
+            throw new ExtCertPathBuilderException(
+                "Error finding target certificate.", e);
+        }
+
+        if (targets.isEmpty())
+        {
+
+            throw new CertPathBuilderException(
+                "No certificate found matching targetContraints.");
+        }
+
+        CertPathBuilderResult result = null;
+
+        // check all potential target certificates
+        targetIter = targets.iterator();
+        while (targetIter.hasNext() && result == null)
+        {
+            cert = (X509Certificate) targetIter.next();
+            result = build(cert, paramsPKIX, certPathList);
+        }
+
+        if (result == null && certPathException != null)
+        {
+            if (certPathException instanceof AnnotatedException)
+            {
+                throw new CertPathBuilderException(certPathException.getMessage(), certPathException.getCause());
+            }
+            throw new CertPathBuilderException(
+                "Possible certificate chain could not be validated.",
+                certPathException);
+        }
+
+        if (result == null && certPathException == null)
+        {
+            throw new CertPathBuilderException(
+                "Unable to find certificate chain.");
+        }
+
+        return result;
+    }
+
+    private Exception certPathException;
+
+    protected CertPathBuilderResult build(X509Certificate tbvCert,
+        PKIXExtendedBuilderParameters pkixParams, List tbvPath)
+    {
+        // If tbvCert is readily present in tbvPath, it indicates having run
+        // into a cycle in the
+        // PKI graph.
+        if (tbvPath.contains(tbvCert))
+        {
+            return null;
+        }
+        // step out, the certificate is not allowed to appear in a certification
+        // chain.
+        if (pkixParams.getExcludedCerts().contains(tbvCert))
+        {
+            return null;
+        }
+        // test if certificate path exceeds maximum length
+        if (pkixParams.getMaxPathLength() != -1)
+        {
+            if (tbvPath.size() - 1 > pkixParams.getMaxPathLength())
+            {
+                return null;
+            }
+        }
+
+        tbvPath.add(tbvCert);
+
+        CertificateFactory cFact;
+        PKIXCertPathValidatorSpi validator;
+        CertPathBuilderResult builderResult = null;
+
+        try
+        {
+            cFact = new CertificateFactory();
+            validator = new PKIXCertPathValidatorSpi();
+        }
+        catch (Exception e)
+        {
+            // cannot happen
+            throw new RuntimeException("Exception creating support classes.");
+        }
+
+        try
+        {
+            // check whether the issuer of <tbvCert> is a TrustAnchor
+            if (CertPathValidatorUtilities.isIssuerTrustAnchor(tbvCert, pkixParams.getBaseParameters().getTrustAnchors(),
+                pkixParams.getBaseParameters().getSigProvider()))
+            {
+                // exception message from possibly later tried certification
+                // chains
+                CertPath certPath = null;
+                PKIXCertPathValidatorResult result = null;
+                try
+                {
+                    certPath = cFact.engineGenerateCertPath(tbvPath);
+                }
+                catch (Exception e)
+                {
+                    throw new AnnotatedException(
+                        "Certification path could not be constructed from certificate list.",
+                        e);
+                }
+
+                try
+                {
+                    result = (PKIXCertPathValidatorResult) validator.engineValidate(
+                        certPath, pkixParams);
+                }
+                catch (Exception e)
+                {
+                    throw new AnnotatedException(
+                        "Certification path could not be validated.", e);
+                }
+
+                return new PKIXCertPathBuilderResult(certPath, result
+                    .getTrustAnchor(), result.getPolicyTree(), result
+                    .getPublicKey());
+
+            }
+            else
+            {
+                List stores = new ArrayList();
+
+
+                stores.addAll(pkixParams.getBaseParameters().getCertificateStores());
+
+                // add additional X.509 stores from locations in certificate
+                try
+                {
+                    stores.addAll(CertPathValidatorUtilities.getAdditionalStoresFromAltNames(
+                        tbvCert.getExtensionValue(Extension.issuerAlternativeName.getId()), pkixParams.getBaseParameters().getNamedCertificateStoreMap()));
+                }
+                catch (CertificateParsingException e)
+                {
+                    throw new AnnotatedException(
+                        "No additional X.509 stores can be added from certificate locations.",
+                        e);
+                }
+                Collection issuers = new HashSet();
+                // try to get the issuer certificate from one
+                // of the stores
+                try
+                {
+                    issuers.addAll(CertPathValidatorUtilities.findIssuerCerts(tbvCert, pkixParams.getBaseParameters().getCertStores(), stores));
+                }
+                catch (AnnotatedException e)
+                {
+                    throw new AnnotatedException(
+                        "Cannot find issuer certificate for certificate in certification path.",
+                        e);
+                }
+                if (issuers.isEmpty())
+                {
+                    throw new AnnotatedException(
+                        "No issuer certificate for certificate in certification path found.");
+                }
+                Iterator it = issuers.iterator();
+
+                while (it.hasNext() && builderResult == null)
+                {
+                    X509Certificate issuer = (X509Certificate) it.next();
+                    builderResult = build(issuer, pkixParams, tbvPath);
+                }
+            }
+        }
+        catch (AnnotatedException e)
+        {
+            certPathException = e;
+        }
+        if (builderResult == null)
+        {
+            tbvPath.remove(tbvCert);
+        }
+        return builderResult;
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
new file mode 100644
index 0000000..1e4e5dc
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
@@ -0,0 +1,523 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorResult;
+import java.security.cert.CertPathValidatorSpi;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.TBSCertificate;
+import com.android.internal.org.bouncycastle.jcajce.PKIXExtendedBuilderParameters;
+import com.android.internal.org.bouncycastle.jcajce.PKIXExtendedParameters;
+import com.android.internal.org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.jce.exception.ExtCertPathValidatorException;
+import com.android.internal.org.bouncycastle.x509.ExtendedPKIXParameters;
+
+/**
+ * CertPathValidatorSpi implementation for X.509 Certificate validation � la RFC
+ * 3280.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKIXCertPathValidatorSpi
+        extends CertPathValidatorSpi
+{
+    private final JcaJceHelper helper = new BCJcaJceHelper();
+
+    public PKIXCertPathValidatorSpi()
+    {
+    }
+    // BEGIN Android-added: Avoid loading blocklist during class init
+    private static class NoPreloadHolder {
+        private final static CertBlocklist blocklist = new CertBlocklist();
+    }
+    // END Android-added: Avoid loading blocklist during class init
+
+    public CertPathValidatorResult engineValidate(
+            CertPath certPath,
+            CertPathParameters params)
+            throws CertPathValidatorException,
+            InvalidAlgorithmParameterException
+    {
+        PKIXExtendedParameters paramsPKIX;
+        if (params instanceof PKIXParameters)
+        {
+            PKIXExtendedParameters.Builder paramsPKIXBldr = new PKIXExtendedParameters.Builder((PKIXParameters)params);
+
+            if (params instanceof ExtendedPKIXParameters)
+            {
+                ExtendedPKIXParameters extPKIX = (ExtendedPKIXParameters)params;
+
+                paramsPKIXBldr.setUseDeltasEnabled(extPKIX.isUseDeltasEnabled());
+                paramsPKIXBldr.setValidityModel(extPKIX.getValidityModel());
+            }
+
+            paramsPKIX = paramsPKIXBldr.build();
+        }
+        else if (params instanceof PKIXExtendedBuilderParameters)
+        {
+            paramsPKIX = ((PKIXExtendedBuilderParameters)params).getBaseParameters();
+        }
+        else if (params instanceof PKIXExtendedParameters)
+        {
+            paramsPKIX = (PKIXExtendedParameters)params;
+        }
+        else
+        {
+            throw new InvalidAlgorithmParameterException("Parameters must be a " + PKIXParameters.class.getName() + " instance.");
+        }
+
+        if (paramsPKIX.getTrustAnchors() == null)
+        {
+            throw new InvalidAlgorithmParameterException(
+                    "trustAnchors is null, this is not allowed for certification path validation.");
+        }
+
+        //
+        // 6.1.1 - inputs
+        //
+
+        //
+        // (a)
+        //
+        List certs = certPath.getCertificates();
+        int n = certs.size();
+
+        if (certs.isEmpty())
+        {
+            throw new CertPathValidatorException("Certification path is empty.", null, certPath, -1);
+        }
+        // BEGIN Android-added: Support blocklisting known-bad certs
+        {
+            X509Certificate cert = (X509Certificate) certs.get(0);
+
+            if (cert != null) {
+                BigInteger serial = cert.getSerialNumber();
+                if (NoPreloadHolder.blocklist.isSerialNumberBlockListed(serial)) {
+                    // emulate CRL exception message in RFC3280CertPathUtilities.checkCRLs
+                    String message = "Certificate revocation of serial 0x" + serial.toString(16);
+                    System.out.println(message);
+                    AnnotatedException e = new AnnotatedException(message);
+                    throw new CertPathValidatorException(e.getMessage(), e, certPath, 0);
+                }
+            }
+        }
+        // END Android-added: Support blocklisting known-bad certs
+
+        //
+        // (b)
+        //
+        // Date validDate = CertPathValidatorUtilities.getValidDate(paramsPKIX);
+
+        //
+        // (c)
+        //
+        Set userInitialPolicySet = paramsPKIX.getInitialPolicies();
+
+        //
+        // (d)
+        // 
+        TrustAnchor trust;
+        try
+        {
+            trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
+                    paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider());
+
+            if (trust == null)
+            {
+                throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1);
+            }
+
+            checkCertificate(trust.getTrustedCert());
+        }
+        catch (AnnotatedException e)
+        {
+            throw new CertPathValidatorException(e.getMessage(), e.getUnderlyingException(), certPath, certs.size() - 1);
+        }
+
+        // RFC 5280 - CRLs must originate from the same trust anchor as the target certificate.
+        paramsPKIX = new PKIXExtendedParameters.Builder(paramsPKIX).setTrustAnchor(trust).build();
+
+        //
+        // (e), (f), (g) are part of the paramsPKIX object.
+        //
+        Iterator certIter;
+        int index = 0;
+        int i;
+        // Certificate for each interation of the validation loop
+        // Signature information for each iteration of the validation loop
+        //
+        // 6.1.2 - setup
+        //
+
+        //
+        // (a)
+        //
+        List[] policyNodes = new ArrayList[n + 1];
+        for (int j = 0; j < policyNodes.length; j++)
+        {
+            policyNodes[j] = new ArrayList();
+        }
+
+        Set policySet = new HashSet();
+
+        policySet.add(RFC3280CertPathUtilities.ANY_POLICY);
+
+        PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(),
+                RFC3280CertPathUtilities.ANY_POLICY, false);
+
+        policyNodes[0].add(validPolicyTree);
+
+        //
+        // (b) and (c)
+        //
+        PKIXNameConstraintValidator nameConstraintValidator = new PKIXNameConstraintValidator();
+
+        // (d)
+        //
+        int explicitPolicy;
+        Set acceptablePolicies = new HashSet();
+
+        if (paramsPKIX.isExplicitPolicyRequired())
+        {
+            explicitPolicy = 0;
+        }
+        else
+        {
+            explicitPolicy = n + 1;
+        }
+
+        //
+        // (e)
+        //
+        int inhibitAnyPolicy;
+
+        if (paramsPKIX.isAnyPolicyInhibited())
+        {
+            inhibitAnyPolicy = 0;
+        }
+        else
+        {
+            inhibitAnyPolicy = n + 1;
+        }
+
+        //
+        // (f)
+        //
+        int policyMapping;
+
+        if (paramsPKIX.isPolicyMappingInhibited())
+        {
+            policyMapping = 0;
+        }
+        else
+        {
+            policyMapping = n + 1;
+        }
+
+        //
+        // (g), (h), (i), (j)
+        //
+        PublicKey workingPublicKey;
+        X500Name workingIssuerName;
+
+        X509Certificate sign = trust.getTrustedCert();
+        try
+        {
+            if (sign != null)
+            {
+                workingIssuerName = PrincipalUtils.getSubjectPrincipal(sign);
+                workingPublicKey = sign.getPublicKey();
+            }
+            else
+            {
+                workingIssuerName = PrincipalUtils.getCA(trust);
+                workingPublicKey = trust.getCAPublicKey();
+            }
+        }
+        catch (IllegalArgumentException ex)
+        {
+            throw new ExtCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath,
+                    -1);
+        }
+
+        AlgorithmIdentifier workingAlgId = null;
+        try
+        {
+            workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+        }
+        catch (CertPathValidatorException e)
+        {
+            throw new ExtCertPathValidatorException(
+                    "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
+        }
+        ASN1ObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getAlgorithm();
+        ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters();
+
+        //
+        // (k)
+        //
+        int maxPathLength = n;
+
+        //
+        // 6.1.3
+        //
+
+        if (paramsPKIX.getTargetConstraints() != null
+                && !paramsPKIX.getTargetConstraints().match((X509Certificate) certs.get(0)))
+        {
+            throw new ExtCertPathValidatorException(
+                    "Target certificate in certification path does not match targetConstraints.", null, certPath, 0);
+        }
+
+        // 
+        // initialize CertPathChecker's
+        //
+        List pathCheckers = paramsPKIX.getCertPathCheckers();
+        certIter = pathCheckers.iterator();
+        while (certIter.hasNext())
+        {
+            ((PKIXCertPathChecker) certIter.next()).init(false);
+        }
+
+        X509Certificate cert = null;
+
+        for (index = certs.size() - 1; index >= 0; index--)
+        {
+            // BEGIN Android-added: Support blocklisting known-bad certs
+            if (NoPreloadHolder.blocklist.isPublicKeyBlockListed(workingPublicKey)) {
+                // emulate CRL exception message in RFC3280CertPathUtilities.checkCRLs
+                String message = "Certificate revocation of public key " + workingPublicKey;
+                System.out.println(message);
+                AnnotatedException e = new AnnotatedException(message);
+                throw new CertPathValidatorException(e.getMessage(), e, certPath, index);
+            }
+            // END Android-added: Support blocklisting known-bad certs
+            // try
+            // {
+            //
+            // i as defined in the algorithm description
+            //
+            i = n - index;
+
+            //
+            // set certificate to be checked in this round
+            // sign and workingPublicKey and workingIssuerName are set
+            // at the end of the for loop and initialized the
+            // first time from the TrustAnchor
+            //
+            cert = (X509Certificate) certs.get(index);
+            boolean verificationAlreadyPerformed = (index == certs.size() - 1);
+
+            try
+            {
+                checkCertificate(cert);
+            }
+            catch (AnnotatedException e)
+            {
+                throw new CertPathValidatorException(e.getMessage(), e.getUnderlyingException(), certPath, index);
+            }
+
+            //
+            // 6.1.3
+            //
+
+            RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey,
+                verificationAlreadyPerformed, workingIssuerName, sign, helper);
+
+            RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator);
+
+            validPolicyTree = RFC3280CertPathUtilities.processCertD(certPath, index, acceptablePolicies,
+                    validPolicyTree, policyNodes, inhibitAnyPolicy);
+
+            validPolicyTree = RFC3280CertPathUtilities.processCertE(certPath, index, validPolicyTree);
+
+            RFC3280CertPathUtilities.processCertF(certPath, index, validPolicyTree, explicitPolicy);
+
+            //
+            // 6.1.4
+            //
+            if (i != n)
+            {
+                if (cert != null && cert.getVersion() == 1)
+                {
+                    // we've found the trust anchor at the top of the path, ignore and keep going
+                    if ((i == 1) && cert.equals(trust.getTrustedCert()))
+                    {
+                        continue;
+                    }
+                    throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null,
+                            certPath, index);
+                }
+
+                RFC3280CertPathUtilities.prepareNextCertA(certPath, index);
+
+                validPolicyTree = RFC3280CertPathUtilities.prepareCertB(certPath, index, policyNodes, validPolicyTree,
+                        policyMapping);
+
+                RFC3280CertPathUtilities.prepareNextCertG(certPath, index, nameConstraintValidator);
+
+                // (h)
+                explicitPolicy = RFC3280CertPathUtilities.prepareNextCertH1(certPath, index, explicitPolicy);
+                policyMapping = RFC3280CertPathUtilities.prepareNextCertH2(certPath, index, policyMapping);
+                inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertH3(certPath, index, inhibitAnyPolicy);
+
+                //
+                // (i)
+                //
+                explicitPolicy = RFC3280CertPathUtilities.prepareNextCertI1(certPath, index, explicitPolicy);
+                policyMapping = RFC3280CertPathUtilities.prepareNextCertI2(certPath, index, policyMapping);
+
+                // (j)
+                inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertJ(certPath, index, inhibitAnyPolicy);
+
+                // (k)
+                RFC3280CertPathUtilities.prepareNextCertK(certPath, index);
+
+                // (l)
+                maxPathLength = RFC3280CertPathUtilities.prepareNextCertL(certPath, index, maxPathLength);
+
+                // (m)
+                maxPathLength = RFC3280CertPathUtilities.prepareNextCertM(certPath, index, maxPathLength);
+
+                // (n)
+                RFC3280CertPathUtilities.prepareNextCertN(certPath, index);
+
+                Set criticalExtensions = cert.getCriticalExtensionOIDs();
+                if (criticalExtensions != null)
+                {
+                    criticalExtensions = new HashSet(criticalExtensions);
+
+                    // these extensions are handled by the algorithm
+                    criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
+                    criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+                    criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
+                    criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
+                    criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+                    criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+                    criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
+                    criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
+                    criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
+                    criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
+                }
+                else
+                {
+                    criticalExtensions = new HashSet();
+                }
+
+                // (o)
+                RFC3280CertPathUtilities.prepareNextCertO(certPath, index, criticalExtensions, pathCheckers);
+                
+                // set signing certificate for next round
+                sign = cert;
+
+                // (c)
+                workingIssuerName = PrincipalUtils.getSubjectPrincipal(sign);
+
+                // (d)
+                try
+                {
+                    workingPublicKey = CertPathValidatorUtilities.getNextWorkingKey(certPath.getCertificates(), index, helper);
+                }
+                catch (CertPathValidatorException e)
+                {
+                    throw new CertPathValidatorException("Next working key could not be retrieved.", e, certPath, index);
+                }
+
+                workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+                // (f)
+                workingPublicKeyAlgorithm = workingAlgId.getAlgorithm();
+                // (e)
+                workingPublicKeyParameters = workingAlgId.getParameters();
+            }
+        }
+
+        //
+        // 6.1.5 Wrap-up procedure
+        //
+
+        explicitPolicy = RFC3280CertPathUtilities.wrapupCertA(explicitPolicy, cert);
+
+        explicitPolicy = RFC3280CertPathUtilities.wrapupCertB(certPath, index + 1, explicitPolicy);
+
+        //
+        // (c) (d) and (e) are already done
+        //
+
+        //
+        // (f)
+        //
+        Set criticalExtensions = cert.getCriticalExtensionOIDs();
+
+        if (criticalExtensions != null)
+        {
+            criticalExtensions = new HashSet(criticalExtensions);
+            // these extensions are handled by the algorithm
+            criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
+            criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+            criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
+            criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
+            criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+            criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+            criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
+            criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
+            criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
+            criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
+            criticalExtensions.remove(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS);
+            criticalExtensions.remove(Extension.extendedKeyUsage.getId());
+        }
+        else
+        {
+            criticalExtensions = new HashSet();
+        }
+
+        RFC3280CertPathUtilities.wrapupCertF(certPath, index + 1, pathCheckers, criticalExtensions);
+
+        PKIXPolicyNode intersection = RFC3280CertPathUtilities.wrapupCertG(certPath, paramsPKIX, userInitialPolicySet,
+                index + 1, policyNodes, validPolicyTree, acceptablePolicies);
+
+        if ((explicitPolicy > 0) || (intersection != null))
+        {
+            return new PKIXCertPathValidatorResult(trust, intersection, cert.getPublicKey());
+        }
+
+        throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index);
+    }
+
+    static void checkCertificate(X509Certificate cert)
+        throws AnnotatedException
+    {
+        try
+        {
+            TBSCertificate.getInstance(cert.getTBSCertificate());
+        }
+        catch (CertificateEncodingException e)
+        {
+            throw new AnnotatedException("unable to process TBSCertificate", e);
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw new AnnotatedException(e.getMessage());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
new file mode 100644
index 0000000..24a38d7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
@@ -0,0 +1,1935 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralSubtree;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Integers;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKIXNameConstraintValidator
+{
+    private Set excludedSubtreesDN = new HashSet();
+
+    private Set excludedSubtreesDNS = new HashSet();
+
+    private Set excludedSubtreesEmail = new HashSet();
+
+    private Set excludedSubtreesURI = new HashSet();
+
+    private Set excludedSubtreesIP = new HashSet();
+
+    private Set permittedSubtreesDN;
+
+    private Set permittedSubtreesDNS;
+
+    private Set permittedSubtreesEmail;
+
+    private Set permittedSubtreesURI;
+
+    private Set permittedSubtreesIP;
+
+    public PKIXNameConstraintValidator()
+    {
+    }
+
+    private static boolean withinDNSubtree(
+        ASN1Sequence dns,
+        ASN1Sequence subtree)
+    {
+        if (subtree.size() < 1)
+        {
+            return false;
+        }
+
+        if (subtree.size() > dns.size())
+        {
+            return false;
+        }
+
+        for (int j = subtree.size() - 1; j >= 0; j--)
+        {
+            if (!subtree.getObjectAt(j).equals(dns.getObjectAt(j)))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public void checkPermittedDN(ASN1Sequence dns)
+        throws PKIXNameConstraintValidatorException
+    {
+        checkPermittedDN(permittedSubtreesDN, dns);
+    }
+
+    public void checkExcludedDN(ASN1Sequence dns)
+        throws PKIXNameConstraintValidatorException
+    {
+        checkExcludedDN(excludedSubtreesDN, dns);
+    }
+
+    private void checkPermittedDN(Set permitted, ASN1Sequence dns)
+        throws PKIXNameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        if (permitted.isEmpty() && dns.size() == 0)
+        {
+            return;
+        }
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+            if (withinDNSubtree(dns, subtree))
+            {
+                return;
+            }
+        }
+
+        throw new PKIXNameConstraintValidatorException(
+            "Subject distinguished name is not from a permitted subtree");
+    }
+
+    private void checkExcludedDN(Set excluded, ASN1Sequence dns)
+        throws PKIXNameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+            if (withinDNSubtree(dns, subtree))
+            {
+                throw new PKIXNameConstraintValidatorException(
+                    "Subject distinguished name is from an excluded subtree");
+            }
+        }
+    }
+
+    private Set intersectDN(Set permitted, Set dns)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = dns.iterator(); it.hasNext();)
+        {
+            ASN1Sequence dn = ASN1Sequence.getInstance(((GeneralSubtree)it
+                .next()).getBase().getName().toASN1Primitive());
+            if (permitted == null)
+            {
+                if (dn != null)
+                {
+                    intersect.add(dn);
+                }
+            }
+            else
+            {
+                Iterator _iter = permitted.iterator();
+                while (_iter.hasNext())
+                {
+                    ASN1Sequence subtree = (ASN1Sequence)_iter.next();
+
+                    if (withinDNSubtree(dn, subtree))
+                    {
+                        intersect.add(dn);
+                    }
+                    else if (withinDNSubtree(subtree, dn))
+                    {
+                        intersect.add(subtree);
+                    }
+                }
+            }
+        }
+        return intersect;
+    }
+
+    private Set unionDN(Set excluded, ASN1Sequence dn)
+    {
+        if (excluded.isEmpty())
+        {
+            if (dn == null)
+            {
+                return excluded;
+            }
+            excluded.add(dn);
+
+            return excluded;
+        }
+        else
+        {
+            Set intersect = new HashSet();
+
+            Iterator it = excluded.iterator();
+            while (it.hasNext())
+            {
+                ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+                if (withinDNSubtree(dn, subtree))
+                {
+                    intersect.add(subtree);
+                }
+                else if (withinDNSubtree(subtree, dn))
+                {
+                    intersect.add(dn);
+                }
+                else
+                {
+                    intersect.add(subtree);
+                    intersect.add(dn);
+                }
+            }
+
+            return intersect;
+        }
+    }
+
+    private Set intersectEmail(Set permitted, Set emails)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = emails.iterator(); it.hasNext();)
+        {
+            String email = extractNameAsString(((GeneralSubtree)it.next())
+                .getBase());
+
+            if (permitted == null)
+            {
+                if (email != null)
+                {
+                    intersect.add(email);
+                }
+            }
+            else
+            {
+                Iterator it2 = permitted.iterator();
+                while (it2.hasNext())
+                {
+                    String _permitted = (String)it2.next();
+
+                    intersectEmail(email, _permitted, intersect);
+                }
+            }
+        }
+        return intersect;
+    }
+
+    private Set unionEmail(Set excluded, String email)
+    {
+        if (excluded.isEmpty())
+        {
+            if (email == null)
+            {
+                return excluded;
+            }
+            excluded.add(email);
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator it = excluded.iterator();
+            while (it.hasNext())
+            {
+                String _excluded = (String)it.next();
+
+                unionEmail(_excluded, email, union);
+            }
+
+            return union;
+        }
+    }
+
+    /**
+     * Returns the intersection of the permitted IP ranges in
+     * <code>permitted</code> with <code>ip</code>.
+     *
+     * @param permitted A <code>Set</code> of permitted IP addresses with
+     *                  their subnet mask as byte arrays.
+     * @param ips       The IP address with its subnet mask.
+     * @return The <code>Set</code> of permitted IP ranges intersected with
+     *         <code>ip</code>.
+     */
+    private Set intersectIP(Set permitted, Set ips)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = ips.iterator(); it.hasNext();)
+        {
+            byte[] ip = ASN1OctetString.getInstance(
+                ((GeneralSubtree)it.next()).getBase().getName()).getOctets();
+            if (permitted == null)
+            {
+                if (ip != null)
+                {
+                    intersect.add(ip);
+                }
+            }
+            else
+            {
+                Iterator it2 = permitted.iterator();
+                while (it2.hasNext())
+                {
+                    byte[] _permitted = (byte[])it2.next();
+                    intersect.addAll(intersectIPRange(_permitted, ip));
+                }
+            }
+        }
+        return intersect;
+    }
+
+    /**
+     * Returns the union of the excluded IP ranges in <code>excluded</code>
+     * with <code>ip</code>.
+     *
+     * @param excluded A <code>Set</code> of excluded IP addresses with their
+     *                 subnet mask as byte arrays.
+     * @param ip       The IP address with its subnet mask.
+     * @return The <code>Set</code> of excluded IP ranges unified with
+     *         <code>ip</code> as byte arrays.
+     */
+    private Set unionIP(Set excluded, byte[] ip)
+    {
+        if (excluded.isEmpty())
+        {
+            if (ip == null)
+            {
+                return excluded;
+            }
+            excluded.add(ip);
+
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator it = excluded.iterator();
+            while (it.hasNext())
+            {
+                byte[] _excluded = (byte[])it.next();
+                union.addAll(unionIPRange(_excluded, ip));
+            }
+
+            return union;
+        }
+    }
+
+    /**
+     * Calculates the union if two IP ranges.
+     *
+     * @param ipWithSubmask1 The first IP address with its subnet mask.
+     * @param ipWithSubmask2 The second IP address with its subnet mask.
+     * @return A <code>Set</code> with the union of both addresses.
+     */
+    private Set unionIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+    {
+        Set set = new HashSet();
+
+        // difficult, adding always all IPs is not wrong
+        if (Arrays.areEqual(ipWithSubmask1, ipWithSubmask2))
+        {
+            set.add(ipWithSubmask1);
+        }
+        else
+        {
+            set.add(ipWithSubmask1);
+            set.add(ipWithSubmask2);
+        }
+        return set;
+    }
+
+    /**
+     * Calculates the interesction if two IP ranges.
+     *
+     * @param ipWithSubmask1 The first IP address with its subnet mask.
+     * @param ipWithSubmask2 The second IP address with its subnet mask.
+     * @return A <code>Set</code> with the single IP address with its subnet
+     *         mask as a byte array or an empty <code>Set</code>.
+     */
+    private Set intersectIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+    {
+        if (ipWithSubmask1.length != ipWithSubmask2.length)
+        {
+            return Collections.EMPTY_SET;
+        }
+        byte[][] temp = extractIPsAndSubnetMasks(ipWithSubmask1, ipWithSubmask2);
+        byte ip1[] = temp[0];
+        byte subnetmask1[] = temp[1];
+        byte ip2[] = temp[2];
+        byte subnetmask2[] = temp[3];
+
+        byte minMax[][] = minMaxIPs(ip1, subnetmask1, ip2, subnetmask2);
+        byte[] min;
+        byte[] max;
+        max = min(minMax[1], minMax[3]);
+        min = max(minMax[0], minMax[2]);
+
+        // minimum IP address must be bigger than max
+        if (compareTo(min, max) == 1)
+        {
+            return Collections.EMPTY_SET;
+        }
+        // OR keeps all significant bits
+        byte[] ip = or(minMax[0], minMax[2]);
+        byte[] subnetmask = or(subnetmask1, subnetmask2);
+        return Collections.singleton(ipWithSubnetMask(ip, subnetmask));
+    }
+
+    /**
+     * Concatenates the IP address with its subnet mask.
+     *
+     * @param ip         The IP address.
+     * @param subnetMask Its subnet mask.
+     * @return The concatenated IP address with its subnet mask.
+     */
+    private byte[] ipWithSubnetMask(byte[] ip, byte[] subnetMask)
+    {
+        int ipLength = ip.length;
+        byte[] temp = new byte[ipLength * 2];
+        System.arraycopy(ip, 0, temp, 0, ipLength);
+        System.arraycopy(subnetMask, 0, temp, ipLength, ipLength);
+        return temp;
+    }
+
+    /**
+     * Splits the IP addresses and their subnet mask.
+     *
+     * @param ipWithSubmask1 The first IP address with the subnet mask.
+     * @param ipWithSubmask2 The second IP address with the subnet mask.
+     * @return An array with two elements. Each element contains the IP address
+     *         and the subnet mask in this order.
+     */
+    private byte[][] extractIPsAndSubnetMasks(
+        byte[] ipWithSubmask1,
+        byte[] ipWithSubmask2)
+    {
+        int ipLength = ipWithSubmask1.length / 2;
+        byte ip1[] = new byte[ipLength];
+        byte subnetmask1[] = new byte[ipLength];
+        System.arraycopy(ipWithSubmask1, 0, ip1, 0, ipLength);
+        System.arraycopy(ipWithSubmask1, ipLength, subnetmask1, 0, ipLength);
+
+        byte ip2[] = new byte[ipLength];
+        byte subnetmask2[] = new byte[ipLength];
+        System.arraycopy(ipWithSubmask2, 0, ip2, 0, ipLength);
+        System.arraycopy(ipWithSubmask2, ipLength, subnetmask2, 0, ipLength);
+        return new byte[][]
+            {ip1, subnetmask1, ip2, subnetmask2};
+    }
+
+    /**
+     * Based on the two IP addresses and their subnet masks the IP range is
+     * computed for each IP address - subnet mask pair and returned as the
+     * minimum IP address and the maximum address of the range.
+     *
+     * @param ip1         The first IP address.
+     * @param subnetmask1 The subnet mask of the first IP address.
+     * @param ip2         The second IP address.
+     * @param subnetmask2 The subnet mask of the second IP address.
+     * @return A array with two elements. The first/second element contains the
+     *         min and max IP address of the first/second IP address and its
+     *         subnet mask.
+     */
+    private byte[][] minMaxIPs(
+        byte[] ip1,
+        byte[] subnetmask1,
+        byte[] ip2,
+        byte[] subnetmask2)
+    {
+        int ipLength = ip1.length;
+        byte[] min1 = new byte[ipLength];
+        byte[] max1 = new byte[ipLength];
+
+        byte[] min2 = new byte[ipLength];
+        byte[] max2 = new byte[ipLength];
+
+        for (int i = 0; i < ipLength; i++)
+        {
+            min1[i] = (byte)(ip1[i] & subnetmask1[i]);
+            max1[i] = (byte)(ip1[i] & subnetmask1[i] | ~subnetmask1[i]);
+
+            min2[i] = (byte)(ip2[i] & subnetmask2[i]);
+            max2[i] = (byte)(ip2[i] & subnetmask2[i] | ~subnetmask2[i]);
+        }
+
+        return new byte[][]{min1, max1, min2, max2};
+    }
+
+    private void checkPermittedEmail(Set permitted, String email)
+        throws PKIXNameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            if (emailIsConstrained(email, str))
+            {
+                return;
+            }
+        }
+
+        if (email.length() == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+
+        throw new PKIXNameConstraintValidatorException(
+            "Subject email address is not from a permitted subtree.");
+    }
+
+    private void checkExcludedEmail(Set excluded, String email)
+        throws PKIXNameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            String str = (String)it.next();
+
+            if (emailIsConstrained(email, str))
+            {
+                throw new PKIXNameConstraintValidatorException(
+                    "Email address is from an excluded subtree.");
+            }
+        }
+    }
+
+    /**
+     * Checks if the IP <code>ip</code> is included in the permitted set
+     * <code>permitted</code>.
+     *
+     * @param permitted A <code>Set</code> of permitted IP addresses with
+     *                  their subnet mask as byte arrays.
+     * @param ip        The IP address.
+     * @throws PKIXNameConstraintValidatorException
+     *          if the IP is not permitted.
+     */
+    private void checkPermittedIP(Set permitted, byte[] ip)
+        throws PKIXNameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            byte[] ipWithSubnet = (byte[])it.next();
+
+            if (isIPConstrained(ip, ipWithSubnet))
+            {
+                return;
+            }
+        }
+        if (ip.length == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+        throw new PKIXNameConstraintValidatorException(
+            "IP is not from a permitted subtree.");
+    }
+
+    /**
+     * Checks if the IP <code>ip</code> is included in the excluded set
+     * <code>excluded</code>.
+     *
+     * @param excluded A <code>Set</code> of excluded IP addresses with their
+     *                 subnet mask as byte arrays.
+     * @param ip       The IP address.
+     * @throws PKIXNameConstraintValidatorException
+     *          if the IP is excluded.
+     */
+    private void checkExcludedIP(Set excluded, byte[] ip)
+        throws PKIXNameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            byte[] ipWithSubnet = (byte[])it.next();
+
+            if (isIPConstrained(ip, ipWithSubnet))
+            {
+                throw new PKIXNameConstraintValidatorException(
+                    "IP is from an excluded subtree.");
+            }
+        }
+    }
+
+    /**
+     * Checks if the IP address <code>ip</code> is constrained by
+     * <code>constraint</code>.
+     *
+     * @param ip         The IP address.
+     * @param constraint The constraint. This is an IP address concatenated with
+     *                   its subnetmask.
+     * @return <code>true</code> if constrained, <code>false</code>
+     *         otherwise.
+     */
+    private boolean isIPConstrained(byte ip[], byte[] constraint)
+    {
+        int ipLength = ip.length;
+
+        if (ipLength != (constraint.length / 2))
+        {
+            return false;
+        }
+
+        byte[] subnetMask = new byte[ipLength];
+        System.arraycopy(constraint, ipLength, subnetMask, 0, ipLength);
+
+        byte[] permittedSubnetAddress = new byte[ipLength];
+
+        byte[] ipSubnetAddress = new byte[ipLength];
+
+        // the resulting IP address by applying the subnet mask
+        for (int i = 0; i < ipLength; i++)
+        {
+            permittedSubnetAddress[i] = (byte)(constraint[i] & subnetMask[i]);
+            ipSubnetAddress[i] = (byte)(ip[i] & subnetMask[i]);
+        }
+
+        return Arrays.areEqual(permittedSubnetAddress, ipSubnetAddress);
+    }
+
+    private boolean emailIsConstrained(String email, String constraint)
+    {
+        String sub = email.substring(email.indexOf('@') + 1);
+        // a particular mailbox or @domain
+        if (constraint.indexOf('@') != -1)
+        {
+            if (email.equalsIgnoreCase(constraint))
+            {
+                return true;
+            }
+            if (sub.equalsIgnoreCase(constraint.substring(1)))
+            {
+                return true;
+            }
+        }
+        // on particular host
+        else if (!(constraint.charAt(0) == '.'))
+        {
+            if (sub.equalsIgnoreCase(constraint))
+            {
+                return true;
+            }
+        }
+        // address in sub domain
+        else if (withinDomain(sub, constraint))
+        {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean withinDomain(String testDomain, String domain)
+    {
+        String tempDomain = domain;
+        if (tempDomain.startsWith("."))
+        {
+            tempDomain = tempDomain.substring(1);
+        }
+        String[] domainParts = Strings.split(tempDomain, '.');
+        String[] testDomainParts = Strings.split(testDomain, '.');
+        // must have at least one subdomain
+        if (testDomainParts.length <= domainParts.length)
+        {
+            return false;
+        }
+        int d = testDomainParts.length - domainParts.length;
+        for (int i = -1; i < domainParts.length; i++)
+        {
+            if (i == -1)
+            {
+                if (testDomainParts[i + d].equals(""))
+                {
+                    return false;
+                }
+            }
+            else if (!domainParts[i].equalsIgnoreCase(testDomainParts[i + d]))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void checkPermittedDNS(Set permitted, String dns)
+        throws PKIXNameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            // is sub domain
+            if (withinDomain(dns, str) || dns.equalsIgnoreCase(str))
+            {
+                return;
+            }
+        }
+        if (dns.length() == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+        throw new PKIXNameConstraintValidatorException(
+            "DNS is not from a permitted subtree.");
+    }
+
+    private void checkExcludedDNS(Set excluded, String dns)
+        throws PKIXNameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            // is sub domain or the same
+            if (withinDomain(dns, str) || dns.equalsIgnoreCase(str))
+            {
+                throw new PKIXNameConstraintValidatorException(
+                    "DNS is from an excluded subtree.");
+            }
+        }
+    }
+
+    /**
+     * The common part of <code>email1</code> and <code>email2</code> is
+     * added to the union <code>union</code>. If <code>email1</code> and
+     * <code>email2</code> have nothing in common they are added both.
+     *
+     * @param email1 Email address constraint 1.
+     * @param email2 Email address constraint 2.
+     * @param union  The union.
+     */
+    private void unionEmail(String email1, String email2, Set union)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email1 specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+    }
+
+    private void unionURI(String email1, String email2, Set union)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email1 specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+    }
+
+    private Set intersectDNS(Set permitted, Set dnss)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = dnss.iterator(); it.hasNext();)
+        {
+            String dns = extractNameAsString(((GeneralSubtree)it.next())
+                .getBase());
+            if (permitted == null)
+            {
+                if (dns != null)
+                {
+                    intersect.add(dns);
+                }
+            }
+            else
+            {
+                Iterator _iter = permitted.iterator();
+                while (_iter.hasNext())
+                {
+                    String _permitted = (String)_iter.next();
+
+                    if (withinDomain(_permitted, dns))
+                    {
+                        intersect.add(_permitted);
+                    }
+                    else if (withinDomain(dns, _permitted))
+                    {
+                        intersect.add(dns);
+                    }
+                }
+            }
+        }
+
+        return intersect;
+    }
+
+    protected Set unionDNS(Set excluded, String dns)
+    {
+        if (excluded.isEmpty())
+        {
+            if (dns == null)
+            {
+                return excluded;
+            }
+            excluded.add(dns);
+
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator _iter = excluded.iterator();
+            while (_iter.hasNext())
+            {
+                String _permitted = (String)_iter.next();
+
+                if (withinDomain(_permitted, dns))
+                {
+                    union.add(dns);
+                }
+                else if (withinDomain(dns, _permitted))
+                {
+                    union.add(_permitted);
+                }
+                else
+                {
+                    union.add(_permitted);
+                    union.add(dns);
+                }
+            }
+
+            return union;
+        }
+    }
+
+    /**
+     * The most restricting part from <code>email1</code> and
+     * <code>email2</code> is added to the intersection <code>intersect</code>.
+     *
+     * @param email1    Email address constraint 1.
+     * @param email2    Email address constraint 2.
+     * @param intersect The intersection.
+     */
+    private void intersectEmail(String email1, String email2, Set intersect)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+        // email specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+        }
+        // email1 specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email2.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+    }
+
+    private void checkExcludedURI(Set excluded, String uri)
+        throws PKIXNameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            if (isUriConstrained(uri, str))
+            {
+                throw new PKIXNameConstraintValidatorException(
+                    "URI is from an excluded subtree.");
+            }
+        }
+    }
+
+    private Set intersectURI(Set permitted, Set uris)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = uris.iterator(); it.hasNext();)
+        {
+            String uri = extractNameAsString(((GeneralSubtree)it.next())
+                .getBase());
+            if (permitted == null)
+            {
+                if (uri != null)
+                {
+                    intersect.add(uri);
+                }
+            }
+            else
+            {
+                Iterator _iter = permitted.iterator();
+                while (_iter.hasNext())
+                {
+                    String _permitted = (String)_iter.next();
+                    intersectURI(_permitted, uri, intersect);
+                }
+            }
+        }
+        return intersect;
+    }
+
+    private Set unionURI(Set excluded, String uri)
+    {
+        if (excluded.isEmpty())
+        {
+            if (uri == null)
+            {
+                return excluded;
+            }
+            excluded.add(uri);
+
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator _iter = excluded.iterator();
+            while (_iter.hasNext())
+            {
+                String _excluded = (String)_iter.next();
+
+                unionURI(_excluded, uri, union);
+            }
+
+            return union;
+        }
+    }
+
+    private void intersectURI(String email1, String email2, Set intersect)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+        // email specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+        }
+        // email1 specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email2.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+    }
+
+    private void checkPermittedURI(Set permitted, String uri)
+        throws PKIXNameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            if (isUriConstrained(uri, str))
+            {
+                return;
+            }
+        }
+        if (uri.length() == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+        throw new PKIXNameConstraintValidatorException(
+            "URI is not from a permitted subtree.");
+    }
+
+    private boolean isUriConstrained(String uri, String constraint)
+    {
+        String host = extractHostFromURL(uri);
+        // a host
+        if (!constraint.startsWith("."))
+        {
+            if (host.equalsIgnoreCase(constraint))
+            {
+                return true;
+            }
+        }
+
+        // in sub domain or domain
+        else if (withinDomain(host, constraint))
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    private static String extractHostFromURL(String url)
+    {
+        // see RFC 1738
+        // remove ':' after protocol, e.g. http:
+        String sub = url.substring(url.indexOf(':') + 1);
+        // extract host from Common Internet Scheme Syntax, e.g. http://
+        if (sub.indexOf("//") != -1)
+        {
+            sub = sub.substring(sub.indexOf("//") + 2);
+        }
+        // first remove port, e.g. http://test.com:21
+        if (sub.lastIndexOf(':') != -1)
+        {
+            sub = sub.substring(0, sub.lastIndexOf(':'));
+        }
+        // remove user and password, e.g. http://john:password@test.com
+        sub = sub.substring(sub.indexOf(':') + 1);
+        sub = sub.substring(sub.indexOf('@') + 1);
+        // remove local parts, e.g. http://test.com/bla
+        if (sub.indexOf('/') != -1)
+        {
+            sub = sub.substring(0, sub.indexOf('/'));
+        }
+        return sub;
+    }
+
+    /**
+     * Checks if the given GeneralName is in the permitted set.
+     *
+     * @param name The GeneralName
+     * @throws PKIXNameConstraintValidatorException
+     *          If the <code>name</code>
+     */
+    public void checkPermitted(GeneralName name)
+        throws PKIXNameConstraintValidatorException
+    {
+        switch (name.getTagNo())
+        {
+            case 1:
+                checkPermittedEmail(permittedSubtreesEmail,
+                    extractNameAsString(name));
+                break;
+            case 2:
+                checkPermittedDNS(permittedSubtreesDNS, DERIA5String.getInstance(
+                    name.getName()).getString());
+                break;
+            case 4:
+                checkPermittedDN(ASN1Sequence.getInstance(name.getName()
+                    .toASN1Primitive()));
+                break;
+            case 6:
+                checkPermittedURI(permittedSubtreesURI, DERIA5String.getInstance(
+                    name.getName()).getString());
+                break;
+            case 7:
+                byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets();
+
+                checkPermittedIP(permittedSubtreesIP, ip);
+        }
+    }
+
+    /**
+     * Check if the given GeneralName is contained in the excluded set.
+     *
+     * @param name The GeneralName.
+     * @throws PKIXNameConstraintValidatorException
+     *          If the <code>name</code> is
+     *          excluded.
+     */
+    public void checkExcluded(GeneralName name)
+        throws PKIXNameConstraintValidatorException
+    {
+        switch (name.getTagNo())
+        {
+            case 1:
+                checkExcludedEmail(excludedSubtreesEmail, extractNameAsString(name));
+                break;
+            case 2:
+                checkExcludedDNS(excludedSubtreesDNS, DERIA5String.getInstance(
+                    name.getName()).getString());
+                break;
+            case 4:
+                checkExcludedDN(ASN1Sequence.getInstance(name.getName()
+                    .toASN1Primitive()));
+                break;
+            case 6:
+                checkExcludedURI(excludedSubtreesURI, DERIA5String.getInstance(
+                    name.getName()).getString());
+                break;
+            case 7:
+                byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets();
+
+                checkExcludedIP(excludedSubtreesIP, ip);
+        }
+    }
+
+    public void intersectPermittedSubtree(GeneralSubtree permitted)
+    {
+        intersectPermittedSubtree(new GeneralSubtree[] { permitted });
+    }
+
+    /**
+     * Updates the permitted set of these name constraints with the intersection
+     * with the given subtree.
+     *
+     * @param permitted The permitted subtrees
+     */
+
+    public void intersectPermittedSubtree(GeneralSubtree[] permitted)
+    {
+        Map subtreesMap = new HashMap();
+
+        // group in sets in a map ordered by tag no.
+        for (int i = 0; i != permitted.length; i++)
+        {
+            GeneralSubtree subtree = permitted[i];
+            Integer tagNo = Integers.valueOf(subtree.getBase().getTagNo());
+            if (subtreesMap.get(tagNo) == null)
+            {
+                subtreesMap.put(tagNo, new HashSet());
+            }
+            ((Set)subtreesMap.get(tagNo)).add(subtree);
+        }
+
+        for (Iterator it = subtreesMap.entrySet().iterator(); it.hasNext();)
+        {
+            Map.Entry entry = (Map.Entry)it.next();
+
+            // go through all subtree groups
+            switch (((Integer)entry.getKey()).intValue())
+            {
+                case 1:
+                    permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail,
+                        (Set)entry.getValue());
+                    break;
+                case 2:
+                    permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS,
+                        (Set)entry.getValue());
+                    break;
+                case 4:
+                    permittedSubtreesDN = intersectDN(permittedSubtreesDN,
+                        (Set)entry.getValue());
+                    break;
+                case 6:
+                    permittedSubtreesURI = intersectURI(permittedSubtreesURI,
+                        (Set)entry.getValue());
+                    break;
+                case 7:
+                    permittedSubtreesIP = intersectIP(permittedSubtreesIP,
+                        (Set)entry.getValue());
+            }
+        }
+    }
+
+    private String extractNameAsString(GeneralName name)
+    {
+        return DERIA5String.getInstance(name.getName()).getString();
+    }
+
+    public void intersectEmptyPermittedSubtree(int nameType)
+    {
+        switch (nameType)
+        {
+        case 1:
+            permittedSubtreesEmail = new HashSet();
+            break;
+        case 2:
+            permittedSubtreesDNS = new HashSet();
+            break;
+        case 4:
+            permittedSubtreesDN = new HashSet();
+            break;
+        case 6:
+            permittedSubtreesURI = new HashSet();
+            break;
+        case 7:
+            permittedSubtreesIP = new HashSet();
+        }
+    }
+
+    /**
+     * Adds a subtree to the excluded set of these name constraints.
+     *
+     * @param subtree A subtree with an excluded GeneralName.
+     */
+    public void addExcludedSubtree(GeneralSubtree subtree)
+    {
+        GeneralName base = subtree.getBase();
+
+        switch (base.getTagNo())
+        {
+            case 1:
+                excludedSubtreesEmail = unionEmail(excludedSubtreesEmail,
+                    extractNameAsString(base));
+                break;
+            case 2:
+                excludedSubtreesDNS = unionDNS(excludedSubtreesDNS,
+                    extractNameAsString(base));
+                break;
+            case 4:
+                excludedSubtreesDN = unionDN(excludedSubtreesDN,
+                    (ASN1Sequence)base.getName().toASN1Primitive());
+                break;
+            case 6:
+                excludedSubtreesURI = unionURI(excludedSubtreesURI,
+                    extractNameAsString(base));
+                break;
+            case 7:
+                excludedSubtreesIP = unionIP(excludedSubtreesIP, ASN1OctetString
+                    .getInstance(base.getName()).getOctets());
+                break;
+        }
+    }
+
+    /**
+     * Returns the maximum IP address.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return The maximum IP address.
+     */
+    private static byte[] max(byte[] ip1, byte[] ip2)
+    {
+        for (int i = 0; i < ip1.length; i++)
+        {
+            if ((ip1[i] & 0xFFFF) > (ip2[i] & 0xFFFF))
+            {
+                return ip1;
+            }
+        }
+        return ip2;
+    }
+
+    /**
+     * Returns the minimum IP address.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return The minimum IP address.
+     */
+    private static byte[] min(byte[] ip1, byte[] ip2)
+    {
+        for (int i = 0; i < ip1.length; i++)
+        {
+            if ((ip1[i] & 0xFFFF) < (ip2[i] & 0xFFFF))
+            {
+                return ip1;
+            }
+        }
+        return ip2;
+    }
+
+    /**
+     * Compares IP address <code>ip1</code> with <code>ip2</code>. If ip1
+     * is equal to ip2 0 is returned. If ip1 is bigger 1 is returned, -1
+     * otherwise.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return 0 if ip1 is equal to ip2, 1 if ip1 is bigger, -1 otherwise.
+     */
+    private static int compareTo(byte[] ip1, byte[] ip2)
+    {
+        if (Arrays.areEqual(ip1, ip2))
+        {
+            return 0;
+        }
+        if (Arrays.areEqual(max(ip1, ip2), ip1))
+        {
+            return 1;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the logical OR of the IP addresses <code>ip1</code> and
+     * <code>ip2</code>.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return The OR of <code>ip1</code> and <code>ip2</code>.
+     */
+    private static byte[] or(byte[] ip1, byte[] ip2)
+    {
+        byte[] temp = new byte[ip1.length];
+        for (int i = 0; i < ip1.length; i++)
+        {
+            temp[i] = (byte)(ip1[i] | ip2[i]);
+        }
+        return temp;
+    }
+
+    public int hashCode()
+    {
+        return hashCollection(excludedSubtreesDN)
+            + hashCollection(excludedSubtreesDNS)
+            + hashCollection(excludedSubtreesEmail)
+            + hashCollection(excludedSubtreesIP)
+            + hashCollection(excludedSubtreesURI)
+            + hashCollection(permittedSubtreesDN)
+            + hashCollection(permittedSubtreesDNS)
+            + hashCollection(permittedSubtreesEmail)
+            + hashCollection(permittedSubtreesIP)
+            + hashCollection(permittedSubtreesURI);
+    }
+
+    private int hashCollection(Collection coll)
+    {
+        if (coll == null)
+        {
+            return 0;
+        }
+        int hash = 0;
+        Iterator it1 = coll.iterator();
+        while (it1.hasNext())
+        {
+            Object o = it1.next();
+            if (o instanceof byte[])
+            {
+                hash += Arrays.hashCode((byte[])o);
+            }
+            else
+            {
+                hash += o.hashCode();
+            }
+        }
+        return hash;
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof PKIXNameConstraintValidator))
+        {
+            return false;
+        }
+        PKIXNameConstraintValidator constraintValidator = (PKIXNameConstraintValidator)o;
+        return collectionsAreEqual(constraintValidator.excludedSubtreesDN, excludedSubtreesDN)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesDNS, excludedSubtreesDNS)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesEmail, excludedSubtreesEmail)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesIP, excludedSubtreesIP)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesURI, excludedSubtreesURI)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesDN, permittedSubtreesDN)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesDNS, permittedSubtreesDNS)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesEmail, permittedSubtreesEmail)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesIP, permittedSubtreesIP)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI);
+    }
+
+    private boolean collectionsAreEqual(Collection coll1, Collection coll2)
+    {
+        if (coll1 == coll2)
+        {
+            return true;
+        }
+        if (coll1 == null || coll2 == null)
+        {
+            return false;
+        }
+        if (coll1.size() != coll2.size())
+        {
+            return false;
+        }
+        Iterator it1 = coll1.iterator();
+
+        while (it1.hasNext())
+        {
+            Object a = it1.next();
+            Iterator it2 = coll2.iterator();
+            boolean found = false;
+            while (it2.hasNext())
+            {
+                Object b = it2.next();
+                if (equals(a, b))
+                {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean equals(Object o1, Object o2)
+    {
+        if (o1 == o2)
+        {
+            return true;
+        }
+        if (o1 == null || o2 == null)
+        {
+            return false;
+        }
+        if (o1 instanceof byte[] && o2 instanceof byte[])
+        {
+            return Arrays.areEqual((byte[])o1, (byte[])o2);
+        }
+        else
+        {
+            return o1.equals(o2);
+        }
+    }
+
+    /**
+     * Stringifies an IPv4 or v6 address with subnet mask.
+     *
+     * @param ip The IP with subnet mask.
+     * @return The stringified IP address.
+     */
+    private String stringifyIP(byte[] ip)
+    {
+        String temp = "";
+        for (int i = 0; i < ip.length / 2; i++)
+        {
+            temp += Integer.toString(ip[i] & 0x00FF) + ".";
+        }
+        temp = temp.substring(0, temp.length() - 1);
+        temp += "/";
+        for (int i = ip.length / 2; i < ip.length; i++)
+        {
+            temp += Integer.toString(ip[i] & 0x00FF) + ".";
+        }
+        temp = temp.substring(0, temp.length() - 1);
+        return temp;
+    }
+
+    private String stringifyIPCollection(Set ips)
+    {
+        String temp = "";
+        temp += "[";
+        for (Iterator it = ips.iterator(); it.hasNext();)
+        {
+            temp += stringifyIP((byte[])it.next()) + ",";
+        }
+        if (temp.length() > 1)
+        {
+            temp = temp.substring(0, temp.length() - 1);
+        }
+        temp += "]";
+        return temp;
+    }
+
+    public String toString()
+    {
+        String temp = "";
+        temp += "permitted:\n";
+        if (permittedSubtreesDN != null)
+        {
+            temp += "DN:\n";
+            temp += permittedSubtreesDN.toString() + "\n";
+        }
+        if (permittedSubtreesDNS != null)
+        {
+            temp += "DNS:\n";
+            temp += permittedSubtreesDNS.toString() + "\n";
+        }
+        if (permittedSubtreesEmail != null)
+        {
+            temp += "Email:\n";
+            temp += permittedSubtreesEmail.toString() + "\n";
+        }
+        if (permittedSubtreesURI != null)
+        {
+            temp += "URI:\n";
+            temp += permittedSubtreesURI.toString() + "\n";
+        }
+        if (permittedSubtreesIP != null)
+        {
+            temp += "IP:\n";
+            temp += stringifyIPCollection(permittedSubtreesIP) + "\n";
+        }
+        temp += "excluded:\n";
+        if (!excludedSubtreesDN.isEmpty())
+        {
+            temp += "DN:\n";
+            temp += excludedSubtreesDN.toString() + "\n";
+        }
+        if (!excludedSubtreesDNS.isEmpty())
+        {
+            temp += "DNS:\n";
+            temp += excludedSubtreesDNS.toString() + "\n";
+        }
+        if (!excludedSubtreesEmail.isEmpty())
+        {
+            temp += "Email:\n";
+            temp += excludedSubtreesEmail.toString() + "\n";
+        }
+        if (!excludedSubtreesURI.isEmpty())
+        {
+            temp += "URI:\n";
+            temp += excludedSubtreesURI.toString() + "\n";
+        }
+        if (!excludedSubtreesIP.isEmpty())
+        {
+            temp += "IP:\n";
+            temp += stringifyIPCollection(excludedSubtreesIP) + "\n";
+        }
+        return temp;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXNameConstraintValidatorException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXNameConstraintValidatorException.java
new file mode 100644
index 0000000..f29377e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXNameConstraintValidatorException.java
@@ -0,0 +1,14 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKIXNameConstraintValidatorException
+    extends Exception
+{
+    public PKIXNameConstraintValidatorException(String msg)
+    {
+        super(msg);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXPolicyNode.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXPolicyNode.java
new file mode 100644
index 0000000..763e553
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PKIXPolicyNode.java
@@ -0,0 +1,177 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.security.cert.PolicyNode;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PKIXPolicyNode
+    implements PolicyNode
+{
+    protected List       children;
+    protected int        depth;
+    protected Set        expectedPolicies;
+    protected PolicyNode parent;
+    protected Set        policyQualifiers;
+    protected String     validPolicy;
+    protected boolean    critical;
+    
+    /*  
+     *  
+     *  CONSTRUCTORS
+     *  
+     */ 
+    
+    public PKIXPolicyNode(
+        List       _children,
+        int        _depth,
+        Set        _expectedPolicies,
+        PolicyNode _parent,
+        Set        _policyQualifiers,
+        String     _validPolicy,
+        boolean    _critical)
+    {
+        children         = _children;
+        depth            = _depth;
+        expectedPolicies = _expectedPolicies;
+        parent           = _parent;
+        policyQualifiers = _policyQualifiers;
+        validPolicy      = _validPolicy;
+        critical         = _critical;
+    }
+    
+    public void addChild(
+        PKIXPolicyNode _child)
+    {
+        children.add(_child);
+        _child.setParent(this);
+    }
+    
+    public Iterator getChildren()
+    {
+        return children.iterator();
+    }
+    
+    public int getDepth()
+    {
+        return depth;
+    }
+    
+    public Set getExpectedPolicies()
+    {
+        return expectedPolicies;
+    }
+    
+    public PolicyNode getParent()
+    {
+        return parent;
+    }
+    
+    public Set getPolicyQualifiers()
+    {
+        return policyQualifiers;
+    }
+    
+    public String getValidPolicy()
+    {
+        return validPolicy;
+    }
+    
+    public boolean hasChildren()
+    {
+        return !children.isEmpty();
+    }
+    
+    public boolean isCritical()
+    {
+        return critical;
+    }
+    
+    public void removeChild(PKIXPolicyNode _child)
+    {
+        children.remove(_child);
+    }
+    
+    public void setCritical(boolean _critical)
+    {
+        critical = _critical;
+    }
+    
+    public void setParent(PKIXPolicyNode _parent)
+    {
+        parent = _parent;
+    }
+    
+    public String toString()
+    {
+        return toString("");
+    }
+    
+    public String toString(String _indent)
+    {
+        StringBuffer _buf = new StringBuffer();
+        _buf.append(_indent);
+        _buf.append(validPolicy);
+        _buf.append(" {\n");
+        
+        for(int i = 0; i < children.size(); i++)
+        {
+            _buf.append(((PKIXPolicyNode)children.get(i)).toString(_indent + "    "));
+        }
+        
+        _buf.append(_indent);
+        _buf.append("}\n");
+        return _buf.toString();
+    }
+    
+    public Object clone()
+    {
+        return copy();
+    }
+    
+    public PKIXPolicyNode copy()
+    {
+        Set     _expectedPolicies = new HashSet();
+        Iterator _iter = expectedPolicies.iterator();
+        while (_iter.hasNext())
+        {
+            _expectedPolicies.add(new String((String)_iter.next()));
+        }
+        
+        Set     _policyQualifiers = new HashSet();
+        _iter = policyQualifiers.iterator();
+        while (_iter.hasNext())
+        {
+            _policyQualifiers.add(new String((String)_iter.next()));
+        }
+        
+        PKIXPolicyNode _node = new PKIXPolicyNode(new ArrayList(),
+                                                  depth,
+                                                  _expectedPolicies,
+                                                  null,
+                                                  _policyQualifiers,
+                                                  new String(validPolicy),
+                                                  critical);
+        
+        _iter = children.iterator();
+        while (_iter.hasNext())
+        {
+            PKIXPolicyNode _child = ((PKIXPolicyNode)_iter.next()).copy();
+            _child.setParent(_node);
+            _node.addChild(_child);
+        }
+        
+        return _node;
+    }
+
+    public void setExpectedPolicies(Set expectedPolicies)
+    {
+        this.expectedPolicies = expectedPolicies;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PrincipalUtils.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PrincipalUtils.java
new file mode 100644
index 0000000..a2a0052
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/PrincipalUtils.java
@@ -0,0 +1,54 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.x509.X509AttributeCertificate;
+
+class PrincipalUtils
+{
+    static X500Name getSubjectPrincipal(X509Certificate cert)
+    {
+        return X500Name.getInstance(cert.getSubjectX500Principal().getEncoded());
+    }
+
+    static X500Name getIssuerPrincipal(X509CRL crl)
+    {
+        return X500Name.getInstance(crl.getIssuerX500Principal().getEncoded());
+    }
+
+    static X500Name getIssuerPrincipal(X509Certificate cert)
+    {
+        return X500Name.getInstance(cert.getIssuerX500Principal().getEncoded());
+    }
+
+    static X500Name getCA(TrustAnchor trustAnchor)
+    {
+        return X500Name.getInstance(trustAnchor.getCA().getEncoded());
+    }
+
+    /**
+     * Returns the issuer of an attribute certificate or certificate.
+     *
+     * @param cert The attribute certificate or certificate.
+     * @return The issuer as <code>X500Principal</code>.
+     */
+    static X500Name getEncodedIssuerPrincipal(
+        Object cert)
+    {
+        if (cert instanceof X509Certificate)
+        {
+            return getIssuerPrincipal((X509Certificate)cert);
+        }
+        else
+        {
+            return X500Name.getInstance(((X500Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0]).getEncoded());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
new file mode 100644
index 0000000..37fcf3d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
@@ -0,0 +1,2616 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLSelector;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509Extension;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1String;
+import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x500.RDN;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x500.style.BCStyle;
+import com.android.internal.org.bouncycastle.asn1.x509.BasicConstraints;
+import com.android.internal.org.bouncycastle.asn1.x509.CRLDistPoint;
+import com.android.internal.org.bouncycastle.asn1.x509.CRLReason;
+import com.android.internal.org.bouncycastle.asn1.x509.DistributionPoint;
+import com.android.internal.org.bouncycastle.asn1.x509.DistributionPointName;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralNames;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralSubtree;
+import com.android.internal.org.bouncycastle.asn1.x509.IssuingDistributionPoint;
+import com.android.internal.org.bouncycastle.asn1.x509.NameConstraints;
+import com.android.internal.org.bouncycastle.asn1.x509.PolicyInformation;
+import com.android.internal.org.bouncycastle.jcajce.PKIXCRLStore;
+import com.android.internal.org.bouncycastle.jcajce.PKIXCRLStoreSelector;
+import com.android.internal.org.bouncycastle.jcajce.PKIXCertStoreSelector;
+import com.android.internal.org.bouncycastle.jcajce.PKIXExtendedBuilderParameters;
+import com.android.internal.org.bouncycastle.jcajce.PKIXExtendedParameters;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.jce.exception.ExtCertPathValidatorException;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+class RFC3280CertPathUtilities
+{
+    private static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
+    /**
+     * If the complete CRL includes an issuing distribution point (IDP) CRL
+     * extension check the following:
+     * <p>
+     * (i) If the distribution point name is present in the IDP CRL extension
+     * and the distribution field is present in the DP, then verify that one of
+     * the names in the IDP matches one of the names in the DP. If the
+     * distribution point name is present in the IDP CRL extension and the
+     * distribution field is omitted from the DP, then verify that one of the
+     * names in the IDP matches one of the names in the cRLIssuer field of the
+     * DP.
+     * </p>
+     * <p>
+     * (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL
+     * extension, verify that the certificate does not include the basic
+     * constraints extension with the cA boolean asserted.
+     * </p>
+     * <p>
+     * (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL
+     * extension, verify that the certificate includes the basic constraints
+     * extension with the cA boolean asserted.
+     * </p>
+     * <p>
+     * (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted.
+     * </p>
+     *
+     * @param dp   The distribution point.
+     * @param cert The certificate.
+     * @param crl  The CRL.
+     * @throws AnnotatedException if one of the conditions is not met or an error occurs.
+     */
+    protected static void processCRLB2(
+        DistributionPoint dp,
+        Object cert,
+        X509CRL crl)
+        throws AnnotatedException
+    {
+        IssuingDistributionPoint idp = null;
+        try
+        {
+            idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+                RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+        }
+        catch (Exception e)
+        {
+            throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+        }
+        // (b) (2) (i)
+        // distribution point name is present
+        if (idp != null)
+        {
+            if (idp.getDistributionPoint() != null)
+            {
+                // make list of names
+                DistributionPointName dpName = IssuingDistributionPoint.getInstance(idp).getDistributionPoint();
+                List names = new ArrayList();
+
+                if (dpName.getType() == DistributionPointName.FULL_NAME)
+                {
+                    GeneralName[] genNames = GeneralNames.getInstance(dpName.getName()).getNames();
+                    for (int j = 0; j < genNames.length; j++)
+                    {
+                        names.add(genNames[j]);
+                    }
+                }
+                if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+                {
+                    ASN1EncodableVector vec = new ASN1EncodableVector();
+                    try
+                    {
+                        Enumeration e = ASN1Sequence.getInstance(PrincipalUtils.getIssuerPrincipal(crl)).getObjects();
+                        while (e.hasMoreElements())
+                        {
+                            vec.add((ASN1Encodable)e.nextElement());
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        throw new AnnotatedException("Could not read CRL issuer.", e);
+                    }
+                    vec.add(dpName.getName());
+                    names.add(new GeneralName(X500Name.getInstance(new DERSequence(vec))));
+                }
+                boolean matches = false;
+                // verify that one of the names in the IDP matches one
+                // of the names in the DP.
+                if (dp.getDistributionPoint() != null)
+                {
+                    dpName = dp.getDistributionPoint();
+                    GeneralName[] genNames = null;
+                    if (dpName.getType() == DistributionPointName.FULL_NAME)
+                    {
+                        genNames = GeneralNames.getInstance(dpName.getName()).getNames();
+                    }
+                    if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+                    {
+                        if (dp.getCRLIssuer() != null)
+                        {
+                            genNames = dp.getCRLIssuer().getNames();
+                        }
+                        else
+                        {
+                            genNames = new GeneralName[1];
+                            try
+                            {
+                                genNames[0] = new GeneralName(X500Name.getInstance(PrincipalUtils
+                                    .getEncodedIssuerPrincipal(cert).getEncoded()));
+                            }
+                            catch (Exception e)
+                            {
+                                throw new AnnotatedException("Could not read certificate issuer.", e);
+                            }
+                        }
+                        for (int j = 0; j < genNames.length; j++)
+                        {
+                            Enumeration e = ASN1Sequence.getInstance(genNames[j].getName().toASN1Primitive()).getObjects();
+                            ASN1EncodableVector vec = new ASN1EncodableVector();
+                            while (e.hasMoreElements())
+                            {
+                                vec.add((ASN1Encodable)e.nextElement());
+                            }
+                            vec.add(dpName.getName());
+                            genNames[j] = new GeneralName(X500Name.getInstance(new DERSequence(vec)));
+                        }
+                    }
+                    if (genNames != null)
+                    {
+                        for (int j = 0; j < genNames.length; j++)
+                        {
+                            if (names.contains(genNames[j]))
+                            {
+                                matches = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (!matches)
+                    {
+                        throw new AnnotatedException(
+                            "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+                    }
+                }
+                // verify that one of the names in
+                // the IDP matches one of the names in the cRLIssuer field of
+                // the DP
+                else
+                {
+                    if (dp.getCRLIssuer() == null)
+                    {
+                        throw new AnnotatedException("Either the cRLIssuer or the distributionPoint field must "
+                            + "be contained in DistributionPoint.");
+                    }
+                    GeneralName[] genNames = dp.getCRLIssuer().getNames();
+                    for (int j = 0; j < genNames.length; j++)
+                    {
+                        if (names.contains(genNames[j]))
+                        {
+                            matches = true;
+                            break;
+                        }
+                    }
+                    if (!matches)
+                    {
+                        throw new AnnotatedException(
+                            "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+                    }
+                }
+            }
+            BasicConstraints bc = null;
+            try
+            {
+                bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue((X509Extension)cert,
+                    BASIC_CONSTRAINTS));
+            }
+            catch (Exception e)
+            {
+                throw new AnnotatedException("Basic constraints extension could not be decoded.", e);
+            }
+
+            if (cert instanceof X509Certificate)
+            {
+                // (b) (2) (ii)
+                if (idp.onlyContainsUserCerts() && (bc != null && bc.isCA()))
+                {
+                    throw new AnnotatedException("CA Cert CRL only contains user certificates.");
+                }
+
+                // (b) (2) (iii)
+                if (idp.onlyContainsCACerts() && (bc == null || !bc.isCA()))
+                {
+                    throw new AnnotatedException("End CRL only contains CA certificates.");
+                }
+            }
+
+            // (b) (2) (iv)
+            if (idp.onlyContainsAttributeCerts())
+            {
+                throw new AnnotatedException("onlyContainsAttributeCerts boolean is asserted.");
+            }
+        }
+    }
+
+    /**
+     * If the DP includes cRLIssuer, then verify that the issuer field in the
+     * complete CRL matches cRLIssuer in the DP and that the complete CRL
+     * contains an issuing distribution point extension with the indirectCRL
+     * boolean asserted. Otherwise, verify that the CRL issuer matches the
+     * certificate issuer.
+     *
+     * @param dp   The distribution point.
+     * @param cert The certificate ot attribute certificate.
+     * @param crl  The CRL for <code>cert</code>.
+     * @throws AnnotatedException if one of the above conditions does not apply or an error
+     *                            occurs.
+     */
+    protected static void processCRLB1(
+        DistributionPoint dp,
+        Object cert,
+        X509CRL crl)
+        throws AnnotatedException
+    {
+        ASN1Primitive idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
+        boolean isIndirect = false;
+        if (idp != null)
+        {
+            if (IssuingDistributionPoint.getInstance(idp).isIndirectCRL())
+            {
+                isIndirect = true;
+            }
+        }
+        byte[] issuerBytes;
+
+        try
+        {
+            issuerBytes = PrincipalUtils.getIssuerPrincipal(crl).getEncoded();
+        }
+        catch (IOException e)
+        {
+            throw new AnnotatedException("Exception encoding CRL issuer: " + e.getMessage(), e);
+        }
+
+        boolean matchIssuer = false;
+        if (dp.getCRLIssuer() != null)
+        {
+            GeneralName genNames[] = dp.getCRLIssuer().getNames();
+            for (int j = 0; j < genNames.length; j++)
+            {
+                if (genNames[j].getTagNo() == GeneralName.directoryName)
+                {
+                    try
+                    {
+                        if (Arrays.areEqual(genNames[j].getName().toASN1Primitive().getEncoded(), issuerBytes))
+                        {
+                            matchIssuer = true;
+                        }
+                    }
+                    catch (IOException e)
+                    {
+                        throw new AnnotatedException(
+                            "CRL issuer information from distribution point cannot be decoded.", e);
+                    }
+                }
+            }
+            if (matchIssuer && !isIndirect)
+            {
+                throw new AnnotatedException("Distribution point contains cRLIssuer field but CRL is not indirect.");
+            }
+            if (!matchIssuer)
+            {
+                throw new AnnotatedException("CRL issuer of CRL does not match CRL issuer of distribution point.");
+            }
+        }
+        else
+        {
+            if (PrincipalUtils.getIssuerPrincipal(crl).equals(
+                PrincipalUtils.getEncodedIssuerPrincipal(cert)))
+            {
+                matchIssuer = true;
+            }
+        }
+        if (!matchIssuer)
+        {
+            throw new AnnotatedException("Cannot find matching CRL issuer for certificate.");
+        }
+    }
+
+    protected static ReasonsMask processCRLD(
+        X509CRL crl,
+        DistributionPoint dp)
+        throws AnnotatedException
+    {
+        IssuingDistributionPoint idp = null;
+        try
+        {
+            idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+                RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+        }
+        catch (Exception e)
+        {
+            throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+        }
+        // (d) (1)
+        if (idp != null && idp.getOnlySomeReasons() != null && dp.getReasons() != null)
+        {
+            return new ReasonsMask(dp.getReasons()).intersect(new ReasonsMask(idp.getOnlySomeReasons()));
+        }
+        // (d) (4)
+        if ((idp == null || idp.getOnlySomeReasons() == null) && dp.getReasons() == null)
+        {
+            return ReasonsMask.allReasons;
+        }
+        // (d) (2) and (d)(3)
+        return (dp.getReasons() == null
+            ? ReasonsMask.allReasons
+            : new ReasonsMask(dp.getReasons())).intersect(idp == null
+            ? ReasonsMask.allReasons
+            : new ReasonsMask(idp.getOnlySomeReasons()));
+
+    }
+
+    public static final String CERTIFICATE_POLICIES = Extension.certificatePolicies.getId();
+
+    public static final String POLICY_MAPPINGS = Extension.policyMappings.getId();
+
+    public static final String INHIBIT_ANY_POLICY = Extension.inhibitAnyPolicy.getId();
+
+    public static final String ISSUING_DISTRIBUTION_POINT = Extension.issuingDistributionPoint.getId();
+
+    public static final String FRESHEST_CRL = Extension.freshestCRL.getId();
+
+    public static final String DELTA_CRL_INDICATOR = Extension.deltaCRLIndicator.getId();
+
+    public static final String POLICY_CONSTRAINTS = Extension.policyConstraints.getId();
+
+    public static final String BASIC_CONSTRAINTS = Extension.basicConstraints.getId();
+
+    public static final String CRL_DISTRIBUTION_POINTS = Extension.cRLDistributionPoints.getId();
+
+    public static final String SUBJECT_ALTERNATIVE_NAME = Extension.subjectAlternativeName.getId();
+
+    public static final String NAME_CONSTRAINTS = Extension.nameConstraints.getId();
+
+    public static final String AUTHORITY_KEY_IDENTIFIER = Extension.authorityKeyIdentifier.getId();
+
+    public static final String KEY_USAGE = Extension.keyUsage.getId();
+
+    public static final String CRL_NUMBER = Extension.cRLNumber.getId();
+
+    public static final String ANY_POLICY = "2.5.29.32.0";
+
+    /*
+     * key usage bits
+     */
+    protected static final int KEY_CERT_SIGN = 5;
+
+    protected static final int CRL_SIGN = 6;
+
+    /**
+     * Obtain and validate the certification path for the complete CRL issuer.
+     * If a key usage extension is present in the CRL issuer's certificate,
+     * verify that the cRLSign bit is set.
+     *
+     * @param crl                CRL which contains revocation information for the certificate
+     *                           <code>cert</code>.
+     * @param cert               The attribute certificate or certificate to check if it is
+     *                           revoked.
+     * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+     * @param defaultCRLSignKey  The public key of the issuer certificate
+     *                           <code>defaultCRLSignCert</code>.
+     * @param paramsPKIX         paramsPKIX PKIX parameters.
+     * @param certPathCerts      The certificates on the certification path.
+     * @return A <code>Set</code> with all keys of possible CRL issuer
+     *         certificates.
+     * @throws AnnotatedException if the CRL is not valid or the status cannot be checked or
+     *                            some error occurs.
+     */
+    protected static Set processCRLF(
+        X509CRL crl,
+        Object cert,
+        X509Certificate defaultCRLSignCert,
+        PublicKey defaultCRLSignKey,
+        PKIXExtendedParameters paramsPKIX,
+        List certPathCerts,
+        JcaJceHelper helper)
+        throws AnnotatedException
+    {
+        // (f)
+
+        // get issuer from CRL
+        X509CertSelector certSelector = new X509CertSelector();
+        try
+        {
+            byte[] issuerPrincipal = PrincipalUtils.getIssuerPrincipal(crl).getEncoded();
+            certSelector.setSubject(issuerPrincipal);
+        }
+        catch (IOException e)
+        {
+            throw new AnnotatedException(
+                "Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e);
+        }
+
+        PKIXCertStoreSelector selector = new PKIXCertStoreSelector.Builder(certSelector).build();
+
+        // get CRL signing certs
+        Collection coll;
+        try
+        {
+            coll = CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getCertificateStores());
+            coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getCertStores()));
+        }
+        catch (AnnotatedException e)
+        {
+            throw new AnnotatedException("Issuer certificate for CRL cannot be searched.", e);
+        }
+
+        coll.add(defaultCRLSignCert);
+
+        Iterator cert_it = coll.iterator();
+
+        List validCerts = new ArrayList();
+        List validKeys = new ArrayList();
+
+        while (cert_it.hasNext())
+        {
+            X509Certificate signingCert = (X509Certificate)cert_it.next();
+
+            /*
+             * CA of the certificate, for which this CRL is checked, has also
+             * signed CRL, so skip the path validation, because is already done
+             */
+            if (signingCert.equals(defaultCRLSignCert))
+            {
+                validCerts.add(signingCert);
+                validKeys.add(defaultCRLSignKey);
+                continue;
+            }
+            try
+            {
+                PKIXCertPathBuilderSpi builder = new PKIXCertPathBuilderSpi();
+                X509CertSelector tmpCertSelector = new X509CertSelector();
+                tmpCertSelector.setCertificate(signingCert);
+
+                PKIXExtendedParameters.Builder paramsBuilder = new PKIXExtendedParameters.Builder(paramsPKIX)
+                    .setTargetConstraints(new PKIXCertStoreSelector.Builder(tmpCertSelector).build());
+
+                /*
+                 * if signingCert is placed not higher on the cert path a
+                 * dependency loop results. CRL for cert is checked, but
+                 * signingCert is needed for checking the CRL which is dependent
+                 * on checking cert because it is higher in the cert path and so
+                 * signing signingCert transitively. so, revocation is disabled,
+                 * forgery attacks of the CRL are detected in this outer loop
+                 * for all other it must be enabled to prevent forgery attacks
+                 */
+                if (certPathCerts.contains(signingCert))
+                {
+                    paramsBuilder.setRevocationEnabled(false);
+                }
+                else
+                {
+                    paramsBuilder.setRevocationEnabled(true);
+                }
+
+                PKIXExtendedBuilderParameters extParams = new PKIXExtendedBuilderParameters.Builder(paramsBuilder.build()).build();
+
+                List certs = builder.engineBuild(extParams).getCertPath().getCertificates();
+                validCerts.add(signingCert);
+                validKeys.add(CertPathValidatorUtilities.getNextWorkingKey(certs, 0, helper));
+            }
+            catch (CertPathBuilderException e)
+            {
+                throw new AnnotatedException("CertPath for CRL signer failed to validate.", e);
+            }
+            catch (CertPathValidatorException e)
+            {
+                throw new AnnotatedException("Public key of issuer certificate of CRL could not be retrieved.", e);
+            }
+            catch (Exception e)
+            {
+                throw new AnnotatedException(e.getMessage());
+            }
+        }
+
+        Set checkKeys = new HashSet();
+
+        AnnotatedException lastException = null;
+        for (int i = 0; i < validCerts.size(); i++)
+        {
+            X509Certificate signCert = (X509Certificate)validCerts.get(i);
+            boolean[] keyusage = signCert.getKeyUsage();
+
+            if (keyusage != null && (keyusage.length < 7 || !keyusage[CRL_SIGN]))
+            {
+                lastException = new AnnotatedException(
+                    "Issuer certificate key usage extension does not permit CRL signing.");
+            }
+            else
+            {
+                checkKeys.add(validKeys.get(i));
+            }
+        }
+
+        if (checkKeys.isEmpty() && lastException == null)
+        {
+            throw new AnnotatedException("Cannot find a valid issuer certificate.");
+        }
+        if (checkKeys.isEmpty() && lastException != null)
+        {
+            throw lastException;
+        }
+
+        return checkKeys;
+    }
+
+    protected static PublicKey processCRLG(
+        X509CRL crl,
+        Set keys)
+        throws AnnotatedException
+    {
+        Exception lastException = null;
+        for (Iterator it = keys.iterator(); it.hasNext();)
+        {
+            PublicKey key = (PublicKey)it.next();
+            try
+            {
+                crl.verify(key);
+                return key;
+            }
+            catch (Exception e)
+            {
+                lastException = e;
+            }
+        }
+        throw new AnnotatedException("Cannot verify CRL.", lastException);
+    }
+
+    protected static X509CRL processCRLH(
+        Set deltacrls,
+        PublicKey key)
+        throws AnnotatedException
+    {
+        Exception lastException = null;
+
+        for (Iterator it = deltacrls.iterator(); it.hasNext();)
+        {
+            X509CRL crl = (X509CRL)it.next();
+            try
+            {
+                crl.verify(key);
+                return crl;
+            }
+            catch (Exception e)
+            {
+                lastException = e;
+            }
+        }
+
+        if (lastException != null)
+        {
+            throw new AnnotatedException("Cannot verify delta CRL.", lastException);
+        }
+        return null;
+    }
+
+    protected static Set processCRLA1i(
+        Date currentDate,
+        PKIXExtendedParameters paramsPKIX,
+        X509Certificate cert,
+        X509CRL crl)
+        throws AnnotatedException
+    {
+        Set set = new HashSet();
+        if (paramsPKIX.isUseDeltasEnabled())
+        {
+            CRLDistPoint freshestCRL = null;
+            try
+            {
+                freshestCRL = CRLDistPoint
+                    .getInstance(CertPathValidatorUtilities.getExtensionValue(cert, FRESHEST_CRL));
+            }
+            catch (AnnotatedException e)
+            {
+                throw new AnnotatedException("Freshest CRL extension could not be decoded from certificate.", e);
+            }
+            if (freshestCRL == null)
+            {
+                try
+                {
+                    freshestCRL = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+                        FRESHEST_CRL));
+                }
+                catch (AnnotatedException e)
+                {
+                    throw new AnnotatedException("Freshest CRL extension could not be decoded from CRL.", e);
+                }
+            }
+            if (freshestCRL != null)
+            {
+                List crlStores = new ArrayList();
+
+                crlStores.addAll(paramsPKIX.getCRLStores());
+
+                try
+                {
+                    crlStores.addAll(CertPathValidatorUtilities.getAdditionalStoresFromCRLDistributionPoint(freshestCRL, paramsPKIX.getNamedCRLStoreMap()));
+                }
+                catch (AnnotatedException e)
+                {
+                    throw new AnnotatedException(
+                        "No new delta CRL locations could be added from Freshest CRL extension.", e);
+                }
+
+                // get delta CRL(s)
+                try
+                {
+                    set.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, crl, paramsPKIX.getCertStores(), crlStores));
+                }
+                catch (AnnotatedException e)
+                {
+                    throw new AnnotatedException("Exception obtaining delta CRLs.", e);
+                }
+            }
+        }
+        return set;
+    }
+
+    protected static Set[] processCRLA1ii(
+        Date currentDate,
+        PKIXExtendedParameters paramsPKIX,
+        X509Certificate cert,
+        X509CRL crl)
+        throws AnnotatedException
+    {
+        Set deltaSet = new HashSet();
+        X509CRLSelector crlselect = new X509CRLSelector();
+        crlselect.setCertificateChecking(cert);
+
+        try
+        {
+            crlselect.addIssuerName(PrincipalUtils.getIssuerPrincipal(crl).getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new AnnotatedException("Cannot extract issuer from CRL." + e, e);
+        }
+
+        PKIXCRLStoreSelector extSelect = new PKIXCRLStoreSelector.Builder(crlselect).setCompleteCRLEnabled(true).build();
+
+        Date validityDate = currentDate;
+
+        if (paramsPKIX.getDate() != null)
+        {
+            validityDate = paramsPKIX.getDate();
+        }
+
+        Set completeSet = CRL_UTIL.findCRLs(extSelect, validityDate, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores());
+
+        if (paramsPKIX.isUseDeltasEnabled())
+        {
+            // get delta CRL(s)
+            try
+            {
+                deltaSet.addAll(CertPathValidatorUtilities.getDeltaCRLs(validityDate, crl, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores()));
+            }
+            catch (AnnotatedException e)
+            {
+                throw new AnnotatedException("Exception obtaining delta CRLs.", e);
+            }
+        }
+        return new Set[]
+            {
+                completeSet,
+                deltaSet};
+    }
+
+
+
+    /**
+     * If use-deltas is set, verify the issuer and scope of the delta CRL.
+     *
+     * @param deltaCRL    The delta CRL.
+     * @param completeCRL The complete CRL.
+     * @param pkixParams  The PKIX paramaters.
+     * @throws AnnotatedException if an exception occurs.
+     */
+    protected static void processCRLC(
+        X509CRL deltaCRL,
+        X509CRL completeCRL,
+        PKIXExtendedParameters pkixParams)
+        throws AnnotatedException
+    {
+        if (deltaCRL == null)
+        {
+            return;
+        }
+        IssuingDistributionPoint completeidp = null;
+        try
+        {
+            completeidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(
+                completeCRL, RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+        }
+        catch (Exception e)
+        {
+            throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+        }
+
+        if (pkixParams.isUseDeltasEnabled())
+        {
+            // (c) (1)
+            if (!PrincipalUtils.getIssuerPrincipal(deltaCRL).equals(PrincipalUtils.getIssuerPrincipal(completeCRL)))
+            {
+                throw new AnnotatedException("Complete CRL issuer does not match delta CRL issuer.");
+            }
+
+            // (c) (2)
+            IssuingDistributionPoint deltaidp = null;
+            try
+            {
+                deltaidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(
+                    deltaCRL, ISSUING_DISTRIBUTION_POINT));
+            }
+            catch (Exception e)
+            {
+                throw new AnnotatedException(
+                    "Issuing distribution point extension from delta CRL could not be decoded.", e);
+            }
+
+            boolean match = false;
+            if (completeidp == null)
+            {
+                if (deltaidp == null)
+                {
+                    match = true;
+                }
+            }
+            else
+            {
+                if (completeidp.equals(deltaidp))
+                {
+                    match = true;
+                }
+            }
+            if (!match)
+            {
+                throw new AnnotatedException(
+                    "Issuing distribution point extension from delta CRL and complete CRL does not match.");
+            }
+
+            // (c) (3)
+            ASN1Primitive completeKeyIdentifier = null;
+            try
+            {
+                completeKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
+                    completeCRL, AUTHORITY_KEY_IDENTIFIER);
+            }
+            catch (AnnotatedException e)
+            {
+                throw new AnnotatedException(
+                    "Authority key identifier extension could not be extracted from complete CRL.", e);
+            }
+
+            ASN1Primitive deltaKeyIdentifier = null;
+            try
+            {
+                deltaKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
+                    deltaCRL, AUTHORITY_KEY_IDENTIFIER);
+            }
+            catch (AnnotatedException e)
+            {
+                throw new AnnotatedException(
+                    "Authority key identifier extension could not be extracted from delta CRL.", e);
+            }
+
+            if (completeKeyIdentifier == null)
+            {
+                throw new AnnotatedException("CRL authority key identifier is null.");
+            }
+
+            if (deltaKeyIdentifier == null)
+            {
+                throw new AnnotatedException("Delta CRL authority key identifier is null.");
+            }
+
+            if (!completeKeyIdentifier.equals(deltaKeyIdentifier))
+            {
+                throw new AnnotatedException(
+                    "Delta CRL authority key identifier does not match complete CRL authority key identifier.");
+            }
+        }
+    }
+
+    protected static void processCRLI(
+        Date validDate,
+        X509CRL deltacrl,
+        Object cert,
+        CertStatus certStatus,
+        PKIXExtendedParameters pkixParams)
+        throws AnnotatedException
+    {
+        if (pkixParams.isUseDeltasEnabled() && deltacrl != null)
+        {
+            CertPathValidatorUtilities.getCertStatus(validDate, deltacrl, cert, certStatus);
+        }
+    }
+
+    protected static void processCRLJ(
+        Date validDate,
+        X509CRL completecrl,
+        Object cert,
+        CertStatus certStatus)
+        throws AnnotatedException
+    {
+        if (certStatus.getCertStatus() == CertStatus.UNREVOKED)
+        {
+            CertPathValidatorUtilities.getCertStatus(validDate, completecrl, cert, certStatus);
+        }
+    }
+
+    protected static PKIXPolicyNode prepareCertB(
+        CertPath certPath,
+        int index,
+        List[] policyNodes,
+        PKIXPolicyNode validPolicyTree,
+        int policyMapping)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        int n = certs.size();
+        // i as defined in the algorithm description
+        int i = n - index;
+        // (b)
+        //
+        ASN1Sequence pm = null;
+        try
+        {
+            pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.POLICY_MAPPINGS));
+        }
+        catch (AnnotatedException ex)
+        {
+            throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath,
+                index);
+        }
+        PKIXPolicyNode _validPolicyTree = validPolicyTree;
+        if (pm != null)
+        {
+            ASN1Sequence mappings = (ASN1Sequence)pm;
+            Map m_idp = new HashMap();
+            Set s_idp = new HashSet();
+
+            for (int j = 0; j < mappings.size(); j++)
+            {
+                ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
+                String id_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(0)).getId();
+                String sd_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(1)).getId();
+                Set tmp;
+
+                if (!m_idp.containsKey(id_p))
+                {
+                    tmp = new HashSet();
+                    tmp.add(sd_p);
+                    m_idp.put(id_p, tmp);
+                    s_idp.add(id_p);
+                }
+                else
+                {
+                    tmp = (Set)m_idp.get(id_p);
+                    tmp.add(sd_p);
+                }
+            }
+
+            Iterator it_idp = s_idp.iterator();
+            while (it_idp.hasNext())
+            {
+                String id_p = (String)it_idp.next();
+
+                //
+                // (1)
+                //
+                if (policyMapping > 0)
+                {
+                    boolean idp_found = false;
+                    Iterator nodes_i = policyNodes[i].iterator();
+                    while (nodes_i.hasNext())
+                    {
+                        PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+                        if (node.getValidPolicy().equals(id_p))
+                        {
+                            idp_found = true;
+                            node.expectedPolicies = (Set)m_idp.get(id_p);
+                            break;
+                        }
+                    }
+
+                    if (!idp_found)
+                    {
+                        nodes_i = policyNodes[i].iterator();
+                        while (nodes_i.hasNext())
+                        {
+                            PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+                            if (RFC3280CertPathUtilities.ANY_POLICY.equals(node.getValidPolicy()))
+                            {
+                                Set pq = null;
+                                ASN1Sequence policies = null;
+                                try
+                                {
+                                    policies = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert,
+                                        RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+                                }
+                                catch (AnnotatedException e)
+                                {
+                                    throw new ExtCertPathValidatorException(
+                                        "Certificate policies extension could not be decoded.", e, certPath, index);
+                                }
+                                Enumeration e = policies.getObjects();
+                                while (e.hasMoreElements())
+                                {
+                                    PolicyInformation pinfo = null;
+                                    try
+                                    {
+                                        pinfo = PolicyInformation.getInstance(e.nextElement());
+                                    }
+                                    catch (Exception ex)
+                                    {
+                                        throw new CertPathValidatorException(
+                                            "Policy information could not be decoded.", ex, certPath, index);
+                                    }
+                                    if (RFC3280CertPathUtilities.ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+                                    {
+                                        try
+                                        {
+                                            pq = CertPathValidatorUtilities
+                                                .getQualifierSet(pinfo.getPolicyQualifiers());
+                                        }
+                                        catch (CertPathValidatorException ex)
+                                        {
+
+                                            throw new ExtCertPathValidatorException(
+                                                "Policy qualifier info set could not be decoded.", ex, certPath,
+                                                index);
+                                        }
+                                        break;
+                                    }
+                                }
+                                boolean ci = false;
+                                if (cert.getCriticalExtensionOIDs() != null)
+                                {
+                                    ci = cert.getCriticalExtensionOIDs().contains(
+                                        RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+                                }
+
+                                PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+                                if (RFC3280CertPathUtilities.ANY_POLICY.equals(p_node.getValidPolicy()))
+                                {
+                                    PKIXPolicyNode c_node = new PKIXPolicyNode(new ArrayList(), i, (Set)m_idp
+                                        .get(id_p), p_node, pq, id_p, ci);
+                                    p_node.addChild(c_node);
+                                    policyNodes[i].add(c_node);
+                                }
+                                break;
+                            }
+                        }
+                    }
+
+                    //
+                    // (2)
+                    //
+                }
+                else if (policyMapping <= 0)
+                {
+                    Iterator nodes_i = policyNodes[i].iterator();
+                    while (nodes_i.hasNext())
+                    {
+                        PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+                        if (node.getValidPolicy().equals(id_p))
+                        {
+                            PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+                            p_node.removeChild(node);
+                            nodes_i.remove();
+                            for (int k = (i - 1); k >= 0; k--)
+                            {
+                                List nodes = policyNodes[k];
+                                for (int l = 0; l < nodes.size(); l++)
+                                {
+                                    PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+                                    if (!node2.hasChildren())
+                                    {
+                                        _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(
+                                            _validPolicyTree, policyNodes, node2);
+                                        if (_validPolicyTree == null)
+                                        {
+                                            break;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return _validPolicyTree;
+    }
+
+    protected static void prepareNextCertA(
+        CertPath certPath,
+        int index)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        //
+        // (a) check the policy mappings
+        //
+        ASN1Sequence pm = null;
+        try
+        {
+            pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.POLICY_MAPPINGS));
+        }
+        catch (AnnotatedException ex)
+        {
+            throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath,
+                index);
+        }
+        if (pm != null)
+        {
+            ASN1Sequence mappings = pm;
+
+            for (int j = 0; j < mappings.size(); j++)
+            {
+                ASN1ObjectIdentifier issuerDomainPolicy = null;
+                ASN1ObjectIdentifier subjectDomainPolicy = null;
+                try
+                {
+                    ASN1Sequence mapping = DERSequence.getInstance(mappings.getObjectAt(j));
+
+                    issuerDomainPolicy = ASN1ObjectIdentifier.getInstance(mapping.getObjectAt(0));
+                    subjectDomainPolicy = ASN1ObjectIdentifier.getInstance(mapping.getObjectAt(1));
+                }
+                catch (Exception e)
+                {
+                    throw new ExtCertPathValidatorException("Policy mappings extension contents could not be decoded.",
+                        e, certPath, index);
+                }
+
+                if (RFC3280CertPathUtilities.ANY_POLICY.equals(issuerDomainPolicy.getId()))
+                {
+
+                    throw new CertPathValidatorException("IssuerDomainPolicy is anyPolicy", null, certPath, index);
+                }
+
+                if (RFC3280CertPathUtilities.ANY_POLICY.equals(subjectDomainPolicy.getId()))
+                {
+
+                    throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy,", null, certPath, index);
+                }
+            }
+        }
+    }
+
+    protected static void processCertF(
+        CertPath certPath,
+        int index,
+        PKIXPolicyNode validPolicyTree,
+        int explicitPolicy)
+        throws CertPathValidatorException
+    {
+        //
+        // (f)
+        //
+        if (explicitPolicy <= 0 && validPolicyTree == null)
+        {
+            throw new ExtCertPathValidatorException("No valid policy tree found when one expected.", null, certPath,
+                index);
+        }
+    }
+
+    protected static PKIXPolicyNode processCertE(
+        CertPath certPath,
+        int index,
+        PKIXPolicyNode validPolicyTree)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        // 
+        // (e)
+        //
+        ASN1Sequence certPolicies = null;
+        try
+        {
+            certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.CERTIFICATE_POLICIES));
+        }
+        catch (AnnotatedException e)
+        {
+            throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.",
+                e, certPath, index);
+        }
+        if (certPolicies == null)
+        {
+            validPolicyTree = null;
+        }
+        return validPolicyTree;
+    }
+
+    protected static void processCertBC(
+        CertPath certPath,
+        int index,
+        PKIXNameConstraintValidator nameConstraintValidator)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        int n = certs.size();
+        // i as defined in the algorithm description
+        int i = n - index;
+        //
+        // (b), (c) permitted and excluded subtree checking.
+        //
+        if (!(CertPathValidatorUtilities.isSelfIssued(cert) && (i < n)))
+        {
+            X500Name principal = PrincipalUtils.getSubjectPrincipal(cert);
+            ASN1Sequence dns;
+
+            try
+            {
+                dns = DERSequence.getInstance(principal.getEncoded());
+            }
+            catch (Exception e)
+            {
+                throw new CertPathValidatorException("Exception extracting subject name when checking subtrees.", e,
+                    certPath, index);
+            }
+
+            try
+            {
+                nameConstraintValidator.checkPermittedDN(dns);
+                nameConstraintValidator.checkExcludedDN(dns);
+            }
+            catch (PKIXNameConstraintValidatorException e)
+            {
+                throw new CertPathValidatorException("Subtree check for certificate subject failed.", e, certPath,
+                    index);
+            }
+
+            GeneralNames altName = null;
+            try
+            {
+                altName = GeneralNames.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                    RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME));
+            }
+            catch (Exception e)
+            {
+                throw new CertPathValidatorException("Subject alternative name extension could not be decoded.", e,
+                    certPath, index);
+            }
+            RDN[] emails = X500Name.getInstance(dns).getRDNs(BCStyle.EmailAddress);
+            for (int eI = 0; eI != emails.length; eI++)
+            {
+                // TODO: this should take into account multi-valued RDNs
+                String email = ((ASN1String)emails[eI].getFirst().getValue()).getString();
+                GeneralName emailAsGeneralName = new GeneralName(GeneralName.rfc822Name, email);
+                try
+                {
+                    nameConstraintValidator.checkPermitted(emailAsGeneralName);
+                    nameConstraintValidator.checkExcluded(emailAsGeneralName);
+                }
+                catch (PKIXNameConstraintValidatorException ex)
+                {
+                    throw new CertPathValidatorException(
+                        "Subtree check for certificate subject alternative email failed.", ex, certPath, index);
+                }
+            }
+            if (altName != null)
+            {
+                GeneralName[] genNames = null;
+                try
+                {
+                    genNames = altName.getNames();
+                }
+                catch (Exception e)
+                {
+                    throw new CertPathValidatorException("Subject alternative name contents could not be decoded.", e,
+                        certPath, index);
+                }
+                for (int j = 0; j < genNames.length; j++)
+                {
+
+                    try
+                    {
+                        nameConstraintValidator.checkPermitted(genNames[j]);
+                        nameConstraintValidator.checkExcluded(genNames[j]);
+                    }
+                    catch (PKIXNameConstraintValidatorException e)
+                    {
+                        throw new CertPathValidatorException(
+                            "Subtree check for certificate subject alternative name failed.", e, certPath, index);
+                    }
+                }
+            }
+        }
+    }
+
+    protected static PKIXPolicyNode processCertD(
+        CertPath certPath,
+        int index,
+        Set acceptablePolicies,
+        PKIXPolicyNode validPolicyTree,
+        List[] policyNodes,
+        int inhibitAnyPolicy)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        int n = certs.size();
+        // i as defined in the algorithm description
+        int i = n - index;
+        //
+        // (d) policy Information checking against initial policy and
+        // policy mapping
+        //
+        ASN1Sequence certPolicies = null;
+        try
+        {
+            certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.CERTIFICATE_POLICIES));
+        }
+        catch (AnnotatedException e)
+        {
+            throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.",
+                e, certPath, index);
+        }
+        if (certPolicies != null && validPolicyTree != null)
+        {
+            //
+            // (d) (1)
+            //
+            Enumeration e = certPolicies.getObjects();
+            Set pols = new HashSet();
+
+            while (e.hasMoreElements())
+            {
+                PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+                ASN1ObjectIdentifier pOid = pInfo.getPolicyIdentifier();
+
+                pols.add(pOid.getId());
+
+                if (!RFC3280CertPathUtilities.ANY_POLICY.equals(pOid.getId()))
+                {
+                    Set pq = null;
+                    try
+                    {
+                        pq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+                    }
+                    catch (CertPathValidatorException ex)
+                    {
+                        throw new ExtCertPathValidatorException("Policy qualifier info set could not be build.", ex,
+                            certPath, index);
+                    }
+
+                    boolean match = CertPathValidatorUtilities.processCertD1i(i, policyNodes, pOid, pq);
+
+                    if (!match)
+                    {
+                        CertPathValidatorUtilities.processCertD1ii(i, policyNodes, pOid, pq);
+                    }
+                }
+            }
+
+            if (acceptablePolicies.isEmpty() || acceptablePolicies.contains(RFC3280CertPathUtilities.ANY_POLICY))
+            {
+                acceptablePolicies.clear();
+                acceptablePolicies.addAll(pols);
+            }
+            else
+            {
+                Iterator it = acceptablePolicies.iterator();
+                Set t1 = new HashSet();
+
+                while (it.hasNext())
+                {
+                    Object o = it.next();
+
+                    if (pols.contains(o))
+                    {
+                        t1.add(o);
+                    }
+                }
+                acceptablePolicies.clear();
+                acceptablePolicies.addAll(t1);
+            }
+
+            //
+            // (d) (2)
+            //
+            if ((inhibitAnyPolicy > 0) || ((i < n) && CertPathValidatorUtilities.isSelfIssued(cert)))
+            {
+                e = certPolicies.getObjects();
+
+                while (e.hasMoreElements())
+                {
+                    PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+
+                    if (RFC3280CertPathUtilities.ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId()))
+                    {
+                        Set _apq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+                        List _nodes = policyNodes[i - 1];
+
+                        for (int k = 0; k < _nodes.size(); k++)
+                        {
+                            PKIXPolicyNode _node = (PKIXPolicyNode)_nodes.get(k);
+
+                            Iterator _policySetIter = _node.getExpectedPolicies().iterator();
+                            while (_policySetIter.hasNext())
+                            {
+                                Object _tmp = _policySetIter.next();
+
+                                String _policy;
+                                if (_tmp instanceof String)
+                                {
+                                    _policy = (String)_tmp;
+                                }
+                                else if (_tmp instanceof ASN1ObjectIdentifier)
+                                {
+                                    _policy = ((ASN1ObjectIdentifier)_tmp).getId();
+                                }
+                                else
+                                {
+                                    continue;
+                                }
+
+                                boolean _found = false;
+                                Iterator _childrenIter = _node.getChildren();
+
+                                while (_childrenIter.hasNext())
+                                {
+                                    PKIXPolicyNode _child = (PKIXPolicyNode)_childrenIter.next();
+
+                                    if (_policy.equals(_child.getValidPolicy()))
+                                    {
+                                        _found = true;
+                                    }
+                                }
+
+                                if (!_found)
+                                {
+                                    Set _newChildExpectedPolicies = new HashSet();
+                                    _newChildExpectedPolicies.add(_policy);
+
+                                    PKIXPolicyNode _newChild = new PKIXPolicyNode(new ArrayList(), i,
+                                        _newChildExpectedPolicies, _node, _apq, _policy, false);
+                                    _node.addChild(_newChild);
+                                    policyNodes[i].add(_newChild);
+                                }
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+
+            PKIXPolicyNode _validPolicyTree = validPolicyTree;
+            //
+            // (d) (3)
+            //
+            for (int j = (i - 1); j >= 0; j--)
+            {
+                List nodes = policyNodes[j];
+
+                for (int k = 0; k < nodes.size(); k++)
+                {
+                    PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+                    if (!node.hasChildren())
+                    {
+                        _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(_validPolicyTree, policyNodes,
+                            node);
+                        if (_validPolicyTree == null)
+                        {
+                            break;
+                        }
+                    }
+                }
+            }
+
+            //
+            // d (4)
+            //
+            Set criticalExtensionOids = cert.getCriticalExtensionOIDs();
+
+            if (criticalExtensionOids != null)
+            {
+                boolean critical = criticalExtensionOids.contains(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+
+                List nodes = policyNodes[i];
+                for (int j = 0; j < nodes.size(); j++)
+                {
+                    PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(j);
+                    node.setCritical(critical);
+                }
+            }
+            return _validPolicyTree;
+        }
+        return null;
+    }
+
+    protected static void processCertA(
+        CertPath certPath,
+        PKIXExtendedParameters paramsPKIX,
+        int index,
+        PublicKey workingPublicKey,
+        boolean verificationAlreadyPerformed,
+        X500Name workingIssuerName,
+        X509Certificate sign,
+        JcaJceHelper helper)
+        throws ExtCertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (a) verify
+        //
+        if (!verificationAlreadyPerformed)
+        {
+            try
+            {
+                // (a) (1)
+                //
+                CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey,
+                    paramsPKIX.getSigProvider());
+            }
+            catch (GeneralSecurityException e)
+            {
+                throw new ExtCertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
+            }
+        }
+
+        try
+        {
+            // (a) (2)
+            //
+            cert.checkValidity(CertPathValidatorUtilities
+                .getValidCertDateFromValidityModel(paramsPKIX, certPath, index));
+        }
+        catch (CertificateExpiredException e)
+        {
+            throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+        }
+        catch (CertificateNotYetValidException e)
+        {
+            throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+        }
+        catch (AnnotatedException e)
+        {
+            throw new ExtCertPathValidatorException("Could not validate time of certificate.", e, certPath, index);
+        }
+
+        //
+        // (a) (3)
+        //
+        if (paramsPKIX.isRevocationEnabled())
+        {
+            try
+            {
+                checkCRLs(paramsPKIX, cert, CertPathValidatorUtilities.getValidCertDateFromValidityModel(paramsPKIX,
+                    certPath, index), sign, workingPublicKey, certs, helper);
+            }
+            catch (AnnotatedException e)
+            {
+                Throwable cause = e;
+                if (null != e.getCause())
+                {
+                    cause = e.getCause();
+                }
+                throw new ExtCertPathValidatorException(e.getMessage(), cause, certPath, index);
+            }
+        }
+
+        //
+        // (a) (4) name chaining
+        //
+        if (!PrincipalUtils.getEncodedIssuerPrincipal(cert).equals(workingIssuerName))
+        {
+            throw new ExtCertPathValidatorException("IssuerName(" + PrincipalUtils.getEncodedIssuerPrincipal(cert)
+                + ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null,
+                certPath, index);
+        }
+    }
+
+    protected static int prepareNextCertI1(
+        CertPath certPath,
+        int index,
+        int explicitPolicy)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (i)
+        //
+        ASN1Sequence pc = null;
+        try
+        {
+            pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+        }
+        catch (Exception e)
+        {
+            throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath,
+                index);
+        }
+
+        int tmpInt;
+
+        if (pc != null)
+        {
+            Enumeration policyConstraints = pc.getObjects();
+
+            while (policyConstraints.hasMoreElements())
+            {
+                try
+                {
+
+                    ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
+                    if (constraint.getTagNo() == 0)
+                    {
+                        tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue();
+                        if (tmpInt < explicitPolicy)
+                        {
+                            return tmpInt;
+                        }
+                        break;
+                    }
+                }
+                catch (IllegalArgumentException e)
+                {
+                    throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.",
+                        e, certPath, index);
+                }
+            }
+        }
+        return explicitPolicy;
+    }
+
+    protected static int prepareNextCertI2(
+        CertPath certPath,
+        int index,
+        int policyMapping)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (i)
+        //
+        ASN1Sequence pc = null;
+        try
+        {
+            pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+        }
+        catch (Exception e)
+        {
+            throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath,
+                index);
+        }
+
+        int tmpInt;
+
+        if (pc != null)
+        {
+            Enumeration policyConstraints = pc.getObjects();
+
+            while (policyConstraints.hasMoreElements())
+            {
+                try
+                {
+                    ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
+                    if (constraint.getTagNo() == 1)
+                    {
+                        tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue();
+                        if (tmpInt < policyMapping)
+                        {
+                            return tmpInt;
+                        }
+                        break;
+                    }
+                }
+                catch (IllegalArgumentException e)
+                {
+                    throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.",
+                        e, certPath, index);
+                }
+            }
+        }
+        return policyMapping;
+    }
+
+    protected static void prepareNextCertG(
+        CertPath certPath,
+        int index,
+        PKIXNameConstraintValidator nameConstraintValidator)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (g) handle the name constraints extension
+        //
+        NameConstraints nc = null;
+        try
+        {
+            ASN1Sequence ncSeq = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.NAME_CONSTRAINTS));
+            if (ncSeq != null)
+            {
+                nc = NameConstraints.getInstance(ncSeq);
+            }
+        }
+        catch (Exception e)
+        {
+            throw new ExtCertPathValidatorException("Name constraints extension could not be decoded.", e, certPath,
+                index);
+        }
+        if (nc != null)
+        {
+
+            //
+            // (g) (1) permitted subtrees
+            //
+            GeneralSubtree[] permitted = nc.getPermittedSubtrees();
+            if (permitted != null)
+            {
+                try
+                {
+                    nameConstraintValidator.intersectPermittedSubtree(permitted);
+                }
+                catch (Exception ex)
+                {
+                    throw new ExtCertPathValidatorException(
+                        "Permitted subtrees cannot be build from name constraints extension.", ex, certPath, index);
+                }
+            }
+
+            //
+            // (g) (2) excluded subtrees
+            //
+            GeneralSubtree[] excluded = nc.getExcludedSubtrees();
+            if (excluded != null)
+            {
+                for (int i = 0; i != excluded.length; i++)
+                try
+                {
+                        nameConstraintValidator.addExcludedSubtree(excluded[i]);
+                }
+                catch (Exception ex)
+                {
+                    throw new ExtCertPathValidatorException(
+                        "Excluded subtrees cannot be build from name constraints extension.", ex, certPath, index);
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks a distribution point for revocation information for the
+     * certificate <code>cert</code>.
+     *
+     * @param dp                 The distribution point to consider.
+     * @param paramsPKIX         PKIX parameters.
+     * @param cert               Certificate to check if it is revoked.
+     * @param validDate          The date when the certificate revocation status should be
+     *                           checked.
+     * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+     * @param defaultCRLSignKey  The public key of the issuer certificate
+     *                           <code>defaultCRLSignCert</code>.
+     * @param certStatus         The current certificate revocation status.
+     * @param reasonMask         The reasons mask which is already checked.
+     * @param certPathCerts      The certificates of the certification path.
+     * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+     *                            or some error occurs.
+     */
+    private static void checkCRL(
+        DistributionPoint dp,
+        PKIXExtendedParameters paramsPKIX,
+        X509Certificate cert,
+        Date validDate,
+        X509Certificate defaultCRLSignCert,
+        PublicKey defaultCRLSignKey,
+        CertStatus certStatus,
+        ReasonsMask reasonMask,
+        List certPathCerts,
+        JcaJceHelper helper)
+        throws AnnotatedException
+    {
+        Date currentDate = new Date(System.currentTimeMillis());
+        if (validDate.getTime() > currentDate.getTime())
+        {
+            throw new AnnotatedException("Validation time is in future.");
+        }
+
+        // (a)
+        /*
+         * We always get timely valid CRLs, so there is no step (a) (1).
+         * "locally cached" CRLs are assumed to be in getStore(), additional
+         * CRLs must be enabled in the ExtendedPKIXParameters and are in
+         * getAdditionalStore()
+         */
+
+        Set crls = CertPathValidatorUtilities.getCompleteCRLs(dp, cert, currentDate, paramsPKIX);
+        boolean validCrlFound = false;
+        AnnotatedException lastException = null;
+        Iterator crl_iter = crls.iterator();
+
+        while (crl_iter.hasNext() && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonMask.isAllReasons())
+        {
+            try
+            {
+                X509CRL crl = (X509CRL)crl_iter.next();
+
+                // (d)
+                ReasonsMask interimReasonsMask = RFC3280CertPathUtilities.processCRLD(crl, dp);
+
+                // (e)
+                /*
+                 * The reasons mask is updated at the end, so only valid CRLs
+                 * can update it. If this CRL does not contain new reasons it
+                 * must be ignored.
+                 */
+                if (!interimReasonsMask.hasNewReasons(reasonMask))
+                {
+                    continue;
+                }
+
+                // (f)
+                Set keys = RFC3280CertPathUtilities.processCRLF(crl, cert, defaultCRLSignCert, defaultCRLSignKey,
+                    paramsPKIX, certPathCerts, helper);
+                // (g)
+                PublicKey key = RFC3280CertPathUtilities.processCRLG(crl, keys);
+
+                X509CRL deltaCRL = null;
+
+                Date validityDate = currentDate;
+
+                if (paramsPKIX.getDate() != null)
+                {
+                    validityDate = paramsPKIX.getDate();
+                }
+
+                if (paramsPKIX.isUseDeltasEnabled())
+                {
+                    // get delta CRLs
+                    Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs(validityDate, crl, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores());
+                    // we only want one valid delta CRL
+                    // (h)
+                    deltaCRL = RFC3280CertPathUtilities.processCRLH(deltaCRLs, key);
+                }
+
+                /*
+                 * CRL must be be valid at the current time, not the validation
+                 * time. If a certificate is revoked with reason keyCompromise,
+                 * cACompromise, it can be used for forgery, also for the past.
+                 * This reason may not be contained in older CRLs.
+                 */
+
+                /*
+                 * in the chain model signatures stay valid also after the
+                 * certificate has been expired, so they do not have to be in
+                 * the CRL validity time
+                 */
+
+                if (paramsPKIX.getValidityModel() != PKIXExtendedParameters.CHAIN_VALIDITY_MODEL)
+                {
+                    /*
+                     * if a certificate has expired, but was revoked, it is not
+                     * more in the CRL, so it would be regarded as valid if the
+                     * first check is not done
+                     */
+                    if (cert.getNotAfter().getTime() < crl.getThisUpdate().getTime())
+                    {
+                        throw new AnnotatedException("No valid CRL for current time found.");
+                    }
+                }
+
+                RFC3280CertPathUtilities.processCRLB1(dp, cert, crl);
+
+                // (b) (2)
+                RFC3280CertPathUtilities.processCRLB2(dp, cert, crl);
+
+                // (c)
+                RFC3280CertPathUtilities.processCRLC(deltaCRL, crl, paramsPKIX);
+
+                // (i)
+                RFC3280CertPathUtilities.processCRLI(validDate, deltaCRL, cert, certStatus, paramsPKIX);
+
+                // (j)
+                RFC3280CertPathUtilities.processCRLJ(validDate, crl, cert, certStatus);
+
+                // (k)
+                if (certStatus.getCertStatus() == CRLReason.removeFromCRL)
+                {
+                    certStatus.setCertStatus(CertStatus.UNREVOKED);
+                }
+
+                // update reasons mask
+                reasonMask.addReasons(interimReasonsMask);
+
+                Set criticalExtensions = crl.getCriticalExtensionOIDs();
+                if (criticalExtensions != null)
+                {
+                    criticalExtensions = new HashSet(criticalExtensions);
+                    criticalExtensions.remove(Extension.issuingDistributionPoint.getId());
+                    criticalExtensions.remove(Extension.deltaCRLIndicator.getId());
+
+                    if (!criticalExtensions.isEmpty())
+                    {
+                        throw new AnnotatedException("CRL contains unsupported critical extensions.");
+                    }
+                }
+
+                if (deltaCRL != null)
+                {
+                    criticalExtensions = deltaCRL.getCriticalExtensionOIDs();
+                    if (criticalExtensions != null)
+                    {
+                        criticalExtensions = new HashSet(criticalExtensions);
+                        criticalExtensions.remove(Extension.issuingDistributionPoint.getId());
+                        criticalExtensions.remove(Extension.deltaCRLIndicator.getId());
+                        if (!criticalExtensions.isEmpty())
+                        {
+                            throw new AnnotatedException("Delta CRL contains unsupported critical extension.");
+                        }
+                    }
+                }
+
+                validCrlFound = true;
+            }
+            catch (AnnotatedException e)
+            {
+                lastException = e;
+            }
+        }
+        if (!validCrlFound)
+        {
+            throw lastException;
+        }
+    }
+
+    /**
+     * Checks a certificate if it is revoked.
+     *
+     * @param paramsPKIX       PKIX parameters.
+     * @param cert             Certificate to check if it is revoked.
+     * @param validDate        The date when the certificate revocation status should be
+     *                         checked.
+     * @param sign             The issuer certificate of the certificate <code>cert</code>.
+     * @param workingPublicKey The public key of the issuer certificate <code>sign</code>.
+     * @param certPathCerts    The certificates of the certification path.
+     * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+     *                            or some error occurs.
+     */
+    protected static void checkCRLs(
+        PKIXExtendedParameters paramsPKIX,
+        X509Certificate cert,
+        Date validDate,
+        X509Certificate sign,
+        PublicKey workingPublicKey,
+        List certPathCerts,
+        JcaJceHelper helper)
+        throws AnnotatedException
+    {
+        AnnotatedException lastException = null;
+        CRLDistPoint crldp = null;
+        try
+        {
+            crldp = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS));
+        }
+        catch (Exception e)
+        {
+            throw new AnnotatedException("CRL distribution point extension could not be read.", e);
+        }
+
+        PKIXExtendedParameters.Builder paramsBldr = new PKIXExtendedParameters.Builder(paramsPKIX);
+        try
+        {
+            List extras = CertPathValidatorUtilities.getAdditionalStoresFromCRLDistributionPoint(crldp, paramsPKIX.getNamedCRLStoreMap());
+            for (Iterator it = extras.iterator(); it.hasNext();)
+            {
+                paramsBldr.addCRLStore((PKIXCRLStore)it.next());
+            }
+        }
+        catch (AnnotatedException e)
+        {
+            throw new AnnotatedException(
+                "No additional CRL locations could be decoded from CRL distribution point extension.", e);
+        }
+        CertStatus certStatus = new CertStatus();
+        ReasonsMask reasonsMask = new ReasonsMask();
+        PKIXExtendedParameters finalParams = paramsBldr.build();
+
+        boolean validCrlFound = false;
+        // for each distribution point
+        if (crldp != null)
+        {
+            DistributionPoint dps[] = null;
+            try
+            {
+                dps = crldp.getDistributionPoints();
+            }
+            catch (Exception e)
+            {
+                throw new AnnotatedException("Distribution points could not be read.", e);
+            }
+            if (dps != null)
+            {
+                for (int i = 0; i < dps.length && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons(); i++)
+                {
+                    try
+                    {
+                        checkCRL(dps[i], finalParams, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts, helper);
+                        validCrlFound = true;
+                    }
+                    catch (AnnotatedException e)
+                    {
+                        lastException = e;
+                    }
+                }
+            }
+        }
+
+        /*
+         * If the revocation status has not been determined, repeat the process
+         * above with any available CRLs not specified in a distribution point
+         * but issued by the certificate issuer.
+         */
+
+        if (certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons())
+        {
+            try
+            {
+                /*
+                 * assume a DP with both the reasons and the cRLIssuer fields
+                 * omitted and a distribution point name of the certificate
+                 * issuer.
+                 */
+                ASN1Primitive issuer = null;
+                try
+                {
+                    issuer = new ASN1InputStream(PrincipalUtils.getEncodedIssuerPrincipal(cert).getEncoded())
+                        .readObject();
+                }
+                catch (Exception e)
+                {
+                    throw new AnnotatedException("Issuer from certificate for CRL could not be reencoded.", e);
+                }
+                DistributionPoint dp = new DistributionPoint(new DistributionPointName(0, new GeneralNames(
+                    new GeneralName(GeneralName.directoryName, issuer))), null, null);
+                PKIXExtendedParameters paramsPKIXClone = (PKIXExtendedParameters)paramsPKIX.clone();
+                checkCRL(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask,
+                    certPathCerts, helper);
+                validCrlFound = true;
+            }
+            catch (AnnotatedException e)
+            {
+                lastException = e;
+            }
+        }
+
+        if (!validCrlFound)
+        {
+            if (lastException instanceof AnnotatedException)
+            {
+                throw lastException;
+            }
+
+            throw new AnnotatedException("No valid CRL found.", lastException);
+        }
+        if (certStatus.getCertStatus() != CertStatus.UNREVOKED)
+        {
+            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
+            df.setTimeZone(TimeZone.getTimeZone("UTC"));
+            String message = "Certificate revocation after " + df.format(certStatus.getRevocationDate());
+            message += ", reason: " + crlReasons[certStatus.getCertStatus()];
+            throw new AnnotatedException(message);
+        }
+        if (!reasonsMask.isAllReasons() && certStatus.getCertStatus() == CertStatus.UNREVOKED)
+        {
+            certStatus.setCertStatus(CertStatus.UNDETERMINED);
+        }
+        if (certStatus.getCertStatus() == CertStatus.UNDETERMINED)
+        {
+            throw new AnnotatedException("Certificate status could not be determined.");
+        }
+    }
+
+    protected static int prepareNextCertJ(
+        CertPath certPath,
+        int index,
+        int inhibitAnyPolicy)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (j)
+        //
+        ASN1Integer iap = null;
+        try
+        {
+            iap = ASN1Integer.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.INHIBIT_ANY_POLICY));
+        }
+        catch (Exception e)
+        {
+            throw new ExtCertPathValidatorException("Inhibit any-policy extension cannot be decoded.", e, certPath,
+                index);
+        }
+
+        if (iap != null)
+        {
+            int _inhibitAnyPolicy = iap.getValue().intValue();
+
+            if (_inhibitAnyPolicy < inhibitAnyPolicy)
+            {
+                return _inhibitAnyPolicy;
+            }
+        }
+        return inhibitAnyPolicy;
+    }
+
+    protected static void prepareNextCertK(
+        CertPath certPath,
+        int index)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (k)
+        //
+        BasicConstraints bc = null;
+        try
+        {
+            bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.BASIC_CONSTRAINTS));
+        }
+        catch (Exception e)
+        {
+            throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+                index);
+        }
+        if (bc != null)
+        {
+            if (!(bc.isCA()))
+            {
+                throw new CertPathValidatorException("Not a CA certificate");
+            }
+        }
+        else
+        {
+            throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints");
+        }
+    }
+
+    protected static int prepareNextCertL(
+        CertPath certPath,
+        int index,
+        int maxPathLength)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (l)
+        //
+        if (!CertPathValidatorUtilities.isSelfIssued(cert))
+        {
+            if (maxPathLength <= 0)
+            {
+                throw new ExtCertPathValidatorException("Max path length not greater than zero", null, certPath, index);
+            }
+
+            return maxPathLength - 1;
+        }
+        return maxPathLength;
+    }
+
+    protected static int prepareNextCertM(
+        CertPath certPath,
+        int index,
+        int maxPathLength)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+
+        //
+        // (m)
+        //
+        BasicConstraints bc = null;
+        try
+        {
+            bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.BASIC_CONSTRAINTS));
+        }
+        catch (Exception e)
+        {
+            throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+                index);
+        }
+        if (bc != null)
+        {
+            BigInteger _pathLengthConstraint = bc.getPathLenConstraint();
+
+            if (_pathLengthConstraint != null)
+            {
+                int _plc = _pathLengthConstraint.intValue();
+
+                if (_plc < maxPathLength)
+                {
+                    return _plc;
+                }
+            }
+        }
+        return maxPathLength;
+    }
+
+    protected static void prepareNextCertN(
+        CertPath certPath,
+        int index)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+
+        //
+        // (n)
+        //
+        boolean[] _usage = cert.getKeyUsage();
+
+        if ((_usage != null) && !_usage[RFC3280CertPathUtilities.KEY_CERT_SIGN])
+        {
+            throw new ExtCertPathValidatorException(
+                "Issuer certificate keyusage extension is critical and does not permit key signing.", null,
+                certPath, index);
+        }
+    }
+
+    protected static void prepareNextCertO(
+        CertPath certPath,
+        int index,
+        Set criticalExtensions,
+        List pathCheckers)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (o)
+        //
+
+        Iterator tmpIter;
+        tmpIter = pathCheckers.iterator();
+        while (tmpIter.hasNext())
+        {
+            try
+            {
+                ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+            }
+            catch (CertPathValidatorException e)
+            {
+                throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index);
+            }
+        }
+        if (!criticalExtensions.isEmpty())
+        {
+            throw new ExtCertPathValidatorException("Certificate has unsupported critical extension: " + criticalExtensions, null, certPath,
+                index);
+        }
+    }
+
+    protected static int prepareNextCertH1(
+        CertPath certPath,
+        int index,
+        int explicitPolicy)
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (h)
+        //
+        if (!CertPathValidatorUtilities.isSelfIssued(cert))
+        {
+            //
+            // (1)
+            //
+            if (explicitPolicy != 0)
+            {
+                return explicitPolicy - 1;
+            }
+        }
+        return explicitPolicy;
+    }
+
+    protected static int prepareNextCertH2(
+        CertPath certPath,
+        int index,
+        int policyMapping)
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (h)
+        //
+        if (!CertPathValidatorUtilities.isSelfIssued(cert))
+        {
+            //
+            // (2)
+            //
+            if (policyMapping != 0)
+            {
+                return policyMapping - 1;
+            }
+        }
+        return policyMapping;
+    }
+
+    protected static int prepareNextCertH3(
+        CertPath certPath,
+        int index,
+        int inhibitAnyPolicy)
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (h)
+        //
+        if (!CertPathValidatorUtilities.isSelfIssued(cert))
+        {
+            //
+            // (3)
+            //
+            if (inhibitAnyPolicy != 0)
+            {
+                return inhibitAnyPolicy - 1;
+            }
+        }
+        return inhibitAnyPolicy;
+    }
+
+    protected static final String[] crlReasons = new String[]
+        {
+            "unspecified",
+            "keyCompromise",
+            "cACompromise",
+            "affiliationChanged",
+            "superseded",
+            "cessationOfOperation",
+            "certificateHold",
+            "unknown",
+            "removeFromCRL",
+            "privilegeWithdrawn",
+            "aACompromise"};
+
+    protected static int wrapupCertA(
+        int explicitPolicy,
+        X509Certificate cert)
+    {
+        //
+        // (a)
+        //
+        if (!CertPathValidatorUtilities.isSelfIssued(cert) && (explicitPolicy != 0))
+        {
+            explicitPolicy--;
+        }
+        return explicitPolicy;
+    }
+
+    protected static int wrapupCertB(
+        CertPath certPath,
+        int index,
+        int explicitPolicy)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        //
+        // (b)
+        //
+        int tmpInt;
+        ASN1Sequence pc = null;
+        try
+        {
+            pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+                RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+        }
+        catch (AnnotatedException e)
+        {
+            throw new ExtCertPathValidatorException("Policy constraints could not be decoded.", e, certPath, index);
+        }
+        if (pc != null)
+        {
+            Enumeration policyConstraints = pc.getObjects();
+
+            while (policyConstraints.hasMoreElements())
+            {
+                ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+                switch (constraint.getTagNo())
+                {
+                    case 0:
+                        try
+                        {
+                            tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue();
+                        }
+                        catch (Exception e)
+                        {
+                            throw new ExtCertPathValidatorException(
+                                "Policy constraints requireExplicitPolicy field could not be decoded.", e, certPath,
+                                index);
+                        }
+                        if (tmpInt == 0)
+                        {
+                            return 0;
+                        }
+                        break;
+                }
+            }
+        }
+        return explicitPolicy;
+    }
+
+    protected static void wrapupCertF(
+        CertPath certPath,
+        int index,
+        List pathCheckers,
+        Set criticalExtensions)
+        throws CertPathValidatorException
+    {
+        List certs = certPath.getCertificates();
+        X509Certificate cert = (X509Certificate)certs.get(index);
+        Iterator tmpIter;
+        tmpIter = pathCheckers.iterator();
+        while (tmpIter.hasNext())
+        {
+            try
+            {
+                ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+            }
+            catch (CertPathValidatorException e)
+            {
+                throw new ExtCertPathValidatorException(e.getMessage(), e, certPath, index);
+            }
+            catch (Exception e)
+            {
+                throw new CertPathValidatorException("Additional certificate path checker failed.", e, certPath, index);
+            }
+        }
+
+        if (!criticalExtensions.isEmpty())
+        {
+            throw new ExtCertPathValidatorException("Certificate has unsupported critical extension: " + criticalExtensions, null, certPath,
+                index);
+        }
+    }
+
+    protected static PKIXPolicyNode wrapupCertG(
+        CertPath certPath,
+        PKIXExtendedParameters paramsPKIX,
+        Set userInitialPolicySet,
+        int index,
+        List[] policyNodes,
+        PKIXPolicyNode validPolicyTree,
+        Set acceptablePolicies)
+        throws CertPathValidatorException
+    {
+        int n = certPath.getCertificates().size();
+        //
+        // (g)
+        //
+        PKIXPolicyNode intersection;
+
+        //
+        // (g) (i)
+        //
+        if (validPolicyTree == null)
+        {
+            if (paramsPKIX.isExplicitPolicyRequired())
+            {
+                throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null,
+                    certPath, index);
+            }
+            intersection = null;
+        }
+        else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g)
+        // (ii)
+        {
+            if (paramsPKIX.isExplicitPolicyRequired())
+            {
+                if (acceptablePolicies.isEmpty())
+                {
+                    throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null,
+                        certPath, index);
+                }
+                else
+                {
+                    Set _validPolicyNodeSet = new HashSet();
+
+                    for (int j = 0; j < policyNodes.length; j++)
+                    {
+                        List _nodeDepth = policyNodes[j];
+
+                        for (int k = 0; k < _nodeDepth.size(); k++)
+                        {
+                            PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+                            if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy()))
+                            {
+                                Iterator _iter = _node.getChildren();
+                                while (_iter.hasNext())
+                                {
+                                    _validPolicyNodeSet.add(_iter.next());
+                                }
+                            }
+                        }
+                    }
+
+                    Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+                    while (_vpnsIter.hasNext())
+                    {
+                        PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+                        String _validPolicy = _node.getValidPolicy();
+
+                        if (!acceptablePolicies.contains(_validPolicy))
+                        {
+                            // validPolicyTree =
+                            // removePolicyNode(validPolicyTree, policyNodes,
+                            // _node);
+                        }
+                    }
+                    if (validPolicyTree != null)
+                    {
+                        for (int j = (n - 1); j >= 0; j--)
+                        {
+                            List nodes = policyNodes[j];
+
+                            for (int k = 0; k < nodes.size(); k++)
+                            {
+                                PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+                                if (!node.hasChildren())
+                                {
+                                    validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree,
+                                        policyNodes, node);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            intersection = validPolicyTree;
+        }
+        else
+        {
+            //
+            // (g) (iii)
+            //
+            // This implementation is not exactly same as the one described in
+            // RFC3280.
+            // However, as far as the validation result is concerned, both
+            // produce
+            // adequate result. The only difference is whether AnyPolicy is
+            // remain
+            // in the policy tree or not.
+            //
+            // (g) (iii) 1
+            //
+            Set _validPolicyNodeSet = new HashSet();
+
+            for (int j = 0; j < policyNodes.length; j++)
+            {
+                List _nodeDepth = policyNodes[j];
+
+                for (int k = 0; k < _nodeDepth.size(); k++)
+                {
+                    PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+                    if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy()))
+                    {
+                        Iterator _iter = _node.getChildren();
+                        while (_iter.hasNext())
+                        {
+                            PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next();
+                            if (!RFC3280CertPathUtilities.ANY_POLICY.equals(_c_node.getValidPolicy()))
+                            {
+                                _validPolicyNodeSet.add(_c_node);
+                            }
+                        }
+                    }
+                }
+            }
+
+            //
+            // (g) (iii) 2
+            //
+            Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+            while (_vpnsIter.hasNext())
+            {
+                PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+                String _validPolicy = _node.getValidPolicy();
+
+                if (!userInitialPolicySet.contains(_validPolicy))
+                {
+                    validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, _node);
+                }
+            }
+
+            //
+            // (g) (iii) 4
+            //
+            if (validPolicyTree != null)
+            {
+                for (int j = (n - 1); j >= 0; j--)
+                {
+                    List nodes = policyNodes[j];
+
+                    for (int k = 0; k < nodes.size(); k++)
+                    {
+                        PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+                        if (!node.hasChildren())
+                        {
+                            validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes,
+                                node);
+                        }
+                    }
+                }
+            }
+
+            intersection = validPolicyTree;
+        }
+        return intersection;
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/ReasonsMask.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/ReasonsMask.java
new file mode 100644
index 0000000..3367bbe
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/ReasonsMask.java
@@ -0,0 +1,102 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import com.android.internal.org.bouncycastle.asn1.x509.ReasonFlags;
+
+/**
+ * This class helps to handle CRL revocation reasons mask. Each CRL handles a
+ * certain set of revocation reasons.
+ */
+class ReasonsMask
+{
+    private int _reasons;
+
+    /**
+     * Constructs are reason mask with the reasons.
+     * 
+     * @param reasons The reasons.
+     */
+    ReasonsMask(ReasonFlags reasons)
+    {
+        _reasons = reasons.intValue();
+    }
+
+    private ReasonsMask(int reasons)
+    {
+        _reasons = reasons;
+    }
+
+    /**
+     * A reason mask with no reason.
+     * 
+     */
+    ReasonsMask()
+    {
+        this(0);
+    }
+
+    /**
+     * A mask with all revocation reasons.
+     */
+    static final ReasonsMask allReasons = new ReasonsMask(ReasonFlags.aACompromise
+            | ReasonFlags.affiliationChanged | ReasonFlags.cACompromise
+            | ReasonFlags.certificateHold | ReasonFlags.cessationOfOperation
+            | ReasonFlags.keyCompromise | ReasonFlags.privilegeWithdrawn
+            | ReasonFlags.unused | ReasonFlags.superseded);
+
+    /**
+     * Adds all reasons from the reasons mask to this mask.
+     * 
+     * @param mask The reasons mask to add.
+     */
+    void addReasons(ReasonsMask mask)
+    {
+        _reasons = _reasons | mask.getReasons();
+    }
+
+    /**
+     * Returns <code>true</code> if this reasons mask contains all possible
+     * reasons.
+     * 
+     * @return <code>true</code> if this reasons mask contains all possible
+     *         reasons.
+     */
+    boolean isAllReasons()
+    {
+        return _reasons == allReasons._reasons ? true : false;
+    }
+
+    /**
+     * Intersects this mask with the given reasons mask.
+     * 
+     * @param mask The mask to intersect with.
+     * @return The intersection of this and the given mask.
+     */
+    ReasonsMask intersect(ReasonsMask mask)
+    {
+        ReasonsMask _mask = new ReasonsMask();
+        _mask.addReasons(new ReasonsMask(_reasons & mask.getReasons()));
+        return _mask;
+    }
+
+    /**
+     * Returns <code>true</code> if the passed reasons mask has new reasons.
+     * 
+     * @param mask The reasons mask which should be tested for new reasons.
+     * @return <code>true</code> if the passed reasons mask has new reasons.
+     */
+    boolean hasNewReasons(ReasonsMask mask)
+    {
+        return ((_reasons | mask.getReasons() ^ _reasons) != 0);
+    }
+
+    /**
+     * Returns the reasons in this mask.
+     * 
+     * @return Returns the reasons.
+     */
+    int getReasons()
+    {
+        return _reasons;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509CRLEntryObject.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509CRLEntryObject.java
new file mode 100644
index 0000000..0efb820
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509CRLEntryObject.java
@@ -0,0 +1,321 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.util.ASN1Dump;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x509.CRLReason;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.Extensions;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralNames;
+import com.android.internal.org.bouncycastle.asn1.x509.TBSCertList;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Extension;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ * 
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509CRLEntryObject extends X509CRLEntry
+{
+    private TBSCertList.CRLEntry c;
+
+    private X500Name certificateIssuer;
+    private int           hashValue;
+    private boolean       isHashValueSet;
+
+    public X509CRLEntryObject(TBSCertList.CRLEntry c)
+    {
+        this.c = c;
+        this.certificateIssuer = null;
+    }
+
+    /**
+     * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code>
+     * is <code>false</code> {@link #getCertificateIssuer()} will always
+     * return <code>null</code>, <code>previousCertificateIssuer</code> is
+     * ignored. If this <code>isIndirect</code> is specified and this CRLEntry
+     * has no certificate issuer CRL entry extension
+     * <code>previousCertificateIssuer</code> is returned by
+     * {@link #getCertificateIssuer()}.
+     * 
+     * @param c
+     *            TBSCertList.CRLEntry object.
+     * @param isIndirect
+     *            <code>true</code> if the corresponding CRL is a indirect
+     *            CRL.
+     * @param previousCertificateIssuer
+     *            Certificate issuer of the previous CRLEntry.
+     */
+    public X509CRLEntryObject(
+        TBSCertList.CRLEntry c,
+        boolean isIndirect,
+        X500Name previousCertificateIssuer)
+    {
+        this.c = c;
+        this.certificateIssuer = loadCertificateIssuer(isIndirect, previousCertificateIssuer);
+    }
+
+    /**
+     * Will return true if any extensions are present and marked as critical as
+     * we currently don't handle any extensions!
+     */
+    public boolean hasUnsupportedCriticalExtension()
+    {
+        Set extns = getCriticalExtensionOIDs();
+
+        return extns != null && !extns.isEmpty();
+    }
+
+    private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer)
+    {
+        if (!isIndirect)
+        {
+            return null;
+        }
+
+        Extension ext = getExtension(Extension.certificateIssuer);
+        if (ext == null)
+        {
+            return previousCertificateIssuer;
+        }
+
+        try
+        {
+            GeneralName[] names = GeneralNames.getInstance(ext.getParsedValue()).getNames();
+            for (int i = 0; i < names.length; i++)
+            {
+                if (names[i].getTagNo() == GeneralName.directoryName)
+                {
+                    return X500Name.getInstance(names[i].getName());
+                }
+            }
+            return null;
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    public X500Principal getCertificateIssuer()
+    {
+        if (certificateIssuer == null)
+        {
+            return null;
+        }
+        try
+        {
+            return new X500Principal(certificateIssuer.getEncoded());
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+
+    private Set getExtensionOIDs(boolean critical)
+    {
+        Extensions extensions = c.getExtensions();
+
+        if (extensions != null)
+        {
+            Set set = new HashSet();
+            Enumeration e = extensions.oids();
+
+            while (e.hasMoreElements())
+            {
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+                Extension ext = extensions.getExtension(oid);
+
+                if (critical == ext.isCritical())
+                {
+                    set.add(oid.getId());
+                }
+            }
+
+            return set;
+        }
+
+        return null;
+    }
+
+    public Set getCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(true);
+    }
+
+    public Set getNonCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(false);
+    }
+
+    private Extension getExtension(ASN1ObjectIdentifier oid)
+    {
+        Extensions exts = c.getExtensions();
+
+        if (exts != null)
+        {
+            return exts.getExtension(oid);
+        }
+
+        return null;
+    }
+
+    public byte[] getExtensionValue(String oid)
+    {
+        Extension ext = getExtension(new ASN1ObjectIdentifier(oid));
+
+        if (ext != null)
+        {
+            try
+            {
+                return ext.getExtnValue().getEncoded();
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException("error encoding " + e.toString());
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Cache the hashCode value - calculating it with the standard method.
+     * @return  calculated hashCode.
+     */
+    public int hashCode()
+    {
+        if (!isHashValueSet)
+        {
+            hashValue = super.hashCode();
+            isHashValueSet = true;
+        }
+
+        return hashValue;
+    }
+
+    public boolean equals(Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (o instanceof X509CRLEntryObject)
+        {
+            X509CRLEntryObject other = (X509CRLEntryObject)o;
+
+            return this.c.equals(other.c);
+        }
+
+        return super.equals(this);
+    }
+
+    public byte[] getEncoded()
+        throws CRLException
+    {
+        try
+        {
+            return c.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+
+    public BigInteger getSerialNumber()
+    {
+        return c.getUserCertificate().getValue();
+    }
+
+    public Date getRevocationDate()
+    {
+        return c.getRevocationDate().getDate();
+    }
+
+    public boolean hasExtensions()
+    {
+        return c.getExtensions() != null;
+    }
+
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        String nl = Strings.lineSeparator();
+
+        buf.append("      userCertificate: ").append(this.getSerialNumber()).append(nl);
+        buf.append("       revocationDate: ").append(this.getRevocationDate()).append(nl);
+        buf.append("       certificateIssuer: ").append(this.getCertificateIssuer()).append(nl);
+
+        Extensions extensions = c.getExtensions();
+
+        if (extensions != null)
+        {
+            Enumeration e = extensions.oids();
+            if (e.hasMoreElements())
+            {
+                buf.append("   crlEntryExtensions:").append(nl);
+
+                while (e.hasMoreElements())
+                {
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    Extension ext = extensions.getExtension(oid);
+                    if (ext.getExtnValue() != null)
+                    {
+                        byte[]                  octs = ext.getExtnValue().getOctets();
+                        ASN1InputStream dIn = new ASN1InputStream(octs);
+                        buf.append("                       critical(").append(ext.isCritical()).append(") ");
+                        try
+                        {
+                            if (oid.equals(X509Extension.reasonCode))
+                            {
+                                buf.append(CRLReason.getInstance(ASN1Enumerated.getInstance(dIn.readObject()))).append(nl);
+                            }
+                            else if (oid.equals(X509Extension.certificateIssuer))
+                            {
+                                buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl);
+                            }
+                            else 
+                            {
+                                buf.append(oid.getId());
+                                buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            buf.append(oid.getId());
+                            buf.append(" value = ").append("*****").append(nl);
+                        }
+                    }
+                    else
+                    {
+                        buf.append(nl);
+                    }
+                }
+            }
+        }
+
+        return buf.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509CRLObject.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509CRLObject.java
new file mode 100644
index 0000000..96d3435
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509CRLObject.java
@@ -0,0 +1,666 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.util.ASN1Dump;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x509.CRLDistPoint;
+import com.android.internal.org.bouncycastle.asn1.x509.CRLNumber;
+import com.android.internal.org.bouncycastle.asn1.x509.CertificateList;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.Extensions;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralNames;
+import com.android.internal.org.bouncycastle.asn1.x509.IssuingDistributionPoint;
+import com.android.internal.org.bouncycastle.asn1.x509.TBSCertList;
+import com.android.internal.org.bouncycastle.jce.X509Principal;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ * @deprecated Do not use this class directly - either use org.bouncycastle.cert (bcpkix) or CertificateFactory.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509CRLObject
+    extends X509CRL
+{
+    private CertificateList c;
+    private String sigAlgName;
+    private byte[] sigAlgParams;
+    private boolean isIndirect;
+    private boolean isHashCodeSet = false;
+    private int     hashCodeValue;
+
+    public static boolean isIndirectCRL(X509CRL crl)
+        throws CRLException
+    {
+        try
+        {
+            byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
+            return idp != null
+                && IssuingDistributionPoint.getInstance(ASN1OctetString.getInstance(idp).getOctets()).isIndirectCRL();
+        }
+        catch (Exception e)
+        {
+            throw new ExtCRLException(
+                    "Exception reading IssuingDistributionPoint", e);
+        }
+    }
+
+    public X509CRLObject(
+        CertificateList c)
+        throws CRLException
+    {
+        this.c = c;
+        
+        try
+        {
+            this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+            
+            if (c.getSignatureAlgorithm().getParameters() != null)
+            {
+                this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
+            }
+            else
+            {
+                this.sigAlgParams = null;
+            }
+
+            this.isIndirect = isIndirectCRL(this);
+        }
+        catch (Exception e)
+        {
+            throw new CRLException("CRL contents invalid: " + e);
+        }
+    }
+
+    /**
+     * Will return true if any extensions are present and marked
+     * as critical as we currently dont handle any extensions!
+     */
+    public boolean hasUnsupportedCriticalExtension()
+    {
+        Set extns = getCriticalExtensionOIDs();
+
+        if (extns == null)
+        {
+            return false;
+        }
+
+        extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+        extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+
+        return !extns.isEmpty();
+    }
+
+    private Set getExtensionOIDs(boolean critical)
+    {
+        if (this.getVersion() == 2)
+        {
+            Extensions extensions = c.getTBSCertList().getExtensions();
+
+            if (extensions != null)
+            {
+                Set set = new HashSet();
+                Enumeration e = extensions.oids();
+
+                while (e.hasMoreElements())
+                {
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    Extension ext = extensions.getExtension(oid);
+
+                    if (critical == ext.isCritical())
+                    {
+                        set.add(oid.getId());
+                    }
+                }
+
+                return set;
+            }
+        }
+
+        return null;
+    }
+
+    public Set getCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(true);
+    }
+
+    public Set getNonCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(false);
+    }
+
+    public byte[] getExtensionValue(String oid)
+    {
+        Extensions exts = c.getTBSCertList().getExtensions();
+
+        if (exts != null)
+        {
+            Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+            if (ext != null)
+            {
+                try
+                {
+                    return ext.getExtnValue().getEncoded();
+                }
+                catch (Exception e)
+                {
+                    throw new IllegalStateException("error parsing " + e.toString());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public byte[] getEncoded()
+        throws CRLException
+    {
+        try
+        {
+            return c.getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+
+    public void verify(PublicKey key)
+        throws CRLException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        Signature sig;
+
+        try
+        {
+            sig = Signature.getInstance(getSigAlgName(), BouncyCastleProvider.PROVIDER_NAME);
+        }
+        catch (Exception e)
+        {
+            sig = Signature.getInstance(getSigAlgName());
+        }
+
+        doVerify(key, sig);
+    }
+
+    public void verify(PublicKey key, String sigProvider)
+        throws CRLException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        Signature sig;
+
+        if (sigProvider != null)
+        {
+            sig = Signature.getInstance(getSigAlgName(), sigProvider);
+        }
+        else
+        {
+            sig = Signature.getInstance(getSigAlgName());
+        }
+
+        doVerify(key, sig);
+    }
+
+    public void verify(PublicKey key, Provider sigProvider)
+        throws CRLException, NoSuchAlgorithmException,
+        InvalidKeyException, SignatureException
+    {
+        Signature sig;
+
+        if (sigProvider != null)
+        {
+            sig = Signature.getInstance(getSigAlgName(), sigProvider);
+        }
+        else
+        {
+            sig = Signature.getInstance(getSigAlgName());
+        }
+
+        doVerify(key, sig);
+    }
+
+    private void doVerify(PublicKey key, Signature sig)
+        throws CRLException, NoSuchAlgorithmException,
+        InvalidKeyException, SignatureException
+    {
+        if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
+        {
+            throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
+        }
+
+        sig.initVerify(key);
+        sig.update(this.getTBSCertList());
+
+        if (!sig.verify(this.getSignature()))
+        {
+            throw new SignatureException("CRL does not verify with supplied public key.");
+        }
+    }
+
+    public int getVersion()
+    {
+        return c.getVersionNumber();
+    }
+
+    public Principal getIssuerDN()
+    {
+        return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
+    }
+
+    public X500Principal getIssuerX500Principal()
+    {
+        try
+        {
+            return new X500Principal(c.getIssuer().getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("can't encode issuer DN");
+        }
+    }
+
+    public Date getThisUpdate()
+    {
+        return c.getThisUpdate().getDate();
+    }
+
+    public Date getNextUpdate()
+    {
+        if (c.getNextUpdate() != null)
+        {
+            return c.getNextUpdate().getDate();
+        }
+
+        return null;
+    }
+ 
+    private Set loadCRLEntries()
+    {
+        Set entrySet = new HashSet();
+        Enumeration certs = c.getRevokedCertificateEnumeration();
+
+        X500Name previousCertificateIssuer = null; // the issuer
+        while (certs.hasMoreElements())
+        {
+            TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+            X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+            entrySet.add(crlEntry);
+            if (isIndirect && entry.hasExtensions())
+            {
+                Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+                if (currentCaName != null)
+                {
+                    previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+                }
+            }
+        }
+
+        return entrySet;
+    }
+
+    public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
+    {
+        Enumeration certs = c.getRevokedCertificateEnumeration();
+
+        X500Name previousCertificateIssuer = null; // the issuer
+        while (certs.hasMoreElements())
+        {
+            TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+
+            if (serialNumber.equals(entry.getUserCertificate().getValue()))
+            {
+                return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+            }
+
+            if (isIndirect && entry.hasExtensions())
+            {
+                Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+                if (currentCaName != null)
+                {
+                    previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public Set getRevokedCertificates()
+    {
+        Set entrySet = loadCRLEntries();
+
+        if (!entrySet.isEmpty())
+        {
+            return Collections.unmodifiableSet(entrySet);
+        }
+
+        return null;
+    }
+
+    public byte[] getTBSCertList()
+        throws CRLException
+    {
+        try
+        {
+            return c.getTBSCertList().getEncoded("DER");
+        }
+        catch (IOException e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+
+    public byte[] getSignature()
+    {
+        return c.getSignature().getOctets();
+    }
+
+    public String getSigAlgName()
+    {
+        return sigAlgName;
+    }
+
+    public String getSigAlgOID()
+    {
+        return c.getSignatureAlgorithm().getAlgorithm().getId();
+    }
+
+    public byte[] getSigAlgParams()
+    {
+        if (sigAlgParams != null)
+        {
+            byte[] tmp = new byte[sigAlgParams.length];
+            
+            System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
+            
+            return tmp;
+        }
+        
+        return null;
+    }
+
+    /**
+     * Returns a string representation of this CRL.
+     *
+     * @return a string representation of this CRL.
+     */
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        String nl = Strings.lineSeparator();
+
+        buf.append("              Version: ").append(this.getVersion()).append(
+            nl);
+        buf.append("             IssuerDN: ").append(this.getIssuerDN())
+            .append(nl);
+        buf.append("          This update: ").append(this.getThisUpdate())
+            .append(nl);
+        buf.append("          Next update: ").append(this.getNextUpdate())
+            .append(nl);
+        buf.append("  Signature Algorithm: ").append(this.getSigAlgName())
+            .append(nl);
+
+        byte[] sig = this.getSignature();
+
+        buf.append("            Signature: ").append(
+            new String(Hex.encode(sig, 0, 20))).append(nl);
+        for (int i = 20; i < sig.length; i += 20)
+        {
+            if (i < sig.length - 20)
+            {
+                buf.append("                       ").append(
+                    new String(Hex.encode(sig, i, 20))).append(nl);
+            }
+            else
+            {
+                buf.append("                       ").append(
+                    new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+            }
+        }
+
+        Extensions extensions = c.getTBSCertList().getExtensions();
+
+        if (extensions != null)
+        {
+            Enumeration e = extensions.oids();
+
+            if (e.hasMoreElements())
+            {
+                buf.append("           Extensions: ").append(nl);
+            }
+
+            while (e.hasMoreElements())
+            {
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+                Extension ext = extensions.getExtension(oid);
+
+                if (ext.getExtnValue() != null)
+                {
+                    byte[] octs = ext.getExtnValue().getOctets();
+                    ASN1InputStream dIn = new ASN1InputStream(octs);
+                    buf.append("                       critical(").append(
+                        ext.isCritical()).append(") ");
+                    try
+                    {
+                        if (oid.equals(Extension.cRLNumber))
+                        {
+                            buf.append(
+                                new CRLNumber(ASN1Integer.getInstance(
+                                    dIn.readObject()).getPositiveValue()))
+                                .append(nl);
+                        }
+                        else if (oid.equals(Extension.deltaCRLIndicator))
+                        {
+                            buf.append(
+                                "Base CRL: "
+                                    + new CRLNumber(ASN1Integer.getInstance(
+                                        dIn.readObject()).getPositiveValue()))
+                                .append(nl);
+                        }
+                        else if (oid
+                            .equals(Extension.issuingDistributionPoint))
+                        {
+                            buf.append(
+                               IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
+                        }
+                        else if (oid
+                            .equals(Extension.cRLDistributionPoints))
+                        {
+                            buf.append(
+                                CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(Extension.freshestCRL))
+                        {
+                            buf.append(
+                                CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+                        }
+                        else
+                        {
+                            buf.append(oid.getId());
+                            buf.append(" value = ").append(
+                                ASN1Dump.dumpAsString(dIn.readObject()))
+                                .append(nl);
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        buf.append(oid.getId());
+                        buf.append(" value = ").append("*****").append(nl);
+                    }
+                }
+                else
+                {
+                    buf.append(nl);
+                }
+            }
+        }
+        Set set = getRevokedCertificates();
+        if (set != null)
+        {
+            Iterator it = set.iterator();
+            while (it.hasNext())
+            {
+                buf.append(it.next());
+                buf.append(nl);
+            }
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Checks whether the given certificate is on this CRL.
+     *
+     * @param cert the certificate to check for.
+     * @return true if the given certificate is on this CRL,
+     * false otherwise.
+     */
+    public boolean isRevoked(Certificate cert)
+    {
+        if (!cert.getType().equals("X.509"))
+        {
+            throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+        }
+
+        Enumeration certs = c.getRevokedCertificateEnumeration();
+
+        X500Name caName = c.getIssuer();
+
+        if (certs != null)
+        {
+            BigInteger serial = ((X509Certificate)cert).getSerialNumber();
+
+            while (certs.hasMoreElements())
+            {
+                TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement());
+
+                if (isIndirect && entry.hasExtensions())
+                {
+                    Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+                    if (currentCaName != null)
+                    {
+                        caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+                    }
+                }
+
+                if (entry.getUserCertificate().getValue().equals(serial))
+                {
+                    X500Name issuer;
+
+                    if (cert instanceof  X509Certificate)
+                    {
+                        issuer = X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded());
+                    }
+                    else
+                    {
+                        try
+                        {
+                            issuer = com.android.internal.org.bouncycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
+                        }
+                        catch (CertificateEncodingException e)
+                        {
+                            throw new RuntimeException("Cannot process certificate");
+                        }
+                    }
+
+                    if (!caName.equals(issuer))
+                    {
+                        return false;
+                    }
+
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public boolean equals(Object other)
+    {
+        if (this == other)
+        {
+            return true;
+        }
+
+        if (!(other instanceof X509CRL))
+        {
+            return false;
+        }
+
+        if (other instanceof X509CRLObject)
+        {
+            X509CRLObject crlObject = (X509CRLObject)other;
+
+            if (isHashCodeSet)
+            {
+                boolean otherIsHashCodeSet = crlObject.isHashCodeSet;
+                if (otherIsHashCodeSet)
+                {
+                    if (crlObject.hashCodeValue != hashCodeValue)
+                    {
+                        return false;
+                    }
+                }
+            }
+
+            return this.c.equals(crlObject.c);
+        }
+
+        return super.equals(other);
+    }
+
+    public int hashCode()
+    {
+        if (!isHashCodeSet)
+        {
+            isHashCodeSet = true;
+            hashCodeValue = super.hashCode();
+        }
+
+        return hashCodeValue;
+    }
+}
+
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509CertificateObject.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509CertificateObject.java
new file mode 100644
index 0000000..4d34408
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509CertificateObject.java
@@ -0,0 +1,951 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1BitString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OutputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.ASN1String;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERIA5String;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.misc.NetscapeCertType;
+import com.android.internal.org.bouncycastle.asn1.misc.NetscapeRevocationURL;
+import com.android.internal.org.bouncycastle.asn1.misc.VerisignCzagExtension;
+import com.android.internal.org.bouncycastle.asn1.util.ASN1Dump;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x500.style.RFC4519Style;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.BasicConstraints;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.Extensions;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.asn1.x509.KeyUsage;
+// BEGIN Android-added: Unknown reason
+import com.android.internal.org.bouncycastle.asn1.x509.X509Name;
+// END Android-added: Unknown reason
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import com.android.internal.org.bouncycastle.jce.X509Principal;
+import com.android.internal.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Integers;
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @deprecated Do not use this class directly - either use org.bouncycastle.cert (bcpkix) or CertificateFactory.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509CertificateObject
+    extends X509Certificate
+    implements PKCS12BagAttributeCarrier
+{
+    private com.android.internal.org.bouncycastle.asn1.x509.Certificate    c;
+    private BasicConstraints            basicConstraints;
+    private boolean[]                   keyUsage;
+    private boolean                     hashValueSet;
+    private int                         hashValue;
+
+    private PKCS12BagAttributeCarrier   attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+    public X509CertificateObject(
+        com.android.internal.org.bouncycastle.asn1.x509.Certificate    c)
+        throws CertificateParsingException
+    {
+        this.c = c;
+
+        try
+        {
+            byte[]  bytes = this.getExtensionBytes("2.5.29.19");
+
+            if (bytes != null)
+            {
+                basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
+            }
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+        }
+
+        try
+        {
+            byte[] bytes = this.getExtensionBytes("2.5.29.15");
+            if (bytes != null)
+            {
+                ASN1BitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
+
+                bytes = bits.getBytes();
+                int length = (bytes.length * 8) - bits.getPadBits();
+
+                keyUsage = new boolean[(length < 9) ? 9 : length];
+
+                for (int i = 0; i != length; i++)
+                {
+                    keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+                }
+            }
+            else
+            {
+                keyUsage = null;
+            }
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+        }
+    }
+
+    public void checkValidity()
+        throws CertificateExpiredException, CertificateNotYetValidException
+    {
+        this.checkValidity(new Date());
+    }
+
+    public void checkValidity(
+        Date    date)
+        throws CertificateExpiredException, CertificateNotYetValidException
+    {
+        if (date.getTime() > this.getNotAfter().getTime())  // for other VM compatibility
+        {
+            throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
+        }
+
+        if (date.getTime() < this.getNotBefore().getTime())
+        {
+            throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
+        }
+    }
+
+    public int getVersion()
+    {
+        return c.getVersionNumber();
+    }
+
+    public BigInteger getSerialNumber()
+    {
+        return c.getSerialNumber().getValue();
+    }
+
+    public Principal getIssuerDN()
+    {
+        try
+        {
+            return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+
+    public X500Principal getIssuerX500Principal()
+    {
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+
+            aOut.writeObject(c.getIssuer());
+
+            return new X500Principal(bOut.toByteArray());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("can't encode issuer DN");
+        }
+    }
+
+    public Principal getSubjectDN()
+    {
+        return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
+    }
+
+    public X500Principal getSubjectX500Principal()
+    {
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+
+            aOut.writeObject(c.getSubject());
+
+            return new X500Principal(bOut.toByteArray());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("can't encode issuer DN");
+        }
+    }
+
+    public Date getNotBefore()
+    {
+        return c.getStartDate().getDate();
+    }
+
+    public Date getNotAfter()
+    {
+        return c.getEndDate().getDate();
+    }
+
+    public byte[] getTBSCertificate()
+        throws CertificateEncodingException
+    {
+        try
+        {
+            return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException(e.toString());
+        }
+    }
+
+    public byte[] getSignature()
+    {
+        return c.getSignature().getOctets();
+    }
+
+    /**
+     * return a more "meaningful" representation for the signature algorithm used in
+     * the certficate.
+     */
+    public String getSigAlgName()
+    {
+        Provider    prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
+
+        if (prov != null)
+        {
+            String      algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+
+            if (algName != null)
+            {
+                return algName;
+            }
+        }
+
+        Provider[] provs = Security.getProviders();
+
+        //
+        // search every provider looking for a real algorithm
+        //
+        for (int i = 0; i != provs.length; i++)
+        {
+            String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+            if (algName != null)
+            {
+                return algName;
+            }
+        }
+
+        return this.getSigAlgOID();
+    }
+
+    /**
+     * return the object identifier for the signature.
+     */
+    public String getSigAlgOID()
+    {
+        return c.getSignatureAlgorithm().getAlgorithm().getId();
+    }
+
+    /**
+     * return the signature parameters, or null if there aren't any.
+     */
+    public byte[] getSigAlgParams()
+    {
+        if (c.getSignatureAlgorithm().getParameters() != null)
+        {
+            try
+            {
+                return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+            }
+            catch (IOException e)
+            {
+                return null;
+            }
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    public boolean[] getIssuerUniqueID()
+    {
+        DERBitString    id = c.getTBSCertificate().getIssuerUniqueId();
+
+        if (id != null)
+        {
+            byte[]          bytes = id.getBytes();
+            boolean[]       boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+            for (int i = 0; i != boolId.length; i++)
+            {
+                boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+            }
+
+            return boolId;
+        }
+            
+        return null;
+    }
+
+    public boolean[] getSubjectUniqueID()
+    {
+        DERBitString    id = c.getTBSCertificate().getSubjectUniqueId();
+
+        if (id != null)
+        {
+            byte[]          bytes = id.getBytes();
+            boolean[]       boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+            for (int i = 0; i != boolId.length; i++)
+            {
+                boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+            }
+
+            return boolId;
+        }
+            
+        return null;
+    }
+
+    public boolean[] getKeyUsage()
+    {
+        return keyUsage;
+    }
+
+    public List getExtendedKeyUsage() 
+        throws CertificateParsingException
+    {
+        byte[]  bytes = this.getExtensionBytes("2.5.29.37");
+
+        if (bytes != null)
+        {
+            try
+            {
+                ASN1InputStream dIn = new ASN1InputStream(bytes);
+                ASN1Sequence    seq = (ASN1Sequence)dIn.readObject();
+                List            list = new ArrayList();
+
+                for (int i = 0; i != seq.size(); i++)
+                {
+                    list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId());
+                }
+                
+                return Collections.unmodifiableList(list);
+            }
+            catch (Exception e)
+            {
+                throw new CertificateParsingException("error processing extended key usage extension");
+            }
+        }
+
+        return null;
+    }
+    
+    public int getBasicConstraints()
+    {
+        if (basicConstraints != null)
+        {
+            if (basicConstraints.isCA())
+            {
+                if (basicConstraints.getPathLenConstraint() == null)
+                {
+                    return Integer.MAX_VALUE;
+                }
+                else
+                {
+                    return basicConstraints.getPathLenConstraint().intValue();
+                }
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        return -1;
+    }
+
+    public Collection getSubjectAlternativeNames()
+        throws CertificateParsingException
+    {
+        return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId()));
+    }
+
+    public Collection getIssuerAlternativeNames()
+        throws CertificateParsingException
+    {
+        return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId()));
+    }
+
+    public Set getCriticalExtensionOIDs() 
+    {
+        if (this.getVersion() == 3)
+        {
+            Set             set = new HashSet();
+            Extensions  extensions = c.getTBSCertificate().getExtensions();
+
+            if (extensions != null)
+            {
+                Enumeration     e = extensions.oids();
+
+                while (e.hasMoreElements())
+                {
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    Extension       ext = extensions.getExtension(oid);
+
+                    if (ext.isCritical())
+                    {
+                        set.add(oid.getId());
+                    }
+                }
+
+                return set;
+            }
+        }
+
+        return null;
+    }
+
+    private byte[] getExtensionBytes(String oid)
+    {
+        Extensions exts = c.getTBSCertificate().getExtensions();
+
+        if (exts != null)
+        {
+            Extension   ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+            if (ext != null)
+            {
+                return ext.getExtnValue().getOctets();
+            }
+        }
+
+        return null;
+    }
+
+    public byte[] getExtensionValue(String oid) 
+    {
+        Extensions exts = c.getTBSCertificate().getExtensions();
+
+        if (exts != null)
+        {
+            Extension   ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+            if (ext != null)
+            {
+                try
+                {
+                    return ext.getExtnValue().getEncoded();
+                }
+                catch (Exception e)
+                {
+                    throw new IllegalStateException("error parsing " + e.toString());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public Set getNonCriticalExtensionOIDs() 
+    {
+        if (this.getVersion() == 3)
+        {
+            Set             set = new HashSet();
+            Extensions  extensions = c.getTBSCertificate().getExtensions();
+
+            if (extensions != null)
+            {
+                Enumeration     e = extensions.oids();
+
+                while (e.hasMoreElements())
+                {
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    Extension       ext = extensions.getExtension(oid);
+
+                    if (!ext.isCritical())
+                    {
+                        set.add(oid.getId());
+                    }
+                }
+
+                return set;
+            }
+        }
+
+        return null;
+    }
+
+    public boolean hasUnsupportedCriticalExtension()
+    {
+        if (this.getVersion() == 3)
+        {
+            Extensions  extensions = c.getTBSCertificate().getExtensions();
+
+            if (extensions != null)
+            {
+                Enumeration     e = extensions.oids();
+
+                while (e.hasMoreElements())
+                {
+                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                    String              oidId = oid.getId();
+
+                    if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE)
+                     || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES)
+                     || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS)
+                     || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)
+                     || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)
+                     || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)
+                     || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR)
+                     || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS)
+                     || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS)
+                     || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)
+                     || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS))
+                    {
+                        continue;
+                    }
+
+                    Extension       ext = extensions.getExtension(oid);
+
+                    if (ext.isCritical())
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public PublicKey getPublicKey()
+    {
+        try
+        {
+            return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
+        }
+        catch (IOException e)
+        {
+            return null;   // should never happen...
+        }
+    }
+
+    // BEGIN Android-added: Cache encoded certificates
+    private byte[] encoded;
+    // END Android-added: Cache encoded certificates
+    public byte[] getEncoded()
+        throws CertificateEncodingException
+    {
+        try
+        {
+            // BEGIN Android-changed: Cache encoded certificates
+            if (encoded == null) {
+                encoded = c.getEncoded(ASN1Encoding.DER);
+            }
+            return encoded;
+            // END Android-changed: Cache encoded certificates
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException(e.toString());
+        }
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (!(o instanceof Certificate))
+        {
+            return false;
+        }
+
+        Certificate other = (Certificate)o;
+
+        try
+        {
+            byte[] b1 = this.getEncoded();
+            byte[] b2 = other.getEncoded();
+
+            return Arrays.areEqual(b1, b2);
+        }
+        catch (CertificateEncodingException e)
+        {
+            return false;
+        }
+    }
+    
+    public synchronized int hashCode()
+    {
+        if (!hashValueSet)
+        {
+            hashValue = calculateHashCode();
+            hashValueSet = true;
+        }
+
+        return hashValue;
+    }
+    
+    private int calculateHashCode()
+    {
+        try
+        {
+            int hashCode = 0;
+            byte[] certData = this.getEncoded();
+            for (int i = 1; i < certData.length; i++)
+            {
+                 hashCode += certData[i] * i;
+            }
+            return hashCode;
+        }
+        catch (CertificateEncodingException e)
+        {
+            return 0;
+        }
+    }
+
+    public void setBagAttribute(
+        ASN1ObjectIdentifier oid,
+        ASN1Encodable        attribute)
+    {
+        attrCarrier.setBagAttribute(oid, attribute);
+    }
+
+    public ASN1Encodable getBagAttribute(
+        ASN1ObjectIdentifier oid)
+    {
+        return attrCarrier.getBagAttribute(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return attrCarrier.getBagAttributeKeys();
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = Strings.lineSeparator();
+
+        buf.append("  [0]         Version: ").append(this.getVersion()).append(nl);
+        buf.append("         SerialNumber: ").append(this.getSerialNumber()).append(nl);
+        buf.append("             IssuerDN: ").append(this.getIssuerDN()).append(nl);
+        buf.append("           Start Date: ").append(this.getNotBefore()).append(nl);
+        buf.append("           Final Date: ").append(this.getNotAfter()).append(nl);
+        buf.append("            SubjectDN: ").append(this.getSubjectDN()).append(nl);
+        buf.append("           Public Key: ").append(this.getPublicKey()).append(nl);
+        buf.append("  Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
+
+        byte[]  sig = this.getSignature();
+
+        buf.append("            Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
+        for (int i = 20; i < sig.length; i += 20)
+        {
+            if (i < sig.length - 20)
+            {
+                buf.append("                       ").append(new String(Hex.encode(sig, i, 20))).append(nl);
+            }
+            else
+            {
+                buf.append("                       ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+            }
+        }
+
+        Extensions extensions = c.getTBSCertificate().getExtensions();
+
+        if (extensions != null)
+        {
+            Enumeration     e = extensions.oids();
+
+            if (e.hasMoreElements())
+            {
+                buf.append("       Extensions: \n");
+            }
+
+            while (e.hasMoreElements())
+            {
+                ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)e.nextElement();
+                Extension ext = extensions.getExtension(oid);
+
+                if (ext.getExtnValue() != null)
+                {
+                    byte[]                  octs = ext.getExtnValue().getOctets();
+                    ASN1InputStream         dIn = new ASN1InputStream(octs);
+                    buf.append("                       critical(").append(ext.isCritical()).append(") ");
+                    try
+                    {
+                        if (oid.equals(Extension.basicConstraints))
+                        {
+                            buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(Extension.keyUsage))
+                        {
+                            buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
+                        {
+                            buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
+                        {
+                            buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
+                        {
+                            buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
+                        }
+                        else 
+                        {
+                            buf.append(oid.getId());
+                            buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+                            //buf.append(" value = ").append("*****").append(nl);
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        buf.append(oid.getId());
+                   //     buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl);
+                        buf.append(" value = ").append("*****").append(nl);
+                    }
+                }
+                else
+                {
+                    buf.append(nl);
+                }
+            }
+        }
+
+        return buf.toString();
+    }
+
+    public final void verify(
+        PublicKey   key)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        Signature   signature;
+        String      sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+        
+        try
+        {
+            signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
+        }
+        catch (Exception e)
+        {
+            signature = Signature.getInstance(sigName);
+        }
+        
+        checkSignature(key, signature);
+    }
+    
+    public final void verify(
+        PublicKey   key,
+        String      sigProvider)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+        Signature signature;
+
+        if (sigProvider != null)
+        {
+            signature = Signature.getInstance(sigName, sigProvider);
+        }
+        else
+        {
+            signature = Signature.getInstance(sigName);
+        }
+        
+        checkSignature(key, signature);
+    }
+
+    public final void verify(
+        PublicKey   key,
+        Provider    sigProvider)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, SignatureException
+    {
+        String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+        Signature signature;
+
+        if (sigProvider != null)
+        {
+            signature = Signature.getInstance(sigName, sigProvider);
+        }
+        else
+        {
+            signature = Signature.getInstance(sigName);
+        }
+
+        checkSignature(key, signature);
+    }
+
+    private void checkSignature(
+        PublicKey key, 
+        Signature signature) 
+        throws CertificateException, NoSuchAlgorithmException, 
+            SignatureException, InvalidKeyException
+    {
+        if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
+        {
+            throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+        }
+
+        ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
+
+        // TODO This should go after the initVerify?
+        X509SignatureUtil.setSignatureParameters(signature, params);
+
+        signature.initVerify(key);
+
+        signature.update(this.getTBSCertificate());
+
+        if (!signature.verify(this.getSignature()))
+        {
+            throw new SignatureException("certificate does not verify with supplied key");
+        }
+    }
+
+    private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+    {
+        if (!id1.getAlgorithm().equals(id2.getAlgorithm()))
+        {
+            return false;
+        }
+
+        if (id1.getParameters() == null)
+        {
+            if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        if (id2.getParameters() == null)
+        {
+            if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
+            {
+                return false;
+            }
+
+            return true;
+        }
+        
+        return id1.getParameters().equals(id2.getParameters());
+    }
+
+    private static Collection getAlternativeNames(byte[] extVal)
+        throws CertificateParsingException
+    {
+        if (extVal == null)
+        {
+            return null;
+        }
+        try
+        {
+            Collection temp = new ArrayList();
+            Enumeration it = ASN1Sequence.getInstance(extVal).getObjects();
+            while (it.hasMoreElements())
+            {
+                GeneralName genName = GeneralName.getInstance(it.nextElement());
+                List list = new ArrayList();
+                list.add(Integers.valueOf(genName.getTagNo()));
+                switch (genName.getTagNo())
+                {
+                case GeneralName.ediPartyName:
+                case GeneralName.x400Address:
+                case GeneralName.otherName:
+                    list.add(genName.getEncoded());
+                    break;
+                case GeneralName.directoryName:
+                    // BEGIN Android-changed: Unknown reason
+                    list.add(X509Name.getInstance(genName.getName()).toString(true, X509Name.DefaultSymbols));
+                    // END Android-changed: Unknown reason
+                    break;
+                case GeneralName.dNSName:
+                case GeneralName.rfc822Name:
+                case GeneralName.uniformResourceIdentifier:
+                    list.add(((ASN1String)genName.getName()).getString());
+                    break;
+                case GeneralName.registeredID:
+                    list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+                    break;
+                case GeneralName.iPAddress:
+                    byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets();
+                    final String addr;
+                    try
+                    {
+                        addr = InetAddress.getByAddress(addrBytes).getHostAddress();
+                    }
+                    catch (UnknownHostException e)
+                    {
+                        continue;
+                    }
+                    list.add(addr);
+                    break;
+                default:
+                    throw new IOException("Bad tag number: " + genName.getTagNo());
+                }
+
+                temp.add(Collections.unmodifiableList(list));
+            }
+            if (temp.size() == 0)
+            {
+                return null;
+            }
+            return Collections.unmodifiableCollection(temp);
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException(e.getMessage());
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509SignatureUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509SignatureUtil.java
new file mode 100644
index 0000000..ec886c7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/provider/X509SignatureUtil.java
@@ -0,0 +1,148 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.PSSParameterSpec;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Null;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+import com.android.internal.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+
+class X509SignatureUtil
+{
+    private static final ASN1Null       derNull = DERNull.INSTANCE;
+    
+    static void setSignatureParameters(
+        Signature signature,
+        ASN1Encodable params)
+        throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        if (params != null && !derNull.equals(params))
+        {
+            AlgorithmParameters  sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+            
+            try
+            {
+                sigParams.init(params.toASN1Primitive().getEncoded());
+            }
+            catch (IOException e)
+            {
+                throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+            }
+            
+            if (signature.getAlgorithm().endsWith("MGF1"))
+            {
+                try
+                {
+                    signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+                }
+                catch (GeneralSecurityException e)
+                {
+                    throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+                }
+            }
+        }
+    }
+    
+    static String getSignatureName(
+        AlgorithmIdentifier sigAlgId) 
+    {
+        ASN1Encodable params = sigAlgId.getParameters();
+        
+        if (params != null && !derNull.equals(params))
+        {
+            // BEGIN Android-removed: Unsupported algorithms
+            /*
+            if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+            {
+                RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+                
+                return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1";
+            }
+            */
+            // END Android-removed: Unsupported algorithms
+            if (sigAlgId.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA2))
+            {
+                ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params);
+                
+                return getDigestAlgName(ASN1ObjectIdentifier.getInstance(ecDsaParams.getObjectAt(0))) + "withECDSA";
+            }
+        }
+
+        return sigAlgId.getAlgorithm().getId();
+    }
+    
+    /**
+     * Return the digest algorithm using one of the standard JCA string
+     * representations rather the the algorithm identifier (if possible).
+     */
+    private static String getDigestAlgName(
+        ASN1ObjectIdentifier digestAlgOID)
+    {
+        if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+        {
+            return "MD5";
+        }
+        else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+        {
+            return "SHA1";
+        }
+        else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+        {
+            return "SHA224";
+        }
+        else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+        {
+            return "SHA256";
+        }
+        else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+        {
+            return "SHA384";
+        }
+        else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+        {
+            return "SHA512";
+        }
+        // BEGIN Android-removed: Unsupported algorithms
+        /*
+        else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+        {
+            return "RIPEMD128";
+        }
+        else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+        {
+            return "RIPEMD160";
+        }
+        else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+        {
+            return "RIPEMD256";
+        }
+        else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+        {
+            return "GOST3411";
+        }
+        */
+        // END Android-removed: Unsupported algorithms
+        else
+        {
+            return digestAlgOID.getId();            
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECKeySpec.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECKeySpec.java
new file mode 100644
index 0000000..3abe394
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECKeySpec.java
@@ -0,0 +1,28 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.spec;
+
+import java.security.spec.KeySpec;
+
+/**
+ * base class for an Elliptic Curve Key Spec
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECKeySpec
+    implements KeySpec
+{
+    private ECParameterSpec     spec;
+
+    protected ECKeySpec(
+        ECParameterSpec spec)
+    {
+        this.spec = spec;
+    }
+
+    /**
+     * return the domain parameters for the curve
+     */
+    public ECParameterSpec getParams()
+    {
+        return spec;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECNamedCurveGenParameterSpec.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECNamedCurveGenParameterSpec.java
new file mode 100644
index 0000000..6d11743
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECNamedCurveGenParameterSpec.java
@@ -0,0 +1,30 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Named curve generation spec
+ * <p>
+ * If you are using JDK 1.5 you should be looking at ECGenParameterSpec.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECNamedCurveGenParameterSpec
+    implements AlgorithmParameterSpec
+{
+    private String  name;
+
+    public ECNamedCurveGenParameterSpec(
+        String name)
+    {
+        this.name = name;
+    }
+
+    /**
+     * return the name of the curve the EC domain parameters belong to.
+     */
+    public String getName()
+    {
+        return name;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java
new file mode 100644
index 0000000..0ec146f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java
@@ -0,0 +1,64 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.spec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * specification signifying that the curve parameters can also be
+ * referred to by name.
+ * <p>
+ * If you are using JDK 1.5 you should be looking at {@link ECNamedCurveSpec}.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECNamedCurveParameterSpec
+    extends ECParameterSpec
+{
+    private String  name;
+
+    public ECNamedCurveParameterSpec(
+        String      name,
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n)
+    {
+        super(curve, G, n);
+
+        this.name = name;
+    }
+
+    public ECNamedCurveParameterSpec(
+        String      name,
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h)
+    {
+        super(curve, G, n, h);
+
+        this.name = name;
+    }
+
+    public ECNamedCurveParameterSpec(
+        String      name,
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h,
+        byte[]      seed)
+    {
+        super(curve, G, n, h, seed);
+
+        this.name = name;
+    }
+
+    /**
+     * return the name of the curve the EC domain parameters belong to.
+     */
+    public String getName()
+    {
+        return name;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECNamedCurveSpec.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECNamedCurveSpec.java
new file mode 100644
index 0000000..401ef67
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECNamedCurveSpec.java
@@ -0,0 +1,119 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.spec;
+
+import java.math.BigInteger;
+import java.security.spec.ECField;
+import java.security.spec.ECFieldF2m;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import com.android.internal.org.bouncycastle.math.ec.ECAlgorithms;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.field.FiniteField;
+import com.android.internal.org.bouncycastle.math.field.Polynomial;
+import com.android.internal.org.bouncycastle.math.field.PolynomialExtensionField;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * specification signifying that the curve parameters can also be
+ * referred to by name.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECNamedCurveSpec
+    extends java.security.spec.ECParameterSpec
+{
+    private String  name;
+
+    private static EllipticCurve convertCurve(
+        ECCurve  curve,
+        byte[]   seed)
+    {
+        ECField field = convertField(curve.getField());
+        BigInteger a = curve.getA().toBigInteger(), b = curve.getB().toBigInteger();
+        return new EllipticCurve(field, a, b, seed);
+    }
+
+    private static ECField convertField(FiniteField field)
+    {
+        if (ECAlgorithms.isFpField(field))
+        {
+            return new ECFieldFp(field.getCharacteristic());
+        }
+        else //if (ECAlgorithms.isF2mField(curveField))
+        {
+            Polynomial poly = ((PolynomialExtensionField)field).getMinimalPolynomial();
+            int[] exponents = poly.getExponentsPresent();
+            int[] ks = Arrays.reverse(Arrays.copyOfRange(exponents, 1, exponents.length - 1));
+            return new ECFieldF2m(poly.getDegree(), ks);
+        }
+    }
+
+    public ECNamedCurveSpec(
+        String                              name,
+        ECCurve                             curve,
+        com.android.internal.org.bouncycastle.math.ec.ECPoint    g,
+        BigInteger                          n)
+    {
+        super(convertCurve(curve, null), EC5Util.convertPoint(g), n, 1);
+
+        this.name = name;
+    }
+
+    public ECNamedCurveSpec(
+        String          name,
+        EllipticCurve   curve,
+        ECPoint         g,
+        BigInteger      n)
+    {
+        super(curve, g, n, 1);
+
+        this.name = name;
+    }
+    
+    public ECNamedCurveSpec(
+        String                              name,
+        ECCurve                             curve,
+        com.android.internal.org.bouncycastle.math.ec.ECPoint    g,
+        BigInteger                          n,
+        BigInteger                          h)
+    {
+        super(convertCurve(curve, null), EC5Util.convertPoint(g), n, h.intValue());
+
+        this.name = name;
+    }
+
+    public ECNamedCurveSpec(
+        String          name,
+        EllipticCurve   curve,
+        ECPoint         g,
+        BigInteger      n,
+        BigInteger      h)
+    {
+        super(curve, g, n, h.intValue());
+
+        this.name = name;
+    }
+    
+    public ECNamedCurveSpec(
+        String                              name,
+        ECCurve                             curve,
+        com.android.internal.org.bouncycastle.math.ec.ECPoint    g,
+        BigInteger                          n,
+        BigInteger                          h,
+        byte[]                              seed)
+    {
+        super(convertCurve(curve, seed), EC5Util.convertPoint(g), n, h.intValue());
+
+        this.name = name;
+    }
+
+    /**
+     * return the name of the curve the EC domain parameters belong to.
+     */
+    public String getName()
+    {
+        return name;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECParameterSpec.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECParameterSpec.java
new file mode 100644
index 0000000..35c927f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECParameterSpec.java
@@ -0,0 +1,123 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.spec;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * basic domain parameters for an Elliptic Curve public or private key.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECParameterSpec
+    implements AlgorithmParameterSpec
+{
+    private ECCurve     curve;
+    private byte[]      seed;
+    private ECPoint     G;
+    private BigInteger  n;
+    private BigInteger  h;
+
+    public ECParameterSpec(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n)
+    {
+        this.curve = curve;
+        this.G = G.normalize();
+        this.n = n;
+        this.h = BigInteger.valueOf(1);
+        this.seed = null;
+    }
+
+    public ECParameterSpec(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h)
+    {
+        this.curve = curve;
+        this.G = G.normalize();
+        this.n = n;
+        this.h = h;
+        this.seed = null;
+    }
+
+    public ECParameterSpec(
+        ECCurve     curve,
+        ECPoint     G,
+        BigInteger  n,
+        BigInteger  h,
+        byte[]      seed)
+    {
+        this.curve = curve;
+        this.G = G.normalize();
+        this.n = n;
+        this.h = h;
+        this.seed = seed;
+    }
+
+    /**
+     * return the curve along which the base point lies.
+     * @return the curve
+     */
+    public ECCurve getCurve()
+    {
+        return curve;
+    }
+
+    /**
+     * return the base point we are using for these domain parameters.
+     * @return the base point.
+     */
+    public ECPoint getG()
+    {
+        return G;
+    }
+
+    /**
+     * return the order N of G
+     * @return the order
+     */
+    public BigInteger getN()
+    {
+        return n;
+    }
+
+    /**
+     * return the cofactor H to the order of G.
+     * @return the cofactor
+     */
+    public BigInteger getH()
+    {
+        return h;
+    }
+
+    /**
+     * return the seed used to generate this curve (if available).
+     * @return the random seed
+     */
+    public byte[] getSeed()
+    {
+        return seed;
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof ECParameterSpec))
+        {
+            return false;
+        }
+
+        ECParameterSpec other = (ECParameterSpec)o;
+
+        return this.getCurve().equals(other.getCurve()) && this.getG().equals(other.getG());
+    }
+
+    public int hashCode()
+    {
+        return this.getCurve().hashCode() ^ this.getG().hashCode();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECPrivateKeySpec.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECPrivateKeySpec.java
new file mode 100644
index 0000000..b592045
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECPrivateKeySpec.java
@@ -0,0 +1,37 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.spec;
+
+import java.math.BigInteger;
+
+/**
+ * Elliptic Curve private key specification.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECPrivateKeySpec
+    extends ECKeySpec
+{
+    private BigInteger    d;
+
+    /**
+     * base constructor
+     *
+     * @param d the private number for the key.
+     * @param spec the domain parameters for the curve being used.
+     */
+    public ECPrivateKeySpec(
+        BigInteger      d,
+        ECParameterSpec spec)
+    {
+        super(spec);
+
+        this.d = d;
+    }
+
+    /**
+     * return the private number D
+     */
+    public BigInteger getD()
+    {
+        return d;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECPublicKeySpec.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECPublicKeySpec.java
new file mode 100644
index 0000000..0078f47
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/jce/spec/ECPublicKeySpec.java
@@ -0,0 +1,44 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.jce.spec;
+
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * Elliptic Curve public key specification
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECPublicKeySpec
+    extends ECKeySpec
+{
+    private ECPoint    q;
+
+    /**
+     * base constructor
+     *
+     * @param q the public point on the curve.
+     * @param spec the domain parameters for the curve.
+     */
+    public ECPublicKeySpec(
+        ECPoint         q,
+        ECParameterSpec spec)
+    {
+        super(spec);
+
+        if (q.getCurve() != null)
+        {
+            this.q = q.normalize();
+        }
+        else
+        {
+            this.q = q;
+        }
+    }
+
+    /**
+     * return the public point q
+     */
+    public ECPoint getQ()
+    {
+        return q;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/Primes.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/Primes.java
new file mode 100644
index 0000000..dd83736
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/Primes.java
@@ -0,0 +1,678 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * Utility methods for generating primes and testing for primality.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class Primes
+{
+    public static final int SMALL_FACTOR_LIMIT = 211;
+
+    private static final BigInteger ONE = BigInteger.valueOf(1);
+    private static final BigInteger TWO = BigInteger.valueOf(2);
+    private static final BigInteger THREE = BigInteger.valueOf(3);
+
+    /**
+     * Used to return the output from the
+     * {@linkplain Primes#enhancedMRProbablePrimeTest(BigInteger, SecureRandom, int) Enhanced
+     * Miller-Rabin Probabilistic Primality Test}
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class MROutput
+    {
+        private static MROutput probablyPrime()
+        {
+            return new MROutput(false, null);
+        }
+
+        private static MROutput provablyCompositeWithFactor(BigInteger factor)
+        {
+            return new MROutput(true, factor);
+        }
+
+        private static MROutput provablyCompositeNotPrimePower()
+        {
+            return new MROutput(true, null);
+        }
+
+        private boolean provablyComposite;
+        private BigInteger factor;
+
+        private MROutput(boolean provablyComposite, BigInteger factor)
+        {
+            this.provablyComposite = provablyComposite;
+            this.factor = factor;
+        }
+
+        public BigInteger getFactor()
+        {
+            return factor;
+        }
+
+        public boolean isProvablyComposite()
+        {
+            return provablyComposite;
+        }
+
+        public boolean isNotPrimePower()
+        {
+            return provablyComposite && factor == null;
+        }
+    }
+
+    /**
+     * Used to return the output from the
+     * {@linkplain Primes#generateSTRandomPrime(Digest, int, byte[]) Shawe-Taylor Random_Prime
+     * Routine}
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class STOutput
+    {
+        private BigInteger prime;
+        private byte[] primeSeed;
+        private int primeGenCounter;
+
+        private STOutput(BigInteger prime, byte[] primeSeed, int primeGenCounter)
+        {
+            this.prime = prime;
+            this.primeSeed = primeSeed;
+            this.primeGenCounter = primeGenCounter;
+        }
+
+        public BigInteger getPrime()
+        {
+            return prime;
+        }
+
+        public byte[] getPrimeSeed()
+        {
+            return primeSeed;
+        }
+
+        public int getPrimeGenCounter()
+        {
+            return primeGenCounter;
+        }
+    }
+
+    /**
+     * FIPS 186-4 C.6 Shawe-Taylor Random_Prime Routine
+     *
+     * Construct a provable prime number using a hash function.
+     *
+     * @param hash
+     *            the {@link Digest} instance to use (as "Hash()"). Cannot be null.
+     * @param length
+     *            the length (in bits) of the prime to be generated. Must be at least 2.
+     * @param inputSeed
+     *            the seed to be used for the generation of the requested prime. Cannot be null or
+     *            empty.
+     * @return an {@link STOutput} instance containing the requested prime.
+     */
+    public static STOutput generateSTRandomPrime(Digest hash, int length, byte[] inputSeed)
+    {
+        if (hash == null)
+        {
+            throw new IllegalArgumentException("'hash' cannot be null");
+        }
+        if (length < 2)
+        {
+            throw new IllegalArgumentException("'length' must be >= 2");
+        }
+        if (inputSeed == null || inputSeed.length == 0)
+        {
+            throw new IllegalArgumentException("'inputSeed' cannot be null or empty");
+        }
+
+        return implSTRandomPrime(hash, length, Arrays.clone(inputSeed));
+    }
+
+    /**
+     * FIPS 186-4 C.3.2 Enhanced Miller-Rabin Probabilistic Primality Test
+     *
+     * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. This is an
+     * alternative to {@link #isMRProbablePrime(BigInteger, SecureRandom, int)} that provides more
+     * information about a composite candidate, which may be useful when generating or validating
+     * RSA moduli.
+     *
+     * @param candidate
+     *            the {@link BigInteger} instance to test for primality.
+     * @param random
+     *            the source of randomness to use to choose bases.
+     * @param iterations
+     *            the number of randomly-chosen bases to perform the test for.
+     * @return an {@link MROutput} instance that can be further queried for details.
+     */
+    public static MROutput enhancedMRProbablePrimeTest(BigInteger candidate, SecureRandom random, int iterations)
+    {
+        checkCandidate(candidate, "candidate");
+
+        if (random == null)
+        {
+            throw new IllegalArgumentException("'random' cannot be null");
+        }
+        if (iterations < 1)
+        {
+            throw new IllegalArgumentException("'iterations' must be > 0");
+        }
+
+        if (candidate.bitLength() == 2)
+        {
+            return MROutput.probablyPrime();
+        }
+        if (!candidate.testBit(0))
+        {
+            return MROutput.provablyCompositeWithFactor(TWO);
+        }
+
+        BigInteger w = candidate;
+        BigInteger wSubOne = candidate.subtract(ONE);
+        BigInteger wSubTwo = candidate.subtract(TWO);
+
+        int a = wSubOne.getLowestSetBit();
+        BigInteger m = wSubOne.shiftRight(a);
+
+        for (int i = 0; i < iterations; ++i)
+        {
+            BigInteger b = BigIntegers.createRandomInRange(TWO, wSubTwo, random);
+            BigInteger g = b.gcd(w);
+
+            if (g.compareTo(ONE) > 0)
+            {
+                return MROutput.provablyCompositeWithFactor(g);
+            }
+
+            BigInteger z = b.modPow(m, w);
+
+            if (z.equals(ONE) || z.equals(wSubOne))
+            {
+                continue;
+            }
+
+            boolean primeToBase = false;
+
+            BigInteger x = z;
+            for (int j = 1; j < a; ++j)
+            {
+                z = z.modPow(TWO, w);
+
+                if (z.equals(wSubOne))
+                {
+                    primeToBase = true;
+                    break;
+                }
+
+                if (z.equals(ONE))
+                {
+                    break;
+                }
+
+                x = z;
+            }
+
+            if (!primeToBase)
+            {
+                if (!z.equals(ONE))
+                {
+                    x = z;
+                    z = z.modPow(TWO, w);
+
+                    if (!z.equals(ONE))
+                    {
+                        x = z;
+                    }
+                }
+
+                g = x.subtract(ONE).gcd(w);
+
+                if (g.compareTo(ONE) > 0)
+                {
+                    return MROutput.provablyCompositeWithFactor(g);
+                }
+
+                return MROutput.provablyCompositeNotPrimePower();
+            }
+        }
+
+        return MROutput.probablyPrime();
+    }
+
+    /**
+     * A fast check for small divisors, up to some implementation-specific limit.
+     *
+     * @param candidate
+     *            the {@link BigInteger} instance to test for division by small factors.
+     *
+     * @return <code>true</code> if the candidate is found to have any small factors,
+     *         <code>false</code> otherwise.
+     */
+    public static boolean hasAnySmallFactors(BigInteger candidate)
+    {
+        checkCandidate(candidate, "candidate");
+
+        return implHasAnySmallFactors(candidate);
+    }
+
+    /**
+     * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test
+     *
+     * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases.
+     *
+     * @param candidate
+     *            the {@link BigInteger} instance to test for primality.
+     * @param random
+     *            the source of randomness to use to choose bases.
+     * @param iterations
+     *            the number of randomly-chosen bases to perform the test for.
+     * @return <code>false</code> if any witness to compositeness is found amongst the chosen bases
+     *         (so <code>candidate</code> is definitely NOT prime), or else <code>true</code>
+     *         (indicating primality with some probability dependent on the number of iterations
+     *         that were performed).
+     */
+    public static boolean isMRProbablePrime(BigInteger candidate, SecureRandom random, int iterations)
+    {
+        checkCandidate(candidate, "candidate");
+
+        if (random == null)
+        {
+            throw new IllegalArgumentException("'random' cannot be null");
+        }
+        if (iterations < 1)
+        {
+            throw new IllegalArgumentException("'iterations' must be > 0");
+        }
+
+        if (candidate.bitLength() == 2)
+        {
+            return true;
+        }
+        if (!candidate.testBit(0))
+        {
+            return false;
+        }
+
+        BigInteger w = candidate;
+        BigInteger wSubOne = candidate.subtract(ONE);
+        BigInteger wSubTwo = candidate.subtract(TWO);
+
+        int a = wSubOne.getLowestSetBit();
+        BigInteger m = wSubOne.shiftRight(a);
+
+        for (int i = 0; i < iterations; ++i)
+        {
+            BigInteger b = BigIntegers.createRandomInRange(TWO, wSubTwo, random);
+
+            if (!implMRProbablePrimeToBase(w, wSubOne, m, a, b))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test (to a fixed base).
+     *
+     * Run a single iteration of the Miller-Rabin algorithm against the specified base.
+     *
+     * @param candidate
+     *            the {@link BigInteger} instance to test for primality.
+     * @param base
+     *            the base value to use for this iteration.
+     * @return <code>false</code> if the specified base is a witness to compositeness (so
+     *         <code>candidate</code> is definitely NOT prime), or else <code>true</code>.
+     */
+    public static boolean isMRProbablePrimeToBase(BigInteger candidate, BigInteger base)
+    {
+        checkCandidate(candidate, "candidate");
+        checkCandidate(base, "base");
+
+        if (base.compareTo(candidate.subtract(ONE)) >= 0)
+        {
+            throw new IllegalArgumentException("'base' must be < ('candidate' - 1)");
+        }
+
+        if (candidate.bitLength() == 2)
+        {
+            return true;
+        }
+
+        BigInteger w = candidate;
+        BigInteger wSubOne = candidate.subtract(ONE);
+
+        int a = wSubOne.getLowestSetBit();
+        BigInteger m = wSubOne.shiftRight(a);
+
+        return implMRProbablePrimeToBase(w, wSubOne, m, a, base);
+    }
+
+    private static void checkCandidate(BigInteger n, String name)
+    {
+        if (n == null || n.signum() < 1 || n.bitLength() < 2)
+        {
+            throw new IllegalArgumentException("'" + name + "' must be non-null and >= 2");
+        }
+    }
+
+    private static boolean implHasAnySmallFactors(BigInteger x)
+    {
+        /*
+         * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders.
+         */
+        int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23;
+        int r = x.mod(BigInteger.valueOf(m)).intValue();
+        if ((r % 2) == 0 || (r % 3) == 0 || (r % 5) == 0 || (r % 7) == 0 || (r % 11) == 0 || (r % 13) == 0
+            || (r % 17) == 0 || (r % 19) == 0 || (r % 23) == 0)
+        {
+            return true;
+        }
+
+        m = 29 * 31 * 37 * 41 * 43;
+        r = x.mod(BigInteger.valueOf(m)).intValue();
+        if ((r % 29) == 0 || (r % 31) == 0 || (r % 37) == 0 || (r % 41) == 0 || (r % 43) == 0)
+        {
+            return true;
+        }
+
+        m = 47 * 53 * 59 * 61 * 67;
+        r = x.mod(BigInteger.valueOf(m)).intValue();
+        if ((r % 47) == 0 || (r % 53) == 0 || (r % 59) == 0 || (r % 61) == 0 || (r % 67) == 0)
+        {
+            return true;
+        }
+
+        m = 71 * 73 * 79 * 83;
+        r = x.mod(BigInteger.valueOf(m)).intValue();
+        if ((r % 71) == 0 || (r % 73) == 0 || (r % 79) == 0 || (r % 83) == 0)
+        {
+            return true;
+        }
+
+        m = 89 * 97 * 101 * 103;
+        r = x.mod(BigInteger.valueOf(m)).intValue();
+        if ((r % 89) == 0 || (r % 97) == 0 || (r % 101) == 0 || (r % 103) == 0)
+        {
+            return true;
+        }
+
+        m = 107 * 109 * 113 * 127;
+        r = x.mod(BigInteger.valueOf(m)).intValue();
+        if ((r % 107) == 0 || (r % 109) == 0 || (r % 113) == 0 || (r % 127) == 0)
+        {
+            return true;
+        }
+
+        m = 131 * 137 * 139 * 149;
+        r = x.mod(BigInteger.valueOf(m)).intValue();
+        if ((r % 131) == 0 || (r % 137) == 0 || (r % 139) == 0 || (r % 149) == 0)
+        {
+            return true;
+        }
+
+        m = 151 * 157 * 163 * 167;
+        r = x.mod(BigInteger.valueOf(m)).intValue();
+        if ((r % 151) == 0 || (r % 157) == 0 || (r % 163) == 0 || (r % 167) == 0)
+        {
+            return true;
+        }
+
+        m = 173 * 179 * 181 * 191;
+        r = x.mod(BigInteger.valueOf(m)).intValue();
+        if ((r % 173) == 0 || (r % 179) == 0 || (r % 181) == 0 || (r % 191) == 0)
+        {
+            return true;
+        }
+
+        m = 193 * 197 * 199 * 211;
+        r = x.mod(BigInteger.valueOf(m)).intValue();
+        if ((r % 193) == 0 || (r % 197) == 0 || (r % 199) == 0 || (r % 211) == 0)
+        {
+            return true;
+        }
+
+        /*
+         * NOTE: Unit tests depend on SMALL_FACTOR_LIMIT matching the
+         * highest small factor tested here.
+         */
+        return false;
+    }
+
+    private static boolean implMRProbablePrimeToBase(BigInteger w, BigInteger wSubOne, BigInteger m, int a, BigInteger b)
+    {
+        BigInteger z = b.modPow(m, w);
+
+        if (z.equals(ONE) || z.equals(wSubOne))
+        {
+            return true;
+        }
+
+        boolean result = false;
+
+        for (int j = 1; j < a; ++j)
+        {
+            z = z.modPow(TWO, w);
+
+            if (z.equals(wSubOne))
+            {
+                result = true;
+                break;
+            }
+
+            if (z.equals(ONE))
+            {
+                return false;
+            }
+        }
+
+        return result;
+    }
+
+    private static STOutput implSTRandomPrime(Digest d, int length, byte[] primeSeed)
+    {
+        int dLen = d.getDigestSize();
+
+        if (length < 33)
+        {
+            int primeGenCounter = 0;
+
+            byte[] c0 = new byte[dLen];
+            byte[] c1 = new byte[dLen];
+
+            for (;;)
+            {
+                hash(d, primeSeed, c0, 0);
+                inc(primeSeed, 1);
+
+                hash(d, primeSeed, c1, 0);
+                inc(primeSeed, 1);
+
+                int c = extract32(c0) ^ extract32(c1);
+                c &= (-1 >>> (32 - length));
+                c |= (1 << (length - 1)) | 1;
+
+                ++primeGenCounter;
+
+                long c64 = c & 0xFFFFFFFFL;
+                if (isPrime32(c64))
+                {
+                    return new STOutput(BigInteger.valueOf(c64), primeSeed, primeGenCounter);
+                }
+
+                if (primeGenCounter > (4 * length))
+                {
+                    throw new IllegalStateException("Too many iterations in Shawe-Taylor Random_Prime Routine");
+                }
+            }
+        }
+
+        STOutput rec = implSTRandomPrime(d, (length + 3) / 2, primeSeed);
+
+        BigInteger c0 = rec.getPrime();
+        primeSeed = rec.getPrimeSeed();
+        int primeGenCounter = rec.getPrimeGenCounter();
+
+        int outlen = 8 * dLen;
+        int iterations = (length - 1) / outlen;
+
+        int oldCounter = primeGenCounter;
+
+        BigInteger x = hashGen(d, primeSeed, iterations + 1);
+        x = x.mod(ONE.shiftLeft(length - 1)).setBit(length - 1);
+
+        BigInteger c0x2 = c0.shiftLeft(1);
+        BigInteger tx2 = x.subtract(ONE).divide(c0x2).add(ONE).shiftLeft(1);
+        int dt = 0;
+
+        BigInteger c = tx2.multiply(c0).add(ONE);
+
+        /*
+         * TODO Since the candidate primes are generated by constant steps ('c0x2'), sieving could
+         * be used here in place of the 'hasAnySmallFactors' approach.
+         */
+        for (;;)
+        {
+            if (c.bitLength() > length)
+            {
+                tx2 = ONE.shiftLeft(length - 1).subtract(ONE).divide(c0x2).add(ONE).shiftLeft(1);
+                c = tx2.multiply(c0).add(ONE);
+            }
+
+            ++primeGenCounter;
+
+            /*
+             * This is an optimization of the original algorithm, using trial division to screen out
+             * many non-primes quickly.
+             * 
+             * NOTE: 'primeSeed' is still incremented as if we performed the full check!
+             */
+            if (!implHasAnySmallFactors(c))
+            {
+                BigInteger a = hashGen(d, primeSeed, iterations + 1);
+                a = a.mod(c.subtract(THREE)).add(TWO);
+
+                tx2 = tx2.add(BigInteger.valueOf(dt));
+                dt = 0;
+
+                BigInteger z = a.modPow(tx2, c);
+
+                if (c.gcd(z.subtract(ONE)).equals(ONE) && z.modPow(c0, c).equals(ONE))
+                {
+                    return new STOutput(c, primeSeed, primeGenCounter);
+                }
+            }
+            else
+            {
+                inc(primeSeed, iterations + 1);
+            }
+
+            if (primeGenCounter >= ((4 * length) + oldCounter))
+            {
+                throw new IllegalStateException("Too many iterations in Shawe-Taylor Random_Prime Routine");
+            }
+
+            dt += 2;
+            c = c.add(c0x2);
+        }
+    }
+
+    private static int extract32(byte[] bs)
+    {
+        int result = 0;
+
+        int count = Math.min(4, bs.length);
+        for (int i = 0; i < count; ++i)
+        {
+            int b = bs[bs.length - (i + 1)] & 0xFF;
+            result |= (b << (8 * i));
+        }
+
+        return result;
+    }
+
+    private static void hash(Digest d, byte[] input, byte[] output, int outPos)
+    {
+        d.update(input, 0, input.length);
+        d.doFinal(output, outPos);
+    }
+
+    private static BigInteger hashGen(Digest d, byte[] seed, int count)
+    {
+        int dLen = d.getDigestSize();
+        int pos = count * dLen;
+        byte[] buf = new byte[pos];
+        for (int i = 0; i < count; ++i)
+        {
+            pos -= dLen;
+            hash(d, seed, buf, pos);
+            inc(seed, 1);
+        }
+        return new BigInteger(1, buf);
+    }
+
+    private static void inc(byte[] seed, int c)
+    {
+        int pos = seed.length;
+        while (c > 0 && --pos >= 0)
+        {
+            c += (seed[pos] & 0xFF);
+            seed[pos] = (byte)c;
+            c >>>= 8;
+        }
+    }
+
+    private static boolean isPrime32(long x)
+    {
+        if (x >>> 32 != 0L)
+        {
+            throw new IllegalArgumentException("Size limit exceeded");
+        }
+
+        /*
+         * Use wheel factorization with 2, 3, 5 to select trial divisors.
+         */
+
+        if (x <= 5L)
+        {
+            return x == 2L || x == 3L || x == 5L;
+        }
+
+        if ((x & 1L) == 0L || (x % 3L) == 0L || (x % 5L) == 0L)
+        {
+            return false;
+        }
+
+        long[] ds = new long[]{ 1L, 7L, 11L, 13L, 17L, 19L, 23L, 29L };
+        long base = 0L;
+        for (int pos = 1;; pos = 0)
+        {
+            /*
+             * Trial division by wheel-selected divisors
+             */
+            while (pos < ds.length)
+            {
+                long d = base + ds[pos];
+                if (x % d == 0L)
+                {
+                    return x < 30L;
+                }
+                ++pos;
+            }
+
+            base += 30L;
+
+            if (base * base >= x)
+            {
+                return true;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/AbstractECMultiplier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/AbstractECMultiplier.java
new file mode 100644
index 0000000..3fbd92c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/AbstractECMultiplier.java
@@ -0,0 +1,35 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class AbstractECMultiplier implements ECMultiplier
+{
+    public ECPoint multiply(ECPoint p, BigInteger k)
+    {
+        int sign = k.signum();
+        if (sign == 0 || p.isInfinity())
+        {
+            return p.getCurve().getInfinity();
+        }
+
+        ECPoint positive = multiplyPositive(p, k.abs());
+        ECPoint result = sign > 0 ? positive : positive.negate();
+
+        /*
+         * Although the various multipliers ought not to produce invalid output under normal
+         * circumstances, a final check here is advised to guard against fault attacks.
+         */
+        return checkResult(result);
+    }
+
+    protected abstract ECPoint multiplyPositive(ECPoint p, BigInteger k);
+
+    protected ECPoint checkResult(ECPoint p)
+    {
+        return ECAlgorithms.implCheckResult(p);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECAlgorithms.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECAlgorithms.java
new file mode 100644
index 0000000..6f819a2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECAlgorithms.java
@@ -0,0 +1,515 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.endo.ECEndomorphism;
+import com.android.internal.org.bouncycastle.math.ec.endo.GLVEndomorphism;
+import com.android.internal.org.bouncycastle.math.field.FiniteField;
+import com.android.internal.org.bouncycastle.math.field.PolynomialExtensionField;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ECAlgorithms
+{
+    public static boolean isF2mCurve(ECCurve c)
+    {
+        return isF2mField(c.getField());
+    }
+
+    public static boolean isF2mField(FiniteField field)
+    {
+        return field.getDimension() > 1 && field.getCharacteristic().equals(ECConstants.TWO)
+            && field instanceof PolynomialExtensionField;
+    }
+
+    public static boolean isFpCurve(ECCurve c)
+    {
+        return isFpField(c.getField());
+    }
+
+    public static boolean isFpField(FiniteField field)
+    {
+        return field.getDimension() == 1;
+    }
+
+    public static ECPoint sumOfMultiplies(ECPoint[] ps, BigInteger[] ks)
+    {
+        if (ps == null || ks == null || ps.length != ks.length || ps.length < 1)
+        {
+            throw new IllegalArgumentException("point and scalar arrays should be non-null, and of equal, non-zero, length");
+        }
+
+        int count = ps.length;
+        switch (count)
+        {
+        case 1:
+            return ps[0].multiply(ks[0]);
+        case 2:
+            return sumOfTwoMultiplies(ps[0], ks[0], ps[1], ks[1]);
+        default:
+            break;
+        }
+
+        ECPoint p = ps[0];
+        ECCurve c = p.getCurve();
+
+        ECPoint[] imported = new ECPoint[count];
+        imported[0] = p;
+        for (int i = 1; i < count; ++i)
+        {
+            imported[i] = importPoint(c, ps[i]);
+        }
+
+        ECEndomorphism endomorphism = c.getEndomorphism();
+        if (endomorphism instanceof GLVEndomorphism)
+        {
+            return implCheckResult(implSumOfMultipliesGLV(imported, ks, (GLVEndomorphism)endomorphism));
+        }
+
+        return implCheckResult(implSumOfMultiplies(imported, ks));
+    }
+
+    public static ECPoint sumOfTwoMultiplies(ECPoint P, BigInteger a,
+        ECPoint Q, BigInteger b)
+    {
+        ECCurve cp = P.getCurve();
+        Q = importPoint(cp, Q);
+
+        // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
+        if (cp instanceof ECCurve.AbstractF2m)
+        {
+            ECCurve.AbstractF2m f2mCurve = (ECCurve.AbstractF2m)cp;
+            if (f2mCurve.isKoblitz())
+            {
+                return implCheckResult(P.multiply(a).add(Q.multiply(b)));
+            }
+        }
+
+        ECEndomorphism endomorphism = cp.getEndomorphism();
+        if (endomorphism instanceof GLVEndomorphism)
+        {
+            return implCheckResult(
+                implSumOfMultipliesGLV(new ECPoint[]{ P, Q }, new BigInteger[]{ a, b }, (GLVEndomorphism)endomorphism));
+        }
+
+        return implCheckResult(implShamirsTrickWNaf(P, a, Q, b));
+    }
+
+    /*
+     * "Shamir's Trick", originally due to E. G. Straus
+     * (Addition chains of vectors. American Mathematical Monthly,
+     * 71(7):806-808, Aug./Sept. 1964)
+     * <pre>
+     * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
+     * and scalar l = (lm?, ... , l1, l0).
+     * Output: R = k * P + l * Q.
+     * 1: Z <- P + Q
+     * 2: R <- O
+     * 3: for i from m-1 down to 0 do
+     * 4:        R <- R + R        {point doubling}
+     * 5:        if (ki = 1) and (li = 0) then R <- R + P end if
+     * 6:        if (ki = 0) and (li = 1) then R <- R + Q end if
+     * 7:        if (ki = 1) and (li = 1) then R <- R + Z end if
+     * 8: end for
+     * 9: return R
+     * </pre>
+     */
+    public static ECPoint shamirsTrick(ECPoint P, BigInteger k,
+        ECPoint Q, BigInteger l)
+    {
+        ECCurve cp = P.getCurve();
+        Q = importPoint(cp, Q);
+
+        return implCheckResult(implShamirsTrickJsf(P, k, Q, l));
+    }
+
+    public static ECPoint importPoint(ECCurve c, ECPoint p)
+    {
+        ECCurve cp = p.getCurve();
+        if (!c.equals(cp))
+        {
+            throw new IllegalArgumentException("Point must be on the same curve");
+        }
+        return c.importPoint(p);
+    }
+
+    public static void montgomeryTrick(ECFieldElement[] zs, int off, int len)
+    {
+        montgomeryTrick(zs, off, len, null);
+    }
+
+    public static void montgomeryTrick(ECFieldElement[] zs, int off, int len, ECFieldElement scale)
+    {
+        /*
+         * Uses the "Montgomery Trick" to invert many field elements, with only a single actual
+         * field inversion. See e.g. the paper:
+         * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick"
+         * by Katsuyuki Okeya, Kouichi Sakurai.
+         */
+
+        ECFieldElement[] c = new ECFieldElement[len];
+        c[0] = zs[off];
+
+        int i = 0;
+        while (++i < len)
+        {
+            c[i] = c[i - 1].multiply(zs[off + i]);
+        }
+
+        --i;
+
+        if (scale != null)
+        {
+            c[i] = c[i].multiply(scale);
+        }
+
+        ECFieldElement u = c[i].invert();
+
+        while (i > 0)
+        {
+            int j = off + i--;
+            ECFieldElement tmp = zs[j];
+            zs[j] = c[i].multiply(u);
+            u = u.multiply(tmp);
+        }
+
+        zs[off] = u;
+    }
+
+    /**
+     * Simple shift-and-add multiplication. Serves as reference implementation
+     * to verify (possibly faster) implementations, and for very small scalars.
+     * 
+     * @param p
+     *            The point to multiply.
+     * @param k
+     *            The multiplier.
+     * @return The result of the point multiplication <code>kP</code>.
+     */
+    public static ECPoint referenceMultiply(ECPoint p, BigInteger k)
+    {
+        BigInteger x = k.abs();
+        ECPoint q = p.getCurve().getInfinity();
+        int t = x.bitLength();
+        if (t > 0)
+        {
+            if (x.testBit(0))
+            {
+                q = p;
+            }
+            for (int i = 1; i < t; i++)
+            {
+                p = p.twice();
+                if (x.testBit(i))
+                {
+                    q = q.add(p);
+                }
+            }
+        }
+        return k.signum() < 0 ? q.negate() : q;
+    }
+
+    public static ECPoint validatePoint(ECPoint p)
+    {
+        if (!p.isValid())
+        {
+            throw new IllegalStateException("Invalid point");
+        }
+
+        return p;
+    }
+
+    public static ECPoint cleanPoint(ECCurve c, ECPoint p)
+    {
+        ECCurve cp = p.getCurve();
+        if (!c.equals(cp))
+        {
+            throw new IllegalArgumentException("Point must be on the same curve");
+        }
+
+        return c.decodePoint(p.getEncoded(false));
+    }
+
+    static ECPoint implCheckResult(ECPoint p)
+    {
+        if (!p.isValidPartial())
+        {
+            throw new IllegalStateException("Invalid result");
+        }
+
+        return p;
+    }
+
+    static ECPoint implShamirsTrickJsf(ECPoint P, BigInteger k,
+        ECPoint Q, BigInteger l)
+    {
+        ECCurve curve = P.getCurve();
+        ECPoint infinity = curve.getInfinity();
+
+        // TODO conjugate co-Z addition (ZADDC) can return both of these
+        ECPoint PaddQ = P.add(Q);
+        ECPoint PsubQ = P.subtract(Q);
+
+        ECPoint[] points = new ECPoint[]{ Q, PsubQ, P, PaddQ };
+        curve.normalizeAll(points);
+
+        ECPoint[] table = new ECPoint[] {
+            points[3].negate(), points[2].negate(), points[1].negate(),
+            points[0].negate(), infinity, points[0],
+            points[1], points[2], points[3] };
+
+        byte[] jsf = WNafUtil.generateJSF(k, l);
+
+        ECPoint R = infinity;
+
+        int i = jsf.length;
+        while (--i >= 0)
+        {
+            int jsfi = jsf[i];
+
+            // NOTE: The shifting ensures the sign is extended correctly
+            int kDigit = ((jsfi << 24) >> 28), lDigit = ((jsfi << 28) >> 28);
+
+            int index = 4 + (kDigit * 3) + lDigit;
+            R = R.twicePlus(table[index]);
+        }
+
+        return R;
+    }
+
+    static ECPoint implShamirsTrickWNaf(ECPoint P, BigInteger k,
+        ECPoint Q, BigInteger l)
+    {
+        boolean negK = k.signum() < 0, negL = l.signum() < 0;
+
+        k = k.abs();
+        l = l.abs();
+
+        int widthP = Math.max(2, Math.min(16, WNafUtil.getWindowSize(k.bitLength())));
+        int widthQ = Math.max(2, Math.min(16, WNafUtil.getWindowSize(l.bitLength())));
+
+        WNafPreCompInfo infoP = WNafUtil.precompute(P, widthP, true);
+        WNafPreCompInfo infoQ = WNafUtil.precompute(Q, widthQ, true);
+
+        ECPoint[] preCompP = negK ? infoP.getPreCompNeg() : infoP.getPreComp();
+        ECPoint[] preCompQ = negL ? infoQ.getPreCompNeg() : infoQ.getPreComp();
+        ECPoint[] preCompNegP = negK ? infoP.getPreComp() : infoP.getPreCompNeg();
+        ECPoint[] preCompNegQ = negL ? infoQ.getPreComp() : infoQ.getPreCompNeg();
+
+        byte[] wnafP = WNafUtil.generateWindowNaf(widthP, k);
+        byte[] wnafQ = WNafUtil.generateWindowNaf(widthQ, l);
+
+        return implShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
+    }
+
+    static ECPoint implShamirsTrickWNaf(ECPoint P, BigInteger k, ECPointMap pointMapQ, BigInteger l)
+    {
+        boolean negK = k.signum() < 0, negL = l.signum() < 0;
+
+        k = k.abs();
+        l = l.abs();
+
+        int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(Math.max(k.bitLength(), l.bitLength()))));
+
+        ECPoint Q = WNafUtil.mapPointWithPrecomp(P, width, true, pointMapQ);
+        WNafPreCompInfo infoP = WNafUtil.getWNafPreCompInfo(P);
+        WNafPreCompInfo infoQ = WNafUtil.getWNafPreCompInfo(Q);
+
+        ECPoint[] preCompP = negK ? infoP.getPreCompNeg() : infoP.getPreComp();
+        ECPoint[] preCompQ = negL ? infoQ.getPreCompNeg() : infoQ.getPreComp();
+        ECPoint[] preCompNegP = negK ? infoP.getPreComp() : infoP.getPreCompNeg();
+        ECPoint[] preCompNegQ = negL ? infoQ.getPreComp() : infoQ.getPreCompNeg();
+
+        byte[] wnafP = WNafUtil.generateWindowNaf(width, k);
+        byte[] wnafQ = WNafUtil.generateWindowNaf(width, l);
+
+        return implShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
+    }
+
+    private static ECPoint implShamirsTrickWNaf(ECPoint[] preCompP, ECPoint[] preCompNegP, byte[] wnafP,
+        ECPoint[] preCompQ, ECPoint[] preCompNegQ, byte[] wnafQ)
+    {
+        int len = Math.max(wnafP.length, wnafQ.length);
+
+        ECCurve curve = preCompP[0].getCurve();
+        ECPoint infinity = curve.getInfinity();
+
+        ECPoint R = infinity;
+        int zeroes = 0;
+
+        for (int i = len - 1; i >= 0; --i)
+        {
+            int wiP = i < wnafP.length ? wnafP[i] : 0;
+            int wiQ = i < wnafQ.length ? wnafQ[i] : 0;
+
+            if ((wiP | wiQ) == 0)
+            {
+                ++zeroes;
+                continue;
+            }
+
+            ECPoint r = infinity;
+            if (wiP != 0)
+            {
+                int nP = Math.abs(wiP);
+                ECPoint[] tableP = wiP < 0 ? preCompNegP : preCompP;
+                r = r.add(tableP[nP >>> 1]);
+            }
+            if (wiQ != 0)
+            {
+                int nQ = Math.abs(wiQ);
+                ECPoint[] tableQ = wiQ < 0 ? preCompNegQ : preCompQ;
+                r = r.add(tableQ[nQ >>> 1]);
+            }
+
+            if (zeroes > 0)
+            {
+                R = R.timesPow2(zeroes);
+                zeroes = 0;
+            }
+
+            R = R.twicePlus(r);
+        }
+
+        if (zeroes > 0)
+        {
+            R = R.timesPow2(zeroes);
+        }
+
+        return R;
+    }
+
+    static ECPoint implSumOfMultiplies(ECPoint[] ps, BigInteger[] ks)
+    {
+        int count = ps.length;
+        boolean[] negs = new boolean[count];
+        WNafPreCompInfo[] infos = new WNafPreCompInfo[count];
+        byte[][] wnafs = new byte[count][];
+
+        for (int i = 0; i < count; ++i)
+        {
+            BigInteger ki = ks[i]; negs[i] = ki.signum() < 0; ki = ki.abs();
+
+            int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(ki.bitLength())));
+            infos[i] = WNafUtil.precompute(ps[i], width, true);
+            wnafs[i] = WNafUtil.generateWindowNaf(width, ki);
+        }
+
+        return implSumOfMultiplies(negs, infos, wnafs);
+    }
+
+    static ECPoint implSumOfMultipliesGLV(ECPoint[] ps, BigInteger[] ks, GLVEndomorphism glvEndomorphism)
+    {
+        BigInteger n = ps[0].getCurve().getOrder();
+
+        int len = ps.length;
+
+        BigInteger[] abs = new BigInteger[len << 1];
+        for (int i = 0, j = 0; i < len; ++i)
+        {
+            BigInteger[] ab = glvEndomorphism.decomposeScalar(ks[i].mod(n));
+            abs[j++] = ab[0];
+            abs[j++] = ab[1];
+        }
+
+        ECPointMap pointMap = glvEndomorphism.getPointMap();
+        if (glvEndomorphism.hasEfficientPointMap())
+        {
+            return ECAlgorithms.implSumOfMultiplies(ps, pointMap, abs);
+        }
+
+        ECPoint[] pqs = new ECPoint[len << 1];
+        for (int i = 0, j = 0; i < len; ++i)
+        {
+            ECPoint p = ps[i], q = pointMap.map(p);
+            pqs[j++] = p;
+            pqs[j++] = q;
+        }
+        
+        return ECAlgorithms.implSumOfMultiplies(pqs, abs);
+
+    }
+
+    static ECPoint implSumOfMultiplies(ECPoint[] ps, ECPointMap pointMap, BigInteger[] ks)
+    {
+        int halfCount = ps.length, fullCount = halfCount << 1;
+
+        boolean[] negs = new boolean[fullCount];
+        WNafPreCompInfo[] infos = new WNafPreCompInfo[fullCount];
+        byte[][] wnafs = new byte[fullCount][];
+
+        for (int i = 0; i < halfCount; ++i)
+        {
+            int j0 = i << 1, j1 = j0 + 1;
+
+            BigInteger kj0 = ks[j0]; negs[j0] = kj0.signum() < 0; kj0 = kj0.abs();
+            BigInteger kj1 = ks[j1]; negs[j1] = kj1.signum() < 0; kj1 = kj1.abs();
+
+            int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(Math.max(kj0.bitLength(), kj1.bitLength()))));
+
+            ECPoint P = ps[i], Q = WNafUtil.mapPointWithPrecomp(P, width, true, pointMap);
+            infos[j0] = WNafUtil.getWNafPreCompInfo(P);
+            infos[j1] = WNafUtil.getWNafPreCompInfo(Q);
+            wnafs[j0] = WNafUtil.generateWindowNaf(width, kj0);
+            wnafs[j1] = WNafUtil.generateWindowNaf(width, kj1);
+        }
+
+        return implSumOfMultiplies(negs, infos, wnafs);
+    }
+
+    private static ECPoint implSumOfMultiplies(boolean[] negs, WNafPreCompInfo[] infos, byte[][] wnafs)
+    {
+        int len = 0, count = wnafs.length;
+        for (int i = 0; i < count; ++i)
+        {
+            len = Math.max(len, wnafs[i].length);
+        }
+
+        ECCurve curve = infos[0].getPreComp()[0].getCurve();
+        ECPoint infinity = curve.getInfinity();
+
+        ECPoint R = infinity;
+        int zeroes = 0;
+
+        for (int i = len - 1; i >= 0; --i)
+        {
+            ECPoint r = infinity;
+
+            for (int j = 0; j < count; ++j)
+            {
+                byte[] wnaf = wnafs[j];
+                int wi = i < wnaf.length ? wnaf[i] : 0;
+                if (wi != 0)
+                {
+                    int n = Math.abs(wi);
+                    WNafPreCompInfo info = infos[j];
+                    ECPoint[] table = (wi < 0 == negs[j]) ? info.getPreComp() : info.getPreCompNeg();
+                    r = r.add(table[n >>> 1]);
+                }
+            }
+
+            if (r == infinity)
+            {
+                ++zeroes;
+                continue;
+            }
+
+            if (zeroes > 0)
+            {
+                R = R.timesPow2(zeroes);
+                zeroes = 0;
+            }
+
+            R = R.twicePlus(r);
+        }
+
+        if (zeroes > 0)
+        {
+            R = R.timesPow2(zeroes);
+        }
+
+        return R;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECConstants.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECConstants.java
new file mode 100644
index 0000000..cd40157
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECConstants.java
@@ -0,0 +1,17 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ECConstants
+{
+    public static final BigInteger ZERO = BigInteger.valueOf(0);
+    public static final BigInteger ONE = BigInteger.valueOf(1);
+    public static final BigInteger TWO = BigInteger.valueOf(2);
+    public static final BigInteger THREE = BigInteger.valueOf(3);
+    public static final BigInteger FOUR = BigInteger.valueOf(4);
+    public static final BigInteger EIGHT = BigInteger.valueOf(8);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECCurve.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECCurve.java
new file mode 100644
index 0000000..176a985
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECCurve.java
@@ -0,0 +1,1296 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+import java.util.Hashtable;
+import java.util.Random;
+
+import com.android.internal.org.bouncycastle.math.ec.endo.ECEndomorphism;
+import com.android.internal.org.bouncycastle.math.ec.endo.GLVEndomorphism;
+import com.android.internal.org.bouncycastle.math.field.FiniteField;
+import com.android.internal.org.bouncycastle.math.field.FiniteFields;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+import com.android.internal.org.bouncycastle.util.Integers;
+
+/**
+ * base class for an elliptic curve
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ECCurve
+{
+    public static final int COORD_AFFINE = 0;
+    public static final int COORD_HOMOGENEOUS = 1;
+    public static final int COORD_JACOBIAN = 2;
+    public static final int COORD_JACOBIAN_CHUDNOVSKY = 3;
+    public static final int COORD_JACOBIAN_MODIFIED = 4;
+    public static final int COORD_LAMBDA_AFFINE = 5;
+    public static final int COORD_LAMBDA_PROJECTIVE = 6;
+    public static final int COORD_SKEWED = 7;
+
+    public static int[] getAllCoordinateSystems()
+    {
+        return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY,
+            COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED };
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public class Config
+    {
+        protected int coord;
+        protected ECEndomorphism endomorphism;
+        protected ECMultiplier multiplier;
+
+        Config(int coord, ECEndomorphism endomorphism, ECMultiplier multiplier)
+        {
+            this.coord = coord;
+            this.endomorphism = endomorphism;
+            this.multiplier = multiplier;
+        }
+
+        public Config setCoordinateSystem(int coord)
+        {
+            this.coord = coord;
+            return this;
+        }
+
+        public Config setEndomorphism(ECEndomorphism endomorphism)
+        {
+            this.endomorphism = endomorphism;
+            return this;
+        }
+
+        public Config setMultiplier(ECMultiplier multiplier)
+        {
+            this.multiplier = multiplier;
+            return this;
+        }
+
+        public ECCurve create()
+        {
+            if (!supportsCoordinateSystem(coord))
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+
+            ECCurve c = cloneCurve();
+            if (c == ECCurve.this)
+            {
+                throw new IllegalStateException("implementation returned current curve");
+            }
+
+            // NOTE: Synchronization added to keep FindBugs™ happy
+            synchronized (c)
+            {
+                c.coord = coord;
+                c.endomorphism = endomorphism;
+                c.multiplier = multiplier;
+            }
+
+            return c;
+        }
+    }
+
+    protected FiniteField field;
+    protected ECFieldElement a, b;
+    protected BigInteger order, cofactor;
+
+    protected int coord = COORD_AFFINE;
+    protected ECEndomorphism endomorphism = null;
+    protected ECMultiplier multiplier = null;
+
+    protected ECCurve(FiniteField field)
+    {
+        this.field = field;
+    }
+
+    public abstract int getFieldSize();
+
+    public abstract ECFieldElement fromBigInteger(BigInteger x);
+
+    public abstract boolean isValidFieldElement(BigInteger x);
+
+    public synchronized Config configure()
+    {
+        return new Config(this.coord, this.endomorphism, this.multiplier);
+    }
+
+    public ECPoint validatePoint(BigInteger x, BigInteger y)
+    {
+        ECPoint p = createPoint(x, y);
+        if (!p.isValid())
+        {
+            throw new IllegalArgumentException("Invalid point coordinates");
+        }
+        return p;
+    }
+
+    /**
+     * @deprecated per-point compression property will be removed, use {@link #validatePoint(BigInteger, BigInteger)}
+     * and refer {@link ECPoint#getEncoded(boolean)}
+     */
+    public ECPoint validatePoint(BigInteger x, BigInteger y, boolean withCompression)
+    {
+        ECPoint p = createPoint(x, y, withCompression);
+        if (!p.isValid())
+        {
+            throw new IllegalArgumentException("Invalid point coordinates");
+        }
+        return p;
+    }
+
+    public ECPoint createPoint(BigInteger x, BigInteger y)
+    {
+        return createPoint(x, y, false);
+    }
+
+    /**
+     * @deprecated per-point compression property will be removed, use {@link #createPoint(BigInteger, BigInteger)}
+     * and refer {@link ECPoint#getEncoded(boolean)}
+     */
+    public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+    {
+        return createRawPoint(fromBigInteger(x), fromBigInteger(y), withCompression);
+    }
+
+    protected abstract ECCurve cloneCurve();
+
+    protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression);
+
+    protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression);
+
+    protected ECMultiplier createDefaultMultiplier()
+    {
+        if (endomorphism instanceof GLVEndomorphism)
+        {
+            return new GLVMultiplier(this, (GLVEndomorphism)endomorphism);
+        }
+
+        return new WNafL2RMultiplier();
+    }
+
+    public boolean supportsCoordinateSystem(int coord)
+    {
+        return coord == COORD_AFFINE;
+    }
+
+    public PreCompInfo getPreCompInfo(ECPoint point, String name)
+    {
+        checkPoint(point);
+
+        Hashtable table;
+        synchronized (point)
+        {
+            table = point.preCompTable;
+        }
+
+        if (null == table)
+        {
+            return null;
+        }
+
+        synchronized (table)
+        {
+            return (PreCompInfo)table.get(name);
+        }
+    }
+
+    /**
+     * Compute a <code>PreCompInfo</code> for a point on this curve, under a given name. Used by
+     * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use
+     * by subsequent multiplication.
+     * 
+     * @param point
+     *            The <code>ECPoint</code> to store precomputations for.
+     * @param name
+     *            A <code>String</code> used to index precomputations of different types.
+     * @param callback
+     *            Called to calculate the <code>PreCompInfo</code>.
+     */
+    public PreCompInfo precompute(ECPoint point, String name, PreCompCallback callback)
+    {
+        checkPoint(point);
+
+        Hashtable table;
+        synchronized (point)
+        {
+            table = point.preCompTable;
+            if (null == table)
+            {
+                point.preCompTable = table = new Hashtable(4);
+            }
+        }
+
+        synchronized (table)
+        {
+            PreCompInfo existing = (PreCompInfo)table.get(name);
+            PreCompInfo result = callback.precompute(existing);
+
+            if (result != existing)
+            {
+                table.put(name, result);
+            }
+
+            return result;
+        }
+    }
+
+    public ECPoint importPoint(ECPoint p)
+    {
+        if (this == p.getCurve())
+        {
+            return p;
+        }
+        if (p.isInfinity())
+        {
+            return getInfinity();
+        }
+
+        // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
+        p = p.normalize();
+
+        return createPoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger(), p.withCompression);
+    }
+
+    /**
+     * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+     * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
+     * than one point is to be normalized, this method will generally be more efficient than
+     * normalizing each point separately.
+     * 
+     * @param points
+     *            An array of points that will be updated in place with their normalized versions,
+     *            where necessary
+     */
+    public void normalizeAll(ECPoint[] points)
+    {
+        normalizeAll(points, 0, points.length, null);
+    }
+
+    /**
+     * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+     * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
+     * than one point is to be normalized, this method will generally be more efficient than
+     * normalizing each point separately. An (optional) z-scaling factor can be applied; effectively
+     * each z coordinate is scaled by this value prior to normalization (but only one
+     * actual multiplication is needed).
+     * 
+     * @param points
+     *            An array of points that will be updated in place with their normalized versions,
+     *            where necessary
+     * @param off
+     *            The start of the range of points to normalize
+     * @param len
+     *            The length of the range of points to normalize
+     * @param iso
+     *            The (optional) z-scaling factor - can be null
+     */
+    public void normalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso)
+    {
+        checkPoints(points, off, len);
+
+        switch (this.getCoordinateSystem())
+        {
+        case ECCurve.COORD_AFFINE:
+        case ECCurve.COORD_LAMBDA_AFFINE:
+        {
+            if (iso != null)
+            {
+                throw new IllegalArgumentException("'iso' not valid for affine coordinates");
+            }
+            return;
+        }
+        }
+
+        /*
+         * Figure out which of the points actually need to be normalized
+         */
+        ECFieldElement[] zs = new ECFieldElement[len];
+        int[] indices = new int[len];
+        int count = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            ECPoint p = points[off + i];
+            if (null != p && (iso != null || !p.isNormalized()))
+            {
+                zs[count] = p.getZCoord(0);
+                indices[count++] = off + i;
+            }
+        }
+
+        if (count == 0)
+        {
+            return;
+        }
+
+        ECAlgorithms.montgomeryTrick(zs, 0, count, iso);
+
+        for (int j = 0; j < count; ++j)
+        {
+            int index = indices[j];
+            points[index] = points[index].normalize(zs[j]);
+        }
+    }
+
+    public abstract ECPoint getInfinity();
+
+    public FiniteField getField()
+    {
+        return field;
+    }
+
+    public ECFieldElement getA()
+    {
+        return a;
+    }
+
+    public ECFieldElement getB()
+    {
+        return b;
+    }
+
+    public BigInteger getOrder()
+    {
+        return order;
+    }
+
+    public BigInteger getCofactor()
+    {
+        return cofactor;
+    }
+
+    public int getCoordinateSystem()
+    {
+        return coord;
+    }
+
+    protected abstract ECPoint decompressPoint(int yTilde, BigInteger X1);
+
+    public ECEndomorphism getEndomorphism()
+    {
+        return endomorphism;
+    }
+
+    /**
+     * Sets the default <code>ECMultiplier</code>, unless already set. 
+     */
+    public synchronized ECMultiplier getMultiplier()
+    {
+        if (this.multiplier == null)
+        {
+            this.multiplier = createDefaultMultiplier();
+        }
+        return this.multiplier;
+    }
+
+    /**
+     * Decode a point on this curve from its ASN.1 encoding. The different
+     * encodings are taken account of, including point compression for
+     * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
+     * @return The decoded point.
+     */
+    public ECPoint decodePoint(byte[] encoded)
+    {
+        ECPoint p = null;
+        int expectedLength = (getFieldSize() + 7) / 8;
+
+        byte type = encoded[0];
+        switch (type)
+        {
+        case 0x00: // infinity
+        {
+            if (encoded.length != 1)
+            {
+                throw new IllegalArgumentException("Incorrect length for infinity encoding");
+            }
+
+            p = getInfinity();
+            break;
+        }
+        case 0x02: // compressed
+        case 0x03: // compressed
+        {
+            if (encoded.length != (expectedLength + 1))
+            {
+                throw new IllegalArgumentException("Incorrect length for compressed encoding");
+            }
+
+            int yTilde = type & 1;
+            BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
+
+            p = decompressPoint(yTilde, X);
+            if (!p.implIsValid(true, true))
+            {
+                throw new IllegalArgumentException("Invalid point");
+            }
+
+            break;
+        }
+        case 0x04: // uncompressed
+        {
+            if (encoded.length != (2 * expectedLength + 1))
+            {
+                throw new IllegalArgumentException("Incorrect length for uncompressed encoding");
+            }
+
+            BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
+            BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength);
+
+            p = validatePoint(X, Y);
+            break;
+        }
+        case 0x06: // hybrid
+        case 0x07: // hybrid
+        {
+            if (encoded.length != (2 * expectedLength + 1))
+            {
+                throw new IllegalArgumentException("Incorrect length for hybrid encoding");
+            }
+
+            BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
+            BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength);
+
+            if (Y.testBit(0) != (type == 0x07))
+            {
+                throw new IllegalArgumentException("Inconsistent Y coordinate in hybrid encoding");
+            }
+
+            p = validatePoint(X, Y);
+            break;
+        }
+        default:
+            throw new IllegalArgumentException("Invalid point encoding 0x" + Integer.toString(type, 16));
+        }
+
+        if (type != 0x00 && p.isInfinity())
+        {
+            throw new IllegalArgumentException("Invalid infinity encoding");
+        }
+
+        return p;
+    }
+
+    /**
+     * Create a cache-safe lookup table for the specified sequence of points. All the points MUST
+     * belong to this {@link ECCurve} instance, and MUST already be normalized.
+     */
+    public ECLookupTable createCacheSafeLookupTable(final ECPoint[] points, int off, final int len)
+    {
+        final int FE_BYTES = (getFieldSize() + 7) >>> 3;
+
+        final byte[] table = new byte[len * FE_BYTES * 2];
+        {
+            int pos = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                ECPoint p = points[off + i];
+                byte[] px = p.getRawXCoord().toBigInteger().toByteArray();
+                byte[] py = p.getRawYCoord().toBigInteger().toByteArray();
+
+                int pxStart = px.length > FE_BYTES ? 1 : 0, pxLen = px.length - pxStart;
+                int pyStart = py.length > FE_BYTES ? 1 : 0, pyLen = py.length - pyStart;
+
+                System.arraycopy(px, pxStart, table, pos + FE_BYTES - pxLen, pxLen); pos += FE_BYTES;
+                System.arraycopy(py, pyStart, table, pos + FE_BYTES - pyLen, pyLen); pos += FE_BYTES;
+            }
+        }
+
+        return new ECLookupTable()
+        {
+            public int getSize()
+            {
+                return len;
+            }
+
+            public ECPoint lookup(int index)
+            {
+                byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES];
+                int pos = 0;
+
+                for (int i = 0; i < len; ++i)
+                {
+                    int MASK = ((i ^ index) - 1) >> 31;
+
+                    for (int j = 0; j < FE_BYTES; ++j)
+                    {
+                        x[j] ^= table[pos + j] & MASK;
+                        y[j] ^= table[pos + FE_BYTES + j] & MASK;
+                    }
+
+                    pos += (FE_BYTES * 2);
+                }
+
+                return createRawPoint(fromBigInteger(new BigInteger(1, x)), fromBigInteger(new BigInteger(1, y)), false);
+            }
+        };
+    }
+
+    protected void checkPoint(ECPoint point)
+    {
+        if (null == point || (this != point.getCurve()))
+        {
+            throw new IllegalArgumentException("'point' must be non-null and on this curve");
+        }
+    }
+
+    protected void checkPoints(ECPoint[] points)
+    {
+        checkPoints(points, 0, points.length);
+    }
+
+    protected void checkPoints(ECPoint[] points, int off, int len)
+    {
+        if (points == null)
+        {
+            throw new IllegalArgumentException("'points' cannot be null");
+        }
+        if (off < 0 || len < 0 || (off > (points.length - len)))
+        {
+            throw new IllegalArgumentException("invalid range specified for 'points'");
+        }
+
+        for (int i = 0; i < len; ++i)
+        {
+            ECPoint point = points[off + i];
+            if (null != point && this != point.getCurve())
+            {
+                throw new IllegalArgumentException("'points' entries must be null or on this curve");
+            }
+        }
+    }
+
+    public boolean equals(ECCurve other)
+    {
+        return this == other
+            || (null != other
+                && getField().equals(other.getField())
+                && getA().toBigInteger().equals(other.getA().toBigInteger())
+                && getB().toBigInteger().equals(other.getB().toBigInteger()));
+    }
+
+    public boolean equals(Object obj) 
+    {
+        return this == obj || (obj instanceof ECCurve && equals((ECCurve)obj));
+    }
+
+    public int hashCode() 
+    {
+        return getField().hashCode()
+            ^ Integers.rotateLeft(getA().toBigInteger().hashCode(), 8)
+            ^ Integers.rotateLeft(getB().toBigInteger().hashCode(), 16);
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static abstract class AbstractFp extends ECCurve
+    {
+        protected AbstractFp(BigInteger q)
+        {
+            super(FiniteFields.getPrimeField(q));
+        }
+
+        public boolean isValidFieldElement(BigInteger x)
+        {
+            return x != null && x.signum() >= 0 && x.compareTo(this.getField().getCharacteristic()) < 0;
+        }
+
+        protected ECPoint decompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = this.fromBigInteger(X1);
+            ECFieldElement rhs = x.square().add(this.a).multiply(x).add(this.b);
+            ECFieldElement y = rhs.sqrt();
+
+            /*
+             * If y is not a square, then we haven't got a point on the curve
+             */
+            if (y == null)
+            {
+                throw new IllegalArgumentException("Invalid point compression");
+            }
+
+            if (y.testBitZero() != (yTilde == 1))
+            {
+                // Use the other root
+                y = y.negate();
+            }
+
+            return this.createRawPoint(x, y, true);
+        }
+    }
+
+    /**
+     * Elliptic curve over Fp
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Fp extends AbstractFp
+    {
+        private static final int FP_DEFAULT_COORDS = ECCurve.COORD_JACOBIAN_MODIFIED;
+
+        BigInteger q, r;
+        ECPoint.Fp infinity;
+
+        /**
+         * @deprecated use constructor taking order/cofactor
+         */
+        public Fp(BigInteger q, BigInteger a, BigInteger b)
+        {
+            this(q, a, b, null, null);
+        }
+
+        public Fp(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
+        {
+            super(q);
+
+            this.q = q;
+            this.r = ECFieldElement.Fp.calculateResidue(q);
+            this.infinity = new ECPoint.Fp(this, null, null, false);
+
+            this.a = fromBigInteger(a);
+            this.b = fromBigInteger(b);
+            this.order = order;
+            this.cofactor = cofactor;
+            this.coord = FP_DEFAULT_COORDS;
+        }
+
+        /**
+         * @deprecated use constructor taking order/cofactor
+         */
+        protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
+        {
+            this(q, r, a, b, null, null);
+        }
+
+        protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
+        {
+            super(q);
+
+            this.q = q;
+            this.r = r;
+            this.infinity = new ECPoint.Fp(this, null, null, false);
+
+            this.a = a;
+            this.b = b;
+            this.order = order;
+            this.cofactor = cofactor;
+            this.coord = FP_DEFAULT_COORDS;
+        }
+
+        protected ECCurve cloneCurve()
+        {
+            return new Fp(this.q, this.r, this.a, this.b, this.order, this.cofactor);
+        }
+
+        public boolean supportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            case ECCurve.COORD_HOMOGENEOUS:
+            case ECCurve.COORD_JACOBIAN:
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public BigInteger getQ()
+        {
+            return q;
+        }
+
+        public int getFieldSize()
+        {
+            return q.bitLength();
+        }
+
+        public ECFieldElement fromBigInteger(BigInteger x)
+        {
+            return new ECFieldElement.Fp(this.q, this.r, x);
+        }
+
+        protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+        {
+            return new ECPoint.Fp(this, x, y, withCompression);
+        }
+
+        protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+        {
+            return new ECPoint.Fp(this, x, y, zs, withCompression);
+        }
+
+        public ECPoint importPoint(ECPoint p)
+        {
+            if (this != p.getCurve() && this.getCoordinateSystem() == ECCurve.COORD_JACOBIAN && !p.isInfinity())
+            {
+                switch (p.getCurve().getCoordinateSystem())
+                {
+                case ECCurve.COORD_JACOBIAN:
+                case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+                case ECCurve.COORD_JACOBIAN_MODIFIED:
+                    return new ECPoint.Fp(this,
+                        fromBigInteger(p.x.toBigInteger()),
+                        fromBigInteger(p.y.toBigInteger()),
+                        new ECFieldElement[]{ fromBigInteger(p.zs[0].toBigInteger()) },
+                        p.withCompression);
+                default:
+                    break;
+                }
+            }
+
+            return super.importPoint(p);
+        }
+
+        public ECPoint getInfinity()
+        {
+            return infinity;
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static abstract class AbstractF2m extends ECCurve
+    {
+        public static BigInteger inverse(int m, int[] ks, BigInteger x)
+        {
+            return new LongArray(x).modInverse(m, ks).toBigInteger();
+        }
+
+        /**
+         * The auxiliary values <code>s<sub>0</sub></code> and
+         * <code>s<sub>1</sub></code> used for partial modular reduction for
+         * Koblitz curves.
+         */
+        private BigInteger[] si = null;
+
+        private static FiniteField buildField(int m, int k1, int k2, int k3)
+        {
+            if (k1 == 0)
+            {
+                throw new IllegalArgumentException("k1 must be > 0");
+            }
+
+            if (k2 == 0)
+            {
+                if (k3 != 0)
+                {
+                    throw new IllegalArgumentException("k3 must be 0 if k2 == 0");
+                }
+
+                return FiniteFields.getBinaryExtensionField(new int[]{ 0, k1, m });
+            }
+
+            if (k2 <= k1)
+            {
+                throw new IllegalArgumentException("k2 must be > k1");
+            }
+
+            if (k3 <= k2)
+            {
+                throw new IllegalArgumentException("k3 must be > k2");
+            }
+
+            return FiniteFields.getBinaryExtensionField(new int[]{ 0, k1, k2, k3, m });
+        }
+
+        protected AbstractF2m(int m, int k1, int k2, int k3)
+        {
+            super(buildField(m, k1, k2, k3));
+        }
+
+        public boolean isValidFieldElement(BigInteger x)
+        {
+            return x != null && x.signum() >= 0 && x.bitLength() <= this.getFieldSize();
+        }
+
+        public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+        {
+            ECFieldElement X = this.fromBigInteger(x), Y = this.fromBigInteger(y);
+
+            int coord = this.getCoordinateSystem();
+
+            switch (coord)
+            {
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                if (X.isZero())
+                {
+                    if (!Y.square().equals(this.getB()))
+                    {
+                        throw new IllegalArgumentException();
+                    }
+                }
+                /*
+                 * NOTE: A division could be avoided using a projective result, except at present
+                 * callers will expect that the result is already normalized.
+                 */
+//                else if (coord == COORD_LAMBDA_PROJECTIVE)
+//                {
+//                    ECFieldElement Z = X;
+//                    X = X.square();
+//                    Y = Y.add(X);
+//                    return createRawPoint(X, Y, new ECFieldElement[]{ Z }, withCompression);
+//                }
+                else
+                {
+                    // Y becomes Lambda (X + Y/X) here
+                    Y = Y.divide(X).add(X);
+                }
+                break;
+            }
+            default:
+            {
+                break;
+            }
+            }
+
+            return this.createRawPoint(X, Y, withCompression);
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected ECPoint decompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = this.fromBigInteger(X1), y = null;
+            if (x.isZero())
+            {
+                y = this.getB().sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.square().invert().multiply(this.getB()).add(this.getA()).add(x);
+                ECFieldElement z = solveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.testBitZero() != (yTilde == 1))
+                    {
+                        z = z.addOne();
+                    }
+
+                    switch (this.getCoordinateSystem())
+                    {
+                    case ECCurve.COORD_LAMBDA_AFFINE:
+                    case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+            {
+                throw new IllegalArgumentException("Invalid point compression");
+            }
+
+            return this.createRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        protected ECFieldElement solveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.isZero())
+            {
+                return beta;
+            }
+
+            ECFieldElement gamma, z, zeroElement = this.fromBigInteger(ECConstants.ZERO);
+
+            int m = this.getFieldSize();
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = this.fromBigInteger(new BigInteger(m, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < m; i++)
+                {
+                    ECFieldElement w2 = w.square();
+                    z = z.square().add(w2.multiply(t));
+                    w = w2.add(beta);
+                }
+                if (!w.isZero())
+                {
+                    return null;
+                }
+                gamma = z.square().add(z);
+            }
+            while (gamma.isZero());
+
+            return z;
+        }
+
+        /**
+         * @return the auxiliary values <code>s<sub>0</sub></code> and
+         * <code>s<sub>1</sub></code> used for partial modular reduction for
+         * Koblitz curves.
+         */
+        synchronized BigInteger[] getSi()
+        {
+            if (si == null)
+            {
+                si = Tnaf.getSi(this);
+            }
+            return si;
+        }
+
+        /**
+         * Returns true if this is a Koblitz curve (ABC curve).
+         * @return true if this is a Koblitz curve (ABC curve), false otherwise
+         */
+        public boolean isKoblitz()
+        {
+            return this.order != null && this.cofactor != null && this.b.isOne() && (this.a.isZero() || this.a.isOne());
+        }
+    }
+
+    /**
+     * Elliptic curves over F2m. The Weierstrass equation is given by
+     * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class F2m extends AbstractF2m
+    {
+        private static final int F2M_DEFAULT_COORDS = ECCurve.COORD_LAMBDA_PROJECTIVE;
+
+        /**
+         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+         */
+        private int m;  // can't be final - JDK 1.1
+
+        /**
+         * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+         * x<sup>k</sup> + 1</code> represents the reduction polynomial
+         * <code>f(z)</code>.<br>
+         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        private int k1;  // can't be final - JDK 1.1
+
+        /**
+         * TPB: Always set to <code>0</code><br>
+         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        private int k2;  // can't be final - JDK 1.1
+
+        /**
+         * TPB: Always set to <code>0</code><br>
+         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        private int k3;  // can't be final - JDK 1.1
+        
+         /**
+         * The point at infinity on this curve.
+         */
+        private ECPoint.F2m infinity;  // can't be final - JDK 1.1
+
+        /**
+         * Constructor for Trinomial Polynomial Basis (TPB).
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+         * x<sup>k</sup> + 1</code> represents the reduction
+         * polynomial <code>f(z)</code>.
+         * @param a The coefficient <code>a</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param b The coefficient <code>b</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @deprecated use constructor taking order/cofactor
+         */
+        public F2m(
+            int m,
+            int k,
+            BigInteger a,
+            BigInteger b)
+        {
+            this(m, k, 0, 0, a, b, null, null);
+        }
+
+        /**
+         * Constructor for Trinomial Polynomial Basis (TPB).
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+         * x<sup>k</sup> + 1</code> represents the reduction
+         * polynomial <code>f(z)</code>.
+         * @param a The coefficient <code>a</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param b The coefficient <code>b</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param order The order of the main subgroup of the elliptic curve.
+         * @param cofactor The cofactor of the elliptic curve, i.e.
+         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
+         */
+        public F2m(
+            int m, 
+            int k, 
+            BigInteger a, 
+            BigInteger b,
+            BigInteger order,
+            BigInteger cofactor)
+        {
+            this(m, k, 0, 0, a, b, order, cofactor);
+        }
+
+        /**
+         * Constructor for Pentanomial Polynomial Basis (PPB).
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param a The coefficient <code>a</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param b The coefficient <code>b</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @deprecated use constructor taking order/cofactor
+         */
+        public F2m(
+            int m,
+            int k1,
+            int k2,
+            int k3,
+            BigInteger a,
+            BigInteger b)
+        {
+            this(m, k1, k2, k3, a, b, null, null);
+        }
+
+        /**
+         * Constructor for Pentanomial Polynomial Basis (PPB).
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param a The coefficient <code>a</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param b The coefficient <code>b</code> in the Weierstrass equation
+         * for non-supersingular elliptic curves over
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param order The order of the main subgroup of the elliptic curve.
+         * @param cofactor The cofactor of the elliptic curve, i.e.
+         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
+         */
+        public F2m(
+            int m, 
+            int k1, 
+            int k2, 
+            int k3,
+            BigInteger a, 
+            BigInteger b,
+            BigInteger order,
+            BigInteger cofactor)
+        {
+            super(m, k1, k2, k3);
+
+            this.m = m;
+            this.k1 = k1;
+            this.k2 = k2;
+            this.k3 = k3;
+            this.order = order;
+            this.cofactor = cofactor;
+
+            this.infinity = new ECPoint.F2m(this, null, null, false);
+            this.a = fromBigInteger(a);
+            this.b = fromBigInteger(b);
+            this.coord = F2M_DEFAULT_COORDS;
+        }
+
+        protected F2m(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
+        {
+            super(m, k1, k2, k3);
+
+            this.m = m;
+            this.k1 = k1;
+            this.k2 = k2;
+            this.k3 = k3;
+            this.order = order;
+            this.cofactor = cofactor;
+
+            this.infinity = new ECPoint.F2m(this, null, null, false);
+            this.a = a;
+            this.b = b;
+            this.coord = F2M_DEFAULT_COORDS;
+        }
+
+        protected ECCurve cloneCurve()
+        {
+            return new F2m(this.m, this.k1, this.k2, this.k3, this.a, this.b, this.order, this.cofactor);
+        }
+
+        public boolean supportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            case ECCurve.COORD_HOMOGENEOUS:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        protected ECMultiplier createDefaultMultiplier()
+        {
+            if (isKoblitz())
+            {
+                return new WTauNafMultiplier();
+            }
+
+            return super.createDefaultMultiplier();
+        }
+
+        public int getFieldSize()
+        {
+            return m;
+        }
+
+        public ECFieldElement fromBigInteger(BigInteger x)
+        {
+            return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x);
+        }
+
+        protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+        {
+            return new ECPoint.F2m(this, x, y, withCompression);
+        }
+
+        protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+        {
+            return new ECPoint.F2m(this, x, y, zs, withCompression);
+        }
+
+        public ECPoint getInfinity()
+        {
+            return infinity;
+        }
+
+        public int getM()
+        {
+            return m;
+        }
+
+        /**
+         * Return true if curve uses a Trinomial basis.
+         * 
+         * @return true if curve Trinomial, false otherwise.
+         */
+        public boolean isTrinomial()
+        {
+            return k2 == 0 && k3 == 0;
+        }
+        
+        public int getK1()
+        {
+            return k1;
+        }
+
+        public int getK2()
+        {
+            return k2;
+        }
+
+        public int getK3()
+        {
+            return k3;
+        }
+
+        public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len)
+        {
+            final int FE_LONGS = (m + 63) >>> 6;
+            final int[] ks = isTrinomial() ? new int[]{ k1 } : new int[]{ k1, k2, k3 }; 
+
+            final long[] table = new long[len * FE_LONGS * 2];
+            {
+                int pos = 0;
+                for (int i = 0; i < len; ++i)
+                {
+                    ECPoint p = points[off + i];
+                    ((ECFieldElement.F2m)p.getRawXCoord()).x.copyTo(table, pos); pos += FE_LONGS;
+                    ((ECFieldElement.F2m)p.getRawYCoord()).x.copyTo(table, pos); pos += FE_LONGS;
+                }
+            }
+
+            return new ECLookupTable()
+            {
+                public int getSize()
+                {
+                    return len;
+                }
+
+                public ECPoint lookup(int index)
+                {
+                    long[] x = Nat.create64(FE_LONGS), y = Nat.create64(FE_LONGS);
+                    int pos = 0;
+
+                    for (int i = 0; i < len; ++i)
+                    {
+                        long MASK = ((i ^ index) - 1) >> 31;
+
+                        for (int j = 0; j < FE_LONGS; ++j)
+                        {
+                            x[j] ^= table[pos + j] & MASK;
+                            y[j] ^= table[pos + FE_LONGS + j] & MASK;
+                        }
+
+                        pos += (FE_LONGS * 2);
+                    }
+
+                    return createRawPoint(new ECFieldElement.F2m(m, ks, new LongArray(x)), new ECFieldElement.F2m(m, ks, new LongArray(y)), false);
+                }
+            };
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECFieldElement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECFieldElement.java
new file mode 100644
index 0000000..fb4cff0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECFieldElement.java
@@ -0,0 +1,931 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+import com.android.internal.org.bouncycastle.math.raw.Mod;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.BigIntegers;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ECFieldElement
+    implements ECConstants
+{
+    public abstract BigInteger     toBigInteger();
+    public abstract String         getFieldName();
+    public abstract int            getFieldSize();
+    public abstract ECFieldElement add(ECFieldElement b);
+    public abstract ECFieldElement addOne();
+    public abstract ECFieldElement subtract(ECFieldElement b);
+    public abstract ECFieldElement multiply(ECFieldElement b);
+    public abstract ECFieldElement divide(ECFieldElement b);
+    public abstract ECFieldElement negate();
+    public abstract ECFieldElement square();
+    public abstract ECFieldElement invert();
+    public abstract ECFieldElement sqrt();
+
+    public ECFieldElement()
+    {
+
+    }
+    
+    public int bitLength()
+    {
+        return toBigInteger().bitLength();
+    }
+
+    public boolean isOne()
+    {
+        return bitLength() == 1;
+    }
+
+    public boolean isZero()
+    {
+        return 0 == toBigInteger().signum();
+    }
+
+    public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+    {
+        return multiply(b).subtract(x.multiply(y));
+    }
+
+    public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+    {
+        return multiply(b).add(x.multiply(y));
+    }
+
+    public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y)
+    {
+        return square().subtract(x.multiply(y));
+    }
+
+    public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y)
+    {
+        return square().add(x.multiply(y));
+    }
+
+    public ECFieldElement squarePow(int pow)
+    {
+        ECFieldElement r = this;
+        for (int i = 0; i < pow; ++i)
+        {
+            r = r.square();
+        }
+        return r;
+    }
+
+    public boolean testBitZero()
+    {
+        return toBigInteger().testBit(0);
+    }
+
+    public String toString()
+    {
+        return this.toBigInteger().toString(16);
+    }
+
+    public byte[] getEncoded()
+    {
+        return BigIntegers.asUnsignedByteArray((getFieldSize() + 7) / 8, toBigInteger());
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static abstract class AbstractFp extends ECFieldElement
+    {
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Fp extends AbstractFp
+    {
+        BigInteger q, r, x;
+
+        static BigInteger calculateResidue(BigInteger p)
+        {
+            int bitLength = p.bitLength();
+            if (bitLength >= 96)
+            {
+                BigInteger firstWord = p.shiftRight(bitLength - 64);
+                if (firstWord.longValue() == -1L)
+                {
+                    return ONE.shiftLeft(bitLength).subtract(p);
+                }
+            }
+            return null;
+        }
+
+        /**
+         * @deprecated Use ECCurve.fromBigInteger to construct field elements
+         */
+        public Fp(BigInteger q, BigInteger x)
+        {
+            this(q, calculateResidue(q), x);
+        }
+
+        Fp(BigInteger q, BigInteger r, BigInteger x)
+        {
+            if (x == null || x.signum() < 0 || x.compareTo(q) >= 0)
+            {
+                throw new IllegalArgumentException("x value invalid in Fp field element");
+            }
+
+            this.q = q;
+            this.r = r;
+            this.x = x;
+        }
+
+        public BigInteger toBigInteger()
+        {
+            return x;
+        }
+
+        /**
+         * return the field name for this field.
+         *
+         * @return the string "Fp".
+         */
+        public String getFieldName()
+        {
+            return "Fp";
+        }
+
+        public int getFieldSize()
+        {
+            return q.bitLength();
+        }
+
+        public BigInteger getQ()
+        {
+            return q;
+        }
+
+        public ECFieldElement add(ECFieldElement b)
+        {
+            return new Fp(q, r, modAdd(x, b.toBigInteger()));
+        }
+
+        public ECFieldElement addOne()
+        {
+            BigInteger x2 = x.add(ECConstants.ONE);
+            if (x2.compareTo(q) == 0)
+            {
+                x2 = ECConstants.ZERO;
+            }
+            return new Fp(q, r, x2);
+        }
+
+        public ECFieldElement subtract(ECFieldElement b)
+        {
+            return new Fp(q, r, modSubtract(x, b.toBigInteger()));
+        }
+
+        public ECFieldElement multiply(ECFieldElement b)
+        {
+            return new Fp(q, r, modMult(x, b.toBigInteger()));
+        }
+
+        public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            BigInteger ax = this.x, bx = b.toBigInteger(), xx = x.toBigInteger(), yx = y.toBigInteger();
+            BigInteger ab = ax.multiply(bx);
+            BigInteger xy = xx.multiply(yx);
+            return new Fp(q, r, modReduce(ab.subtract(xy)));
+        }
+
+        public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            BigInteger ax = this.x, bx = b.toBigInteger(), xx = x.toBigInteger(), yx = y.toBigInteger();
+            BigInteger ab = ax.multiply(bx);
+            BigInteger xy = xx.multiply(yx);
+            return new Fp(q, r, modReduce(ab.add(xy)));
+        }
+
+        public ECFieldElement divide(ECFieldElement b)
+        {
+            return new Fp(q, r, modMult(x, modInverse(b.toBigInteger())));
+        }
+
+        public ECFieldElement negate()
+        {
+            return x.signum() == 0 ? this : new Fp(q, r, q.subtract(x));
+        }
+
+        public ECFieldElement square()
+        {
+            return new Fp(q, r, modMult(x, x));
+        }
+
+        public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            BigInteger ax = this.x, xx = x.toBigInteger(), yx = y.toBigInteger();
+            BigInteger aa = ax.multiply(ax);
+            BigInteger xy = xx.multiply(yx);
+            return new Fp(q, r, modReduce(aa.subtract(xy)));
+        }
+
+        public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            BigInteger ax = this.x, xx = x.toBigInteger(), yx = y.toBigInteger();
+            BigInteger aa = ax.multiply(ax);
+            BigInteger xy = xx.multiply(yx);
+            return new Fp(q, r, modReduce(aa.add(xy)));
+        }
+
+        public ECFieldElement invert()
+        {
+            // TODO Modular inversion can be faster for a (Generalized) Mersenne Prime.
+            return new Fp(q, r, modInverse(x));
+        }
+
+        // D.1.4 91
+        /**
+         * return a sqrt root - the routine verifies that the calculation
+         * returns the right value - if none exists it returns null.
+         */
+        public ECFieldElement sqrt()
+        {
+            if (this.isZero() || this.isOne()) // earlier JDK compatibility
+            {
+                return this;
+            }
+
+            if (!q.testBit(0))
+            {
+                throw new RuntimeException("not done yet");
+            }
+
+            // note: even though this class implements ECConstants don't be tempted to
+            // remove the explicit declaration, some J2ME environments don't cope.
+
+            if (q.testBit(1)) // q == 4m + 3
+            {
+                BigInteger e = q.shiftRight(2).add(ECConstants.ONE);
+                return checkSqrt(new Fp(q, r, x.modPow(e, q)));
+            }
+
+            if (q.testBit(2)) // q == 8m + 5
+            {
+                BigInteger t1 = x.modPow(q.shiftRight(3), q);
+                BigInteger t2 = modMult(t1, x);
+                BigInteger t3 = modMult(t2, t1);
+
+                if (t3.equals(ECConstants.ONE))
+                {
+                    return checkSqrt(new Fp(q, r, t2));
+                }
+
+                // TODO This is constant and could be precomputed
+                BigInteger t4 = ECConstants.TWO.modPow(q.shiftRight(2), q);
+
+                BigInteger y = modMult(t2, t4);
+
+                return checkSqrt(new Fp(q, r, y));
+            }
+
+            // q == 8m + 1
+
+            BigInteger legendreExponent = q.shiftRight(1);
+            if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE)))
+            {
+                return null;
+            }
+
+            BigInteger X = this.x;
+            BigInteger fourX = modDouble(modDouble(X));
+
+            BigInteger k = legendreExponent.add(ECConstants.ONE), qMinusOne = q.subtract(ECConstants.ONE);
+
+            BigInteger U, V;
+            Random rand = new Random();
+            do
+            {
+                BigInteger P;
+                do
+                {
+                    P = new BigInteger(q.bitLength(), rand);
+                }
+                while (P.compareTo(q) >= 0
+                    || !modReduce(P.multiply(P).subtract(fourX)).modPow(legendreExponent, q).equals(qMinusOne));
+
+                BigInteger[] result = lucasSequence(P, X, k);
+                U = result[0];
+                V = result[1];
+
+                if (modMult(V, V).equals(fourX))
+                {
+                    return new ECFieldElement.Fp(q, r, modHalfAbs(V));
+                }
+            }
+            while (U.equals(ECConstants.ONE) || U.equals(qMinusOne));
+
+            return null;
+        }
+
+        private ECFieldElement checkSqrt(ECFieldElement z)
+        {
+            return z.square().equals(this) ? z : null;
+        }
+
+        private BigInteger[] lucasSequence(
+            BigInteger  P,
+            BigInteger  Q,
+            BigInteger  k)
+        {
+            // TODO Research and apply "common-multiplicand multiplication here"
+
+            int n = k.bitLength();
+            int s = k.getLowestSetBit();
+
+            // assert k.testBit(s);
+
+            BigInteger Uh = ECConstants.ONE;
+            BigInteger Vl = ECConstants.TWO;
+            BigInteger Vh = P;
+            BigInteger Ql = ECConstants.ONE;
+            BigInteger Qh = ECConstants.ONE;
+
+            for (int j = n - 1; j >= s + 1; --j)
+            {
+                Ql = modMult(Ql, Qh);
+
+                if (k.testBit(j))
+                {
+                    Qh = modMult(Ql, Q);
+                    Uh = modMult(Uh, Vh);
+                    Vl = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
+                    Vh = modReduce(Vh.multiply(Vh).subtract(Qh.shiftLeft(1)));
+                }
+                else
+                {
+                    Qh = Ql;
+                    Uh = modReduce(Uh.multiply(Vl).subtract(Ql));
+                    Vh = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
+                    Vl = modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));
+                }
+            }
+
+            Ql = modMult(Ql, Qh);
+            Qh = modMult(Ql, Q);
+            Uh = modReduce(Uh.multiply(Vl).subtract(Ql));
+            Vl = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
+            Ql = modMult(Ql, Qh);
+
+            for (int j = 1; j <= s; ++j)
+            {
+                Uh = modMult(Uh, Vl);
+                Vl = modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));
+                Ql = modMult(Ql, Ql);
+            }
+
+            return new BigInteger[]{ Uh, Vl };
+        }
+
+        protected BigInteger modAdd(BigInteger x1, BigInteger x2)
+        {
+            BigInteger x3 = x1.add(x2);
+            if (x3.compareTo(q) >= 0)
+            {
+                x3 = x3.subtract(q);
+            }
+            return x3;
+        }
+
+        protected BigInteger modDouble(BigInteger x)
+        {
+            BigInteger _2x = x.shiftLeft(1);
+            if (_2x.compareTo(q) >= 0)
+            {
+                _2x = _2x.subtract(q);
+            }
+            return _2x;
+        }
+
+        protected BigInteger modHalf(BigInteger x)
+        {
+            if (x.testBit(0))
+            {
+                x = q.add(x);
+            }
+            return x.shiftRight(1);
+        }
+
+        protected BigInteger modHalfAbs(BigInteger x)
+        {
+            if (x.testBit(0))
+            {
+                x = q.subtract(x);
+            }
+            return x.shiftRight(1);
+        }
+
+        protected BigInteger modInverse(BigInteger x)
+        {
+            int bits = getFieldSize();
+            int len = (bits + 31) >> 5;
+            int[] p = Nat.fromBigInteger(bits, q);
+            int[] n = Nat.fromBigInteger(bits, x);
+            int[] z = Nat.create(len);
+            Mod.invert(p, n, z);
+            return Nat.toBigInteger(len, z);
+        }
+
+        protected BigInteger modMult(BigInteger x1, BigInteger x2)
+        {
+            return modReduce(x1.multiply(x2));
+        }
+
+        protected BigInteger modReduce(BigInteger x)
+        {
+            if (r != null)
+            {
+                boolean negative = x.signum() < 0;
+                if (negative)
+                {
+                    x = x.abs();
+                }
+                int qLen = q.bitLength();
+                boolean rIsOne = r.equals(ECConstants.ONE);
+                while (x.bitLength() > (qLen + 1))
+                {
+                    BigInteger u = x.shiftRight(qLen);
+                    BigInteger v = x.subtract(u.shiftLeft(qLen));
+                    if (!rIsOne)
+                    {
+                        u = u.multiply(r);
+                    }
+                    x = u.add(v); 
+                }
+                while (x.compareTo(q) >= 0)
+                {
+                    x = x.subtract(q);
+                }
+                if (negative && x.signum() != 0)
+                {
+                    x = q.subtract(x);
+                }
+            }
+            else
+            {
+                x = x.mod(q);
+            }
+            return x;
+        }
+
+        protected BigInteger modSubtract(BigInteger x1, BigInteger x2)
+        {
+            BigInteger x3 = x1.subtract(x2);
+            if (x3.signum() < 0)
+            {
+                x3 = x3.add(q);
+            }
+            return x3;
+        }
+
+        public boolean equals(Object other)
+        {
+            if (other == this)
+            {
+                return true;
+            }
+
+            if (!(other instanceof ECFieldElement.Fp))
+            {
+                return false;
+            }
+            
+            ECFieldElement.Fp o = (ECFieldElement.Fp)other;
+            return q.equals(o.q) && x.equals(o.x);
+        }
+
+        public int hashCode()
+        {
+            return q.hashCode() ^ x.hashCode();
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static abstract class AbstractF2m extends ECFieldElement
+    {
+        public ECFieldElement halfTrace()
+        {
+            int m = this.getFieldSize();
+            if ((m & 1) == 0)
+            {
+                throw new IllegalStateException("Half-trace only defined for odd m");
+            }
+
+            ECFieldElement fe = this;
+            ECFieldElement ht = fe;
+            for (int i = 2; i < m; i += 2)
+            {
+                fe = fe.squarePow(2);
+                ht = ht.add(fe);
+            }
+
+            return ht;
+        }
+
+        public int trace()
+        {
+            int m = this.getFieldSize();
+            ECFieldElement fe = this;
+            ECFieldElement tr = fe;
+            for (int i = 1; i < m; ++i)
+            {
+                fe = fe.square();
+                tr = tr.add(fe);
+            }
+            if (tr.isZero())
+            {
+                return 0;
+            }
+            if (tr.isOne())
+            {
+                return 1;
+            }
+            throw new IllegalStateException("Internal error in trace calculation");
+        }
+    }
+
+    /**
+     * Class representing the Elements of the finite field
+     * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB)
+     * representation. Both trinomial (TPB) and pentanomial (PPB) polynomial
+     * basis representations are supported. Gaussian normal basis (GNB)
+     * representation is not supported.
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class F2m extends AbstractF2m
+    {
+        /**
+         * Indicates gaussian normal basis representation (GNB). Number chosen
+         * according to X9.62. GNB is not implemented at present.
+         */
+        public static final int GNB = 1;
+
+        /**
+         * Indicates trinomial basis representation (TPB). Number chosen
+         * according to X9.62.
+         */
+        public static final int TPB = 2;
+
+        /**
+         * Indicates pentanomial basis representation (PPB). Number chosen
+         * according to X9.62.
+         */
+        public static final int PPB = 3;
+
+        /**
+         * TPB or PPB.
+         */
+        private int representation;
+
+        /**
+         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+         */
+        private int m;
+
+        private int[] ks;
+
+        /**
+         * The <code>LongArray</code> holding the bits.
+         */
+        LongArray x;
+
+        /**
+         * Constructor for PPB.
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param x The BigInteger representing the value of the field element.
+         * @deprecated Use ECCurve.fromBigInteger to construct field elements
+         */
+        public F2m(
+            int m, 
+            int k1, 
+            int k2, 
+            int k3,
+            BigInteger x)
+        {
+            if (x == null || x.signum() < 0 || x.bitLength() > m)
+            {
+                throw new IllegalArgumentException("x value invalid in F2m field element");
+            }
+
+            if ((k2 == 0) && (k3 == 0))
+            {
+                this.representation = TPB;
+                this.ks = new int[]{ k1 }; 
+            }
+            else
+            {
+                if (k2 >= k3)
+                {
+                    throw new IllegalArgumentException(
+                            "k2 must be smaller than k3");
+                }
+                if (k2 <= 0)
+                {
+                    throw new IllegalArgumentException(
+                            "k2 must be larger than 0");
+                }
+                this.representation = PPB;
+                this.ks = new int[]{ k1, k2, k3 }; 
+            }
+
+            this.m = m;
+            this.x = new LongArray(x);
+        }
+
+        F2m(int m, int[] ks, LongArray x)
+        {
+            this.m = m;
+            this.representation = (ks.length == 1) ? TPB : PPB;
+            this.ks = ks;
+            this.x = x;
+        }
+
+        public int bitLength()
+        {
+            return x.degree();
+        }
+
+        public boolean isOne()
+        {
+            return x.isOne();
+        }
+
+        public boolean isZero()
+        {
+            return x.isZero();
+        }
+
+        public boolean testBitZero()
+        {
+            return x.testBitZero();
+        }
+
+        public BigInteger toBigInteger()
+        {
+            return x.toBigInteger();
+        }
+
+        public String getFieldName()
+        {
+            return "F2m";
+        }
+
+        public int getFieldSize()
+        {
+            return m;
+        }
+
+        /**
+         * Checks, if the ECFieldElements <code>a</code> and <code>b</code>
+         * are elements of the same field <code>F<sub>2<sup>m</sup></sub></code>
+         * (having the same representation).
+         * @param a field element.
+         * @param b field element to be compared.
+         * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
+         * are not elements of the same field
+         * <code>F<sub>2<sup>m</sup></sub></code> (having the same
+         * representation). 
+         */
+        public static void checkFieldElements(
+            ECFieldElement a,
+            ECFieldElement b)
+        {
+            if ((!(a instanceof F2m)) || (!(b instanceof F2m)))
+            {
+                throw new IllegalArgumentException("Field elements are not "
+                        + "both instances of ECFieldElement.F2m");
+            }
+
+            ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a;
+            ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b;
+
+            if (aF2m.representation != bF2m.representation)
+            {
+                // Should never occur
+                throw new IllegalArgumentException("One of the F2m field elements has incorrect representation");
+            }
+
+            if ((aF2m.m != bF2m.m) || !Arrays.areEqual(aF2m.ks, bF2m.ks))
+            {
+                throw new IllegalArgumentException("Field elements are not elements of the same field F2m");
+            }
+        }
+
+        public ECFieldElement add(final ECFieldElement b)
+        {
+            // No check performed here for performance reasons. Instead the
+            // elements involved are checked in ECPoint.F2m
+            // checkFieldElements(this, b);
+            LongArray iarrClone = (LongArray)this.x.clone();
+            F2m bF2m = (F2m)b;
+            iarrClone.addShiftedByWords(bF2m.x, 0);
+            return new F2m(m, ks, iarrClone);
+        }
+
+        public ECFieldElement addOne()
+        {
+            return new F2m(m, ks, x.addOne());
+        }
+
+        public ECFieldElement subtract(final ECFieldElement b)
+        {
+            // Addition and subtraction are the same in F2m
+            return add(b);
+        }
+
+        public ECFieldElement multiply(final ECFieldElement b)
+        {
+            // Right-to-left comb multiplication in the LongArray
+            // Input: Binary polynomials a(z) and b(z) of degree at most m-1
+            // Output: c(z) = a(z) * b(z) mod f(z)
+
+            // No check performed here for performance reasons. Instead the
+            // elements involved are checked in ECPoint.F2m
+            // checkFieldElements(this, b);
+            return new F2m(m, ks, x.modMultiply(((F2m)b).x, m, ks));
+        }
+
+        public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return multiplyPlusProduct(b, x, y);
+        }
+
+        public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            LongArray ax = this.x, bx = ((F2m)b).x, xx = ((F2m)x).x, yx = ((F2m)y).x;
+
+            LongArray ab = ax.multiply(bx, m, ks);
+            LongArray xy = xx.multiply(yx, m, ks);
+
+            if (ab == ax || ab == bx)
+            {
+                ab = (LongArray)ab.clone();
+            }
+
+            ab.addShiftedByWords(xy, 0);
+            ab.reduce(m, ks);
+
+            return new F2m(m, ks, ab);
+        }
+
+        public ECFieldElement divide(final ECFieldElement b)
+        {
+            // There may be more efficient implementations
+            ECFieldElement bInv = b.invert();
+            return multiply(bInv);
+        }
+
+        public ECFieldElement negate()
+        {
+            // -x == x holds for all x in F2m
+            return this;
+        }
+
+        public ECFieldElement square()
+        {
+            return new F2m(m, ks, x.modSquare(m, ks));
+        }
+
+        public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return squarePlusProduct(x, y);
+        }
+
+        public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            LongArray ax = this.x, xx = ((F2m)x).x, yx = ((F2m)y).x;
+
+            LongArray aa = ax.square(m, ks);
+            LongArray xy = xx.multiply(yx, m, ks);
+
+            if (aa == ax)
+            {
+                aa = (LongArray)aa.clone();
+            }
+
+            aa.addShiftedByWords(xy, 0);
+            aa.reduce(m, ks);
+
+            return new F2m(m, ks, aa);
+        }
+
+        public ECFieldElement squarePow(int pow)
+        {
+            return pow < 1 ? this : new F2m(m, ks, x.modSquareN(pow, m, ks));
+        }
+
+        public ECFieldElement invert()
+        {
+            return new ECFieldElement.F2m(this.m, this.ks, this.x.modInverse(m, ks));
+        }
+
+        public ECFieldElement sqrt()
+        {
+            return (x.isZero() || x.isOne()) ? this : squarePow(m - 1);
+        }
+
+        /**
+         * @return the representation of the field
+         * <code>F<sub>2<sup>m</sup></sub></code>, either of
+         * TPB (trinomial
+         * basis representation) or
+         * PPB (pentanomial
+         * basis representation).
+         */
+        public int getRepresentation()
+        {
+            return this.representation;
+        }
+
+        /**
+         * @return the degree <code>m</code> of the reduction polynomial
+         * <code>f(z)</code>.
+         */
+        public int getM()
+        {
+            return this.m;
+        }
+
+        /**
+         * @return TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+         * x<sup>k</sup> + 1</code> represents the reduction polynomial
+         * <code>f(z)</code>.<br>
+         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        public int getK1()
+        {
+            return this.ks[0];
+        }
+
+        /**
+         * @return TPB: Always returns <code>0</code><br>
+         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        public int getK2()
+        {
+            return this.ks.length >= 2 ? this.ks[1] : 0;
+        }
+
+        /**
+         * @return TPB: Always set to <code>0</code><br>
+         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.<br>
+         */
+        public int getK3()
+        {
+            return this.ks.length >= 3 ? this.ks[2] : 0;
+        }
+
+        public boolean equals(Object anObject)
+        {
+            if (anObject == this) 
+            {
+                return true;
+            }
+
+            if (!(anObject instanceof ECFieldElement.F2m)) 
+            {
+                return false;
+            }
+
+            ECFieldElement.F2m b = (ECFieldElement.F2m)anObject;
+            
+            return ((this.m == b.m)
+                && (this.representation == b.representation)
+                && Arrays.areEqual(this.ks, b.ks)
+                && (this.x.equals(b.x)));
+        }
+
+        public int hashCode()
+        {
+            return x.hashCode() ^ m ^ Arrays.hashCode(ks);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECLookupTable.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECLookupTable.java
new file mode 100644
index 0000000..37e3672
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECLookupTable.java
@@ -0,0 +1,11 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ECLookupTable
+{
+    int getSize();
+    ECPoint lookup(int index);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECMultiplier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECMultiplier.java
new file mode 100644
index 0000000..7ee82e9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECMultiplier.java
@@ -0,0 +1,21 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Interface for classes encapsulating a point multiplication algorithm
+ * for <code>ECPoint</code>s.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ECMultiplier
+{
+    /**
+     * Multiplies the <code>ECPoint p</code> by <code>k</code>, i.e.
+     * <code>p</code> is added <code>k</code> times to itself.
+     * @param p The <code>ECPoint</code> to be multiplied.
+     * @param k The factor by which <code>p</code> is multiplied.
+     * @return <code>p</code> multiplied by <code>k</code>.
+     */
+    ECPoint multiply(ECPoint p, BigInteger k);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECPoint.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECPoint.java
new file mode 100644
index 0000000..60db91c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECPoint.java
@@ -0,0 +1,2144 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+import java.util.Hashtable;
+
+/**
+ * base class for points on elliptic curves.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class ECPoint
+{
+    protected final static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0];
+
+    protected static ECFieldElement[] getInitialZCoords(ECCurve curve)
+    {
+        // Cope with null curve, most commonly used by implicitlyCa
+        int coord = null == curve ? ECCurve.COORD_AFFINE : curve.getCoordinateSystem();
+
+        switch (coord)
+        {
+        case ECCurve.COORD_AFFINE:
+        case ECCurve.COORD_LAMBDA_AFFINE:
+            return EMPTY_ZS;
+        default:
+            break;
+        }
+
+        ECFieldElement one = curve.fromBigInteger(ECConstants.ONE);
+
+        switch (coord)
+        {
+        case ECCurve.COORD_HOMOGENEOUS:
+        case ECCurve.COORD_JACOBIAN:
+        case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            return new ECFieldElement[]{ one };
+        case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+            return new ECFieldElement[]{ one, one, one };
+        case ECCurve.COORD_JACOBIAN_MODIFIED:
+            return new ECFieldElement[]{ one, curve.getA() };
+        default:
+            throw new IllegalArgumentException("unknown coordinate system");
+        }
+    }
+
+    protected ECCurve curve;
+    protected ECFieldElement x;
+    protected ECFieldElement y;
+    protected ECFieldElement[] zs;
+
+    protected boolean withCompression;
+
+    // Hashtable is (String -> PreCompInfo)
+    protected Hashtable preCompTable = null;
+
+    protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
+    {
+        this(curve, x, y, getInitialZCoords(curve));
+    }
+
+    protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs)
+    {
+        this.curve = curve;
+        this.x = x;
+        this.y = y;
+        this.zs = zs;
+    }
+
+    protected abstract boolean satisfiesCurveEquation();
+
+    protected boolean satisfiesOrder()
+    {
+        if (ECConstants.ONE.equals(curve.getCofactor()))
+        {
+            return true;
+        }
+
+        BigInteger n = curve.getOrder();
+
+        // TODO Require order to be available for all curves
+
+        return n == null || ECAlgorithms.referenceMultiply(this, n).isInfinity();
+    }
+
+    public final ECPoint getDetachedPoint()
+    {
+        return normalize().detach();
+    }
+
+    public ECCurve getCurve()
+    {
+        return curve;
+    }
+
+    protected abstract ECPoint detach();
+
+    protected int getCurveCoordinateSystem()
+    {
+        // Cope with null curve, most commonly used by implicitlyCa
+        return null == curve ? ECCurve.COORD_AFFINE : curve.getCoordinateSystem();
+    }
+
+    /**
+     * Returns the affine x-coordinate after checking that this point is normalized.
+     * 
+     * @return The affine x-coordinate of this point
+     * @throws IllegalStateException if the point is not normalized
+     */
+    public ECFieldElement getAffineXCoord()
+    {
+        checkNormalized();
+        return getXCoord();
+    }
+
+    /**
+     * Returns the affine y-coordinate after checking that this point is normalized
+     * 
+     * @return The affine y-coordinate of this point
+     * @throws IllegalStateException if the point is not normalized
+     */
+    public ECFieldElement getAffineYCoord()
+    {
+        checkNormalized();
+        return getYCoord();
+    }
+
+    /**
+     * Returns the x-coordinate.
+     * 
+     * Caution: depending on the curve's coordinate system, this may not be the same value as in an
+     * affine coordinate system; use normalize() to get a point where the coordinates have their
+     * affine values, or use getAffineXCoord() if you expect the point to already have been
+     * normalized.
+     * 
+     * @return the x-coordinate of this point
+     */
+    public ECFieldElement getXCoord()
+    {
+        return x;
+    }
+
+    /**
+     * Returns the y-coordinate.
+     * 
+     * Caution: depending on the curve's coordinate system, this may not be the same value as in an
+     * affine coordinate system; use normalize() to get a point where the coordinates have their
+     * affine values, or use getAffineYCoord() if you expect the point to already have been
+     * normalized.
+     * 
+     * @return the y-coordinate of this point
+     */
+    public ECFieldElement getYCoord()
+    {
+        return y;
+    }
+
+    public ECFieldElement getZCoord(int index)
+    {
+        return (index < 0 || index >= zs.length) ? null : zs[index];
+    }
+
+    public ECFieldElement[] getZCoords()
+    {
+        int zsLen = zs.length;
+        if (zsLen == 0)
+        {
+            return EMPTY_ZS;
+        }
+        ECFieldElement[] copy = new ECFieldElement[zsLen];
+        System.arraycopy(zs, 0, copy, 0, zsLen);
+        return copy;
+    }
+
+    public final ECFieldElement getRawXCoord()
+    {
+        return x;
+    }
+
+    public final ECFieldElement getRawYCoord()
+    {
+        return y;
+    }
+
+    protected final ECFieldElement[] getRawZCoords()
+    {
+        return zs;
+    }
+
+    protected void checkNormalized()
+    {
+        if (!isNormalized())
+        {
+            throw new IllegalStateException("point not in normal form");
+        }
+    }
+
+    public boolean isNormalized()
+    {
+        int coord = this.getCurveCoordinateSystem();
+
+        return coord == ECCurve.COORD_AFFINE
+            || coord == ECCurve.COORD_LAMBDA_AFFINE
+            || isInfinity()
+            || zs[0].isOne();
+    }
+
+    /**
+     * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+     * coordinates reflect those of the equivalent point in an affine coordinate system.
+     * 
+     * @return a new ECPoint instance representing the same point, but with normalized coordinates
+     */
+    public ECPoint normalize()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        switch (this.getCurveCoordinateSystem())
+        {
+        case ECCurve.COORD_AFFINE:
+        case ECCurve.COORD_LAMBDA_AFFINE:
+        {
+            return this;
+        }
+        default:
+        {
+            ECFieldElement Z1 = getZCoord(0);
+            if (Z1.isOne())
+            {
+                return this;
+            }
+
+            return normalize(Z1.invert());
+        }
+        }
+    }
+
+    ECPoint normalize(ECFieldElement zInv)
+    {
+        switch (this.getCurveCoordinateSystem())
+        {
+        case ECCurve.COORD_HOMOGENEOUS:
+        case ECCurve.COORD_LAMBDA_PROJECTIVE:
+        {
+            return createScaledPoint(zInv, zInv);
+        }
+        case ECCurve.COORD_JACOBIAN:
+        case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+        case ECCurve.COORD_JACOBIAN_MODIFIED:
+        {
+            ECFieldElement zInv2 = zInv.square(), zInv3 = zInv2.multiply(zInv);
+            return createScaledPoint(zInv2, zInv3);
+        }
+        default:
+        {
+            throw new IllegalStateException("not a projective coordinate system");
+        }
+        }
+    }
+
+    protected ECPoint createScaledPoint(ECFieldElement sx, ECFieldElement sy)
+    {
+        return this.getCurve().createRawPoint(getRawXCoord().multiply(sx), getRawYCoord().multiply(sy), this.withCompression);
+    }
+
+    public boolean isInfinity()
+    {
+        return x == null || y == null || (zs.length > 0 && zs[0].isZero());
+    }
+
+    /**
+     * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)}
+     */
+    public boolean isCompressed()
+    {
+        return this.withCompression;
+    }
+
+    public boolean isValid()
+    {
+        return implIsValid(false, true);
+    }
+
+    boolean isValidPartial()
+    {
+        return implIsValid(false, false);
+    }
+
+    boolean implIsValid(final boolean decompressed, final boolean checkOrder)
+    {
+        if (isInfinity())
+        {
+            return true;
+        }
+
+        ValidityPrecompInfo validity = (ValidityPrecompInfo)getCurve().precompute(this, ValidityPrecompInfo.PRECOMP_NAME, new PreCompCallback()
+        {
+            public PreCompInfo precompute(PreCompInfo existing)
+            {
+                ValidityPrecompInfo info = (existing instanceof ValidityPrecompInfo) ? (ValidityPrecompInfo)existing : null;
+                if (info == null)
+                {
+                    info = new ValidityPrecompInfo();
+                }
+
+                if (info.hasFailed())
+                {
+                    return info;
+                }
+                if (!info.hasCurveEquationPassed())
+                {
+                    if (!decompressed && !satisfiesCurveEquation())
+                    {
+                        info.reportFailed();
+                        return info;
+                    }
+                    info.reportCurveEquationPassed();
+                }
+                if (checkOrder && !info.hasOrderPassed())
+                {
+                    if (!satisfiesOrder())
+                    {
+                        info.reportFailed();
+                        return info;
+                    }
+                    info.reportOrderPassed();
+                }
+                return info;
+            }
+        });
+
+        return !validity.hasFailed();
+    }
+
+    public ECPoint scaleX(ECFieldElement scale)
+    {
+        return isInfinity()
+            ?   this
+            :   getCurve().createRawPoint(getRawXCoord().multiply(scale), getRawYCoord(), getRawZCoords(), this.withCompression);
+    }
+
+    public ECPoint scaleY(ECFieldElement scale)
+    {
+        return isInfinity()
+            ?   this
+            :   getCurve().createRawPoint(getRawXCoord(), getRawYCoord().multiply(scale), getRawZCoords(), this.withCompression);
+    }
+
+    public boolean equals(ECPoint other)
+    {
+        if (null == other)
+        {
+            return false;
+        }
+
+        ECCurve c1 = this.getCurve(), c2 = other.getCurve();
+        boolean n1 = (null == c1), n2 = (null == c2);
+        boolean i1 = isInfinity(), i2 = other.isInfinity();
+
+        if (i1 || i2)
+        {
+            return (i1 && i2) && (n1 || n2 || c1.equals(c2));
+        }
+
+        ECPoint p1 = this, p2 = other;
+        if (n1 && n2)
+        {
+            // Points with null curve are in affine form, so already normalized
+        }
+        else if (n1)
+        {
+            p2 = p2.normalize();
+        }
+        else if (n2)
+        {
+            p1 = p1.normalize();
+        }
+        else if (!c1.equals(c2))
+        {
+            return false;
+        }
+        else
+        {
+            // TODO Consider just requiring already normalized, to avoid silent performance degradation
+
+            ECPoint[] points = new ECPoint[]{ this, c1.importPoint(p2) };
+
+            // TODO This is a little strong, really only requires coZNormalizeAll to get Zs equal
+            c1.normalizeAll(points);
+
+            p1 = points[0];
+            p2 = points[1];
+        }
+
+        return p1.getXCoord().equals(p2.getXCoord()) && p1.getYCoord().equals(p2.getYCoord());
+    }
+
+    public boolean equals(Object other)
+    {
+        if (other == this)
+        {
+            return true;
+        }
+
+        if (!(other instanceof ECPoint))
+        {
+            return false;
+        }
+
+        return equals((ECPoint)other);
+    }
+
+    public int hashCode()
+    {
+        ECCurve c = this.getCurve();
+        int hc = (null == c) ? 0 : ~c.hashCode();
+
+        if (!this.isInfinity())
+        {
+            // TODO Consider just requiring already normalized, to avoid silent performance degradation
+
+            ECPoint p = normalize();
+
+            hc ^= p.getXCoord().hashCode() * 17;
+            hc ^= p.getYCoord().hashCode() * 257;
+        }
+
+        return hc;
+    }
+
+    public String toString()
+    {
+        if (this.isInfinity())
+        {
+            return "INF";
+        }
+
+        StringBuffer sb = new StringBuffer();
+        sb.append('(');
+        sb.append(getRawXCoord());
+        sb.append(',');
+        sb.append(getRawYCoord());
+        for (int i = 0; i < zs.length; ++i)
+        {
+            sb.append(',');
+            sb.append(zs[i]);
+        }
+        sb.append(')');
+        return sb.toString();
+    }
+
+    /**
+     * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)}
+     * @return a byte encoding.
+     */
+    public byte[] getEncoded()
+    {
+        return getEncoded(this.withCompression);
+    }
+
+    /**
+     * Get an encoding of the point value, optionally in compressed format.
+     * 
+     * @param compressed whether to generate a compressed point encoding.
+     * @return the point encoding
+     */
+    public byte[] getEncoded(boolean compressed)
+    {
+        if (this.isInfinity())
+        {
+            return new byte[1];
+        }
+
+        ECPoint normed = normalize();
+
+        byte[] X = normed.getXCoord().getEncoded();
+
+        if (compressed)
+        {
+            byte[] PO = new byte[X.length + 1];
+            PO[0] = (byte)(normed.getCompressionYTilde() ? 0x03 : 0x02);
+            System.arraycopy(X, 0, PO, 1, X.length);
+            return PO;
+        }
+
+        byte[] Y = normed.getYCoord().getEncoded();
+
+        byte[] PO = new byte[X.length + Y.length + 1];
+        PO[0] = 0x04;
+        System.arraycopy(X, 0, PO, 1, X.length);
+        System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
+        return PO;
+    }
+
+    protected abstract boolean getCompressionYTilde();
+
+    public abstract ECPoint add(ECPoint b);
+
+    public abstract ECPoint negate();
+
+    public abstract ECPoint subtract(ECPoint b);
+
+    public ECPoint timesPow2(int e)
+    {
+        if (e < 0)
+        {
+            throw new IllegalArgumentException("'e' cannot be negative");
+        }
+
+        ECPoint p = this;
+        while (--e >= 0)
+        {
+            p = p.twice();
+        }
+        return p;
+    }
+
+    public abstract ECPoint twice();
+
+    public ECPoint twicePlus(ECPoint b)
+    {
+        return twice().add(b);
+    }
+
+    public ECPoint threeTimes()
+    {
+        return twicePlus(this);
+    }
+
+    /**
+     * Multiplies this <code>ECPoint</code> by the given number.
+     * @param k The multiplicator.
+     * @return <code>k * this</code>.
+     */
+    public ECPoint multiply(BigInteger k)
+    {
+        return this.getCurve().getMultiplier().multiply(this, k);
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static abstract class AbstractFp extends ECPoint
+    {
+        protected AbstractFp(ECCurve curve, ECFieldElement x, ECFieldElement y)
+        {
+            super(curve, x, y);
+        }
+
+        protected AbstractFp(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs)
+        {
+            super(curve, x, y, zs);
+        }
+
+        protected boolean getCompressionYTilde()
+        {
+            return this.getAffineYCoord().testBitZero();
+        }
+
+        protected boolean satisfiesCurveEquation()
+        {
+            ECFieldElement X = this.x, Y = this.y, A = curve.getA(), B = curve.getB();
+            ECFieldElement lhs = Y.square();
+
+            switch (this.getCurveCoordinateSystem())
+            {
+            case ECCurve.COORD_AFFINE:
+                break;
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Z = this.zs[0];
+                if (!Z.isOne())
+                {
+                    ECFieldElement Z2 = Z.square(), Z3 = Z.multiply(Z2);
+                    lhs = lhs.multiply(Z);
+                    A = A.multiply(Z2);
+                    B = B.multiply(Z3);
+                }
+                break;
+            }
+            case ECCurve.COORD_JACOBIAN:
+            case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+            {
+                ECFieldElement Z = this.zs[0];
+                if (!Z.isOne())
+                {
+                    ECFieldElement Z2 = Z.square(), Z4 = Z2.square(), Z6 = Z2.multiply(Z4);
+                    A = A.multiply(Z4);
+                    B = B.multiply(Z6);
+                }
+                break;
+            }
+            default:
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+
+            ECFieldElement rhs = X.square().add(A).multiply(X).add(B);
+            return lhs.equals(rhs);
+        }
+
+        public ECPoint subtract(ECPoint b)
+        {
+            if (b.isInfinity())
+            {
+                return this;
+            }
+
+            // Add -b
+            return this.add(b.negate());
+        }
+    }
+
+    /**
+     * Elliptic curve points over Fp
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Fp extends AbstractFp
+    {
+        /**
+         * Create a point that encodes with or without point compression.
+         * 
+         * @param curve the curve to use
+         * @param x affine x co-ordinate
+         * @param y affine y co-ordinate
+         * @param withCompression if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)}
+         */
+        public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+        {
+            super(curve, x, y);
+
+            if ((x == null) != (y == null))
+            {
+                throw new IllegalArgumentException("Exactly one of the field elements is null");
+            }
+
+            this.withCompression = withCompression;
+        }
+
+        Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+        {
+            super(curve, x, y, zs);
+
+            this.withCompression = withCompression;
+        }
+
+        protected ECPoint detach()
+        {
+            return new ECPoint.Fp(null, this.getAffineXCoord(), this.getAffineYCoord(), false);
+        }
+
+        public ECFieldElement getZCoord(int index)
+        {
+            if (index == 1 && ECCurve.COORD_JACOBIAN_MODIFIED == this.getCurveCoordinateSystem())
+            {
+                return getJacobianModifiedW();
+            }
+
+            return super.getZCoord(index);
+        }
+
+        // B.3 pg 62
+        public ECPoint add(ECPoint b)
+        {
+            if (this.isInfinity())
+            {
+                return b;
+            }
+            if (b.isInfinity())
+            {
+                return this;
+            }
+            if (this == b)
+            {
+                return twice();
+            }
+
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
+
+            ECFieldElement X1 = this.x, Y1 = this.y;
+            ECFieldElement X2 = b.x, Y2 = b.y;
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement dx = X2.subtract(X1), dy = Y2.subtract(Y1);
+
+                if (dx.isZero())
+                {
+                    if (dy.isZero())
+                    {
+                        // this == b, i.e. this must be doubled
+                        return twice();
+                    }
+
+                    // this == -b, i.e. the result is the point at infinity
+                    return curve.getInfinity();
+                }
+
+                ECFieldElement gamma = dy.divide(dx);
+                ECFieldElement X3 = gamma.square().subtract(X1).subtract(X2);
+                ECFieldElement Y3 = gamma.multiply(X1.subtract(X3)).subtract(Y1);
+
+                return new ECPoint.Fp(curve, X3, Y3, this.withCompression);
+            }
+
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Z1 = this.zs[0];
+                ECFieldElement Z2 = b.zs[0];
+
+                boolean Z1IsOne = Z1.isOne();
+                boolean Z2IsOne = Z2.isOne();
+
+                ECFieldElement u1 = Z1IsOne ? Y2 : Y2.multiply(Z1);
+                ECFieldElement u2 = Z2IsOne ? Y1 : Y1.multiply(Z2);
+                ECFieldElement u = u1.subtract(u2);
+                ECFieldElement v1 = Z1IsOne ? X2 : X2.multiply(Z1);
+                ECFieldElement v2 = Z2IsOne ? X1 : X1.multiply(Z2);
+                ECFieldElement v = v1.subtract(v2);
+
+                // Check if b == this or b == -this
+                if (v.isZero())
+                {
+                    if (u.isZero())
+                    {
+                        // this == b, i.e. this must be doubled
+                        return this.twice();
+                    }
+
+                    // this == -b, i.e. the result is the point at infinity
+                    return curve.getInfinity();
+                }
+
+                // TODO Optimize for when w == 1
+                ECFieldElement w = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.multiply(Z2);
+                ECFieldElement vSquared = v.square();
+                ECFieldElement vCubed = vSquared.multiply(v);
+                ECFieldElement vSquaredV2 = vSquared.multiply(v2);
+                ECFieldElement A = u.square().multiply(w).subtract(vCubed).subtract(two(vSquaredV2));
+
+                ECFieldElement X3 = v.multiply(A);
+                ECFieldElement Y3 = vSquaredV2.subtract(A).multiplyMinusProduct(u, u2, vCubed);
+                ECFieldElement Z3 = vCubed.multiply(w);
+
+                return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+
+            case ECCurve.COORD_JACOBIAN:
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+            {
+                ECFieldElement Z1 = this.zs[0];
+                ECFieldElement Z2 = b.zs[0];
+
+                boolean Z1IsOne = Z1.isOne();
+
+                ECFieldElement X3, Y3, Z3, Z3Squared = null;
+
+                if (!Z1IsOne && Z1.equals(Z2))
+                {
+                    // TODO Make this available as public method coZAdd?
+
+                    ECFieldElement dx = X1.subtract(X2), dy = Y1.subtract(Y2);
+                    if (dx.isZero())
+                    {
+                        if (dy.isZero())
+                        {
+                            return twice();
+                        }
+                        return curve.getInfinity();
+                    }
+
+                    ECFieldElement C = dx.square();
+                    ECFieldElement W1 = X1.multiply(C), W2 = X2.multiply(C);
+                    ECFieldElement A1 = W1.subtract(W2).multiply(Y1);
+
+                    X3 = dy.square().subtract(W1).subtract(W2);
+                    Y3 = W1.subtract(X3).multiply(dy).subtract(A1);
+                    Z3 = dx;
+
+                    Z3 = Z3.multiply(Z1);
+                }
+                else
+                {
+                    ECFieldElement Z1Squared, U2, S2;
+                    if (Z1IsOne)
+                    {
+                        Z1Squared = Z1; U2 = X2; S2 = Y2;
+                    }
+                    else
+                    {
+                        Z1Squared = Z1.square();
+                        U2 = Z1Squared.multiply(X2);
+                        ECFieldElement Z1Cubed = Z1Squared.multiply(Z1);
+                        S2 = Z1Cubed.multiply(Y2);
+                    }
+
+                    boolean Z2IsOne = Z2.isOne();
+                    ECFieldElement Z2Squared, U1, S1;
+                    if (Z2IsOne)
+                    {
+                        Z2Squared = Z2; U1 = X1; S1 = Y1;
+                    }
+                    else
+                    {
+                        Z2Squared = Z2.square();
+                        U1 = Z2Squared.multiply(X1); 
+                        ECFieldElement Z2Cubed = Z2Squared.multiply(Z2);
+                        S1 = Z2Cubed.multiply(Y1);
+                    }
+
+                    ECFieldElement H = U1.subtract(U2);
+                    ECFieldElement R = S1.subtract(S2);
+    
+                    // Check if b == this or b == -this
+                    if (H.isZero())
+                    {
+                        if (R.isZero())
+                        {
+                            // this == b, i.e. this must be doubled
+                            return this.twice();
+                        }
+    
+                        // this == -b, i.e. the result is the point at infinity
+                        return curve.getInfinity();
+                    }
+    
+                    ECFieldElement HSquared = H.square();
+                    ECFieldElement G = HSquared.multiply(H);
+                    ECFieldElement V = HSquared.multiply(U1);
+    
+                    X3 = R.square().add(G).subtract(two(V));
+                    Y3 = V.subtract(X3).multiplyMinusProduct(R, G, S1);
+
+                    Z3 = H;
+                    if (!Z1IsOne)
+                    {
+                        Z3 = Z3.multiply(Z1);
+                    }
+                    if (!Z2IsOne)
+                    {
+                        Z3 = Z3.multiply(Z2);
+                    }
+    
+                    // Alternative calculation of Z3 using fast square
+    //                X3 = four(X3);
+    //                Y3 = eight(Y3);
+    //                Z3 = doubleProductFromSquares(Z1, Z2, Z1Squared, Z2Squared).multiply(H);
+                    
+                    if (Z3 == H)
+                    {
+                        Z3Squared = HSquared;
+                    }
+                }
+
+                ECFieldElement[] zs;
+                if (coord == ECCurve.COORD_JACOBIAN_MODIFIED)
+                {
+                    // TODO If the result will only be used in a subsequent addition, we don't need W3
+                    ECFieldElement W3 = calculateJacobianModifiedW(Z3, Z3Squared);
+
+                    zs = new ECFieldElement[]{ Z3, W3 };
+                }
+                else
+                {
+                    zs = new ECFieldElement[]{ Z3 };
+                }
+
+                return new ECPoint.Fp(curve, X3, Y3, zs, this.withCompression);
+            }
+
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
+        }
+
+        // B.3 pg 62
+        public ECPoint twice()
+        {
+            if (this.isInfinity())
+            {
+                return this;
+            }
+
+            ECCurve curve = this.getCurve();
+
+            ECFieldElement Y1 = this.y;
+            if (Y1.isZero()) 
+            {
+                return curve.getInfinity();
+            }
+
+            int coord = curve.getCoordinateSystem();
+
+            ECFieldElement X1 = this.x;
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement X1Squared = X1.square();
+                ECFieldElement gamma = three(X1Squared).add(this.getCurve().getA()).divide(two(Y1));
+                ECFieldElement X3 = gamma.square().subtract(two(X1));
+                ECFieldElement Y3 = gamma.multiply(X1.subtract(X3)).subtract(Y1);
+    
+                return new ECPoint.Fp(curve, X3, Y3, this.withCompression);
+            }
+
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Z1 = this.zs[0];
+
+                boolean Z1IsOne = Z1.isOne();
+
+                // TODO Optimize for small negative a4 and -3
+                ECFieldElement w = curve.getA();
+                if (!w.isZero() && !Z1IsOne)
+                {
+                    w = w.multiply(Z1.square());
+                }
+                w = w.add(three(X1.square()));
+                
+                ECFieldElement s = Z1IsOne ? Y1 : Y1.multiply(Z1);
+                ECFieldElement t = Z1IsOne ? Y1.square() : s.multiply(Y1);
+                ECFieldElement B = X1.multiply(t);
+                ECFieldElement _4B = four(B);
+                ECFieldElement h = w.square().subtract(two(_4B));
+
+                ECFieldElement _2s = two(s);
+                ECFieldElement X3 = h.multiply(_2s);
+                ECFieldElement _2t = two(t);
+                ECFieldElement Y3 = _4B.subtract(h).multiply(w).subtract(two(_2t.square()));
+                ECFieldElement _4sSquared = Z1IsOne ? two(_2t) : _2s.square();
+                ECFieldElement Z3 = two(_4sSquared).multiply(s);
+
+                return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+
+            case ECCurve.COORD_JACOBIAN:
+            {
+                ECFieldElement Z1 = this.zs[0];
+
+                boolean Z1IsOne = Z1.isOne();
+
+                ECFieldElement Y1Squared = Y1.square();
+                ECFieldElement T = Y1Squared.square();
+
+                ECFieldElement a4 = curve.getA();
+                ECFieldElement a4Neg = a4.negate();
+
+                ECFieldElement M, S;
+                if (a4Neg.toBigInteger().equals(BigInteger.valueOf(3)))
+                {
+                    ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.square();
+                    M = three(X1.add(Z1Squared).multiply(X1.subtract(Z1Squared)));
+                    S = four(Y1Squared.multiply(X1));
+                }
+                else
+                {
+                    ECFieldElement X1Squared = X1.square();
+                    M = three(X1Squared);
+                    if (Z1IsOne)
+                    {
+                        M = M.add(a4);
+                    }
+                    else if (!a4.isZero())
+                    {
+                        ECFieldElement Z1Squared = Z1.square();
+                        ECFieldElement Z1Pow4 = Z1Squared.square();
+                        if (a4Neg.bitLength() < a4.bitLength())
+                        {
+                            M = M.subtract(Z1Pow4.multiply(a4Neg));
+                        }
+                        else
+                        {
+                            M = M.add(Z1Pow4.multiply(a4));
+                        }
+                    }
+//                  S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T));
+                    S = four(X1.multiply(Y1Squared));
+                }
+
+                ECFieldElement X3 = M.square().subtract(two(S));
+                ECFieldElement Y3 = S.subtract(X3).multiply(M).subtract(eight(T));
+
+                ECFieldElement Z3 = two(Y1);
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.multiply(Z1);
+                }
+
+                // Alternative calculation of Z3 using fast square
+//                ECFieldElement Z3 = doubleProductFromSquares(Y1, Z1, Y1Squared, Z1Squared);
+
+                return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+            {
+                return twiceJacobianModified(true);
+            }
+
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
+        }
+
+        public ECPoint twicePlus(ECPoint b)
+        {
+            if (this == b)
+            {
+                return threeTimes();
+            }
+            if (this.isInfinity())
+            {
+                return b;
+            }
+            if (b.isInfinity())
+            {
+                return twice();
+            }
+
+            ECFieldElement Y1 = this.y;
+            if (Y1.isZero()) 
+            {
+                return b;
+            }
+
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement X1 = this.x;
+                ECFieldElement X2 = b.x, Y2 = b.y;
+
+                ECFieldElement dx = X2.subtract(X1), dy = Y2.subtract(Y1);
+
+                if (dx.isZero())
+                {
+                    if (dy.isZero())
+                    {
+                        // this == b i.e. the result is 3P
+                        return threeTimes();
+                    }
+
+                    // this == -b, i.e. the result is P
+                    return this;
+                }
+
+                /*
+                 * Optimized calculation of 2P + Q, as described in "Trading Inversions for
+                 * Multiplications in Elliptic Curve Cryptography", by Ciet, Joye, Lauter, Montgomery.
+                 */
+
+                ECFieldElement X = dx.square(), Y = dy.square();
+                ECFieldElement d = X.multiply(two(X1).add(X2)).subtract(Y);
+                if (d.isZero())
+                {
+                    return curve.getInfinity();
+                }
+
+                ECFieldElement D = d.multiply(dx);
+                ECFieldElement I = D.invert();
+                ECFieldElement L1 = d.multiply(I).multiply(dy);
+                ECFieldElement L2 = two(Y1).multiply(X).multiply(dx).multiply(I).subtract(L1);
+                ECFieldElement X4 = (L2.subtract(L1)).multiply(L1.add(L2)).add(X2);
+                ECFieldElement Y4 = (X1.subtract(X4)).multiply(L2).subtract(Y1);
+
+                return new ECPoint.Fp(curve, X4, Y4, this.withCompression);
+            }
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+            {
+                return twiceJacobianModified(false).add(b);
+            }
+            default:
+            {
+                return twice().add(b);
+            }
+            }
+        }
+
+        public ECPoint threeTimes()
+        {
+            if (this.isInfinity())
+            {
+                return this;
+            }
+
+            ECFieldElement Y1 = this.y;
+            if (Y1.isZero())
+            {
+                return this;
+            }
+
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement X1 = this.x;
+
+                ECFieldElement _2Y1 = two(Y1); 
+                ECFieldElement X = _2Y1.square();
+                ECFieldElement Z = three(X1.square()).add(this.getCurve().getA());
+                ECFieldElement Y = Z.square();
+
+                ECFieldElement d = three(X1).multiply(X).subtract(Y);
+                if (d.isZero())
+                {
+                    return this.getCurve().getInfinity();
+                }
+
+                ECFieldElement D = d.multiply(_2Y1); 
+                ECFieldElement I = D.invert();
+                ECFieldElement L1 = d.multiply(I).multiply(Z);
+                ECFieldElement L2 = X.square().multiply(I).subtract(L1);
+
+                ECFieldElement X4 = (L2.subtract(L1)).multiply(L1.add(L2)).add(X1);
+                ECFieldElement Y4 = (X1.subtract(X4)).multiply(L2).subtract(Y1); 
+                return new ECPoint.Fp(curve, X4, Y4, this.withCompression);
+            }
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+            {
+                return twiceJacobianModified(false).add(this);
+            }
+            default:
+            {
+                // NOTE: Be careful about recursions between twicePlus and threeTimes
+                return twice().add(this);
+            }
+            }
+        }
+
+        public ECPoint timesPow2(int e)
+        {
+            if (e < 0)
+            {
+                throw new IllegalArgumentException("'e' cannot be negative");
+            }
+            if (e == 0 || this.isInfinity())
+            {
+                return this;
+            }
+            if (e == 1)
+            {
+                return twice();
+            }
+
+            ECCurve curve = this.getCurve();
+
+            ECFieldElement Y1 = this.y;
+            if (Y1.isZero()) 
+            {
+                return curve.getInfinity();
+            }
+
+            int coord = curve.getCoordinateSystem();
+
+            ECFieldElement W1 = curve.getA();
+            ECFieldElement X1 = this.x;
+            ECFieldElement Z1 = this.zs.length < 1 ? curve.fromBigInteger(ECConstants.ONE) : this.zs[0];
+
+            if (!Z1.isOne())
+            {
+                switch (coord)
+                {
+                case ECCurve.COORD_AFFINE:
+                    break;
+                case ECCurve.COORD_HOMOGENEOUS:
+                    ECFieldElement Z1Sq = Z1.square();
+                    X1 = X1.multiply(Z1);
+                    Y1 = Y1.multiply(Z1Sq);
+                    W1 = calculateJacobianModifiedW(Z1, Z1Sq);
+                    break;
+                case ECCurve.COORD_JACOBIAN:
+                    W1 = calculateJacobianModifiedW(Z1, null);
+                    break;
+                case ECCurve.COORD_JACOBIAN_MODIFIED:
+                    W1 = getJacobianModifiedW();
+                    break;
+                default:
+                    throw new IllegalStateException("unsupported coordinate system");
+                }
+            }
+
+            for (int i = 0; i < e; ++i)
+            {
+                if (Y1.isZero()) 
+                {
+                    return curve.getInfinity();
+                }
+
+                ECFieldElement X1Squared = X1.square();
+                ECFieldElement M = three(X1Squared);
+                ECFieldElement _2Y1 = two(Y1);
+                ECFieldElement _2Y1Squared = _2Y1.multiply(Y1);
+                ECFieldElement S = two(X1.multiply(_2Y1Squared));
+                ECFieldElement _4T = _2Y1Squared.square();
+                ECFieldElement _8T = two(_4T);
+
+                if (!W1.isZero())
+                {
+                    M = M.add(W1);
+                    W1 = two(_8T.multiply(W1));
+                }
+
+                X1 = M.square().subtract(two(S));
+                Y1 = M.multiply(S.subtract(X1)).subtract(_8T);
+                Z1 = Z1.isOne() ? _2Y1 : _2Y1.multiply(Z1);
+            }
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+                ECFieldElement zInv = Z1.invert(), zInv2 = zInv.square(), zInv3 = zInv2.multiply(zInv);
+                return new Fp(curve, X1.multiply(zInv2), Y1.multiply(zInv3), this.withCompression);
+            case ECCurve.COORD_HOMOGENEOUS:
+                X1 = X1.multiply(Z1);
+                Z1 = Z1.multiply(Z1.square());
+                return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1 }, this.withCompression);
+            case ECCurve.COORD_JACOBIAN:
+                return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1 }, this.withCompression);
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+                return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1, W1 }, this.withCompression);
+            default:
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+        }
+
+        protected ECFieldElement two(ECFieldElement x)
+        {
+            return x.add(x);
+        }
+
+        protected ECFieldElement three(ECFieldElement x)
+        {
+            return two(x).add(x);
+        }
+
+        protected ECFieldElement four(ECFieldElement x)
+        {
+            return two(two(x));
+        }
+
+        protected ECFieldElement eight(ECFieldElement x)
+        {
+            return four(two(x));
+        }
+
+        protected ECFieldElement doubleProductFromSquares(ECFieldElement a, ECFieldElement b,
+            ECFieldElement aSquared, ECFieldElement bSquared)
+        {
+            /*
+             * NOTE: If squaring in the field is faster than multiplication, then this is a quicker
+             * way to calculate 2.A.B, if A^2 and B^2 are already known.
+             */
+            return a.add(b).square().subtract(aSquared).subtract(bSquared);
+        }
+
+        public ECPoint negate()
+        {
+            if (this.isInfinity())
+            {
+                return this;
+            }
+
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
+
+            if (ECCurve.COORD_AFFINE != coord)
+            {
+                return new ECPoint.Fp(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+            }
+
+            return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);
+        }
+
+        protected ECFieldElement calculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared)
+        {
+            ECFieldElement a4 = this.getCurve().getA();
+            if (a4.isZero() || Z.isOne())
+            {
+                return a4;
+            }
+
+            if (ZSquared == null)
+            {
+                ZSquared = Z.square();
+            }
+
+            ECFieldElement W = ZSquared.square();
+            ECFieldElement a4Neg = a4.negate();
+            if (a4Neg.bitLength() < a4.bitLength())
+            {
+                W = W.multiply(a4Neg).negate();
+            }
+            else
+            {
+                W = W.multiply(a4);
+            }
+            return W;
+        }
+
+        protected ECFieldElement getJacobianModifiedW()
+        {
+            ECFieldElement W = this.zs[1];
+            if (W == null)
+            {
+                // NOTE: Rarely, twicePlus will result in the need for a lazy W1 calculation here
+                this.zs[1] = W = calculateJacobianModifiedW(this.zs[0], null);
+            }
+            return W;
+        }
+
+        protected ECPoint.Fp twiceJacobianModified(boolean calculateW)
+        {
+            ECFieldElement X1 = this.x, Y1 = this.y, Z1 = this.zs[0], W1 = getJacobianModifiedW();
+
+            ECFieldElement X1Squared = X1.square();
+            ECFieldElement M = three(X1Squared).add(W1);
+            ECFieldElement _2Y1 = two(Y1);
+            ECFieldElement _2Y1Squared = _2Y1.multiply(Y1);
+            ECFieldElement S = two(X1.multiply(_2Y1Squared));
+            ECFieldElement X3 = M.square().subtract(two(S));
+            ECFieldElement _4T = _2Y1Squared.square();
+            ECFieldElement _8T = two(_4T);
+            ECFieldElement Y3 = M.multiply(S.subtract(X3)).subtract(_8T);
+            ECFieldElement W3 = calculateW ? two(_8T.multiply(W1)) : null;
+            ECFieldElement Z3 = Z1.isOne() ? _2Y1 : _2Y1.multiply(Z1);
+
+            return new ECPoint.Fp(this.getCurve(), X3, Y3, new ECFieldElement[]{ Z3, W3 }, this.withCompression);
+        }
+    }
+
+    /**
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static abstract class AbstractF2m extends ECPoint
+    {
+        protected AbstractF2m(ECCurve curve, ECFieldElement x, ECFieldElement y)
+        {
+            super(curve, x, y);
+        }
+
+        protected AbstractF2m(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs)
+        {
+            super(curve, x, y, zs);
+        }
+
+        protected boolean satisfiesCurveEquation()
+        {
+            ECCurve curve = this.getCurve();
+            ECFieldElement X = this.x, A = curve.getA(), B = curve.getB();
+            
+            int coord = curve.getCoordinateSystem();
+            if (coord == ECCurve.COORD_LAMBDA_PROJECTIVE)
+            {
+                ECFieldElement Z = this.zs[0];
+                boolean ZIsOne = Z.isOne();
+
+                if (X.isZero())
+                {
+                    // NOTE: For x == 0, we expect the affine-y instead of the lambda-y 
+                    ECFieldElement Y = this.y;
+                    ECFieldElement lhs = Y.square(), rhs = B;
+                    if (!ZIsOne)
+                    {
+                        rhs = rhs.multiply(Z.square());
+                    }
+                    return lhs.equals(rhs);
+                }
+
+                ECFieldElement L = this.y, X2 = X.square();
+                ECFieldElement lhs, rhs;
+                if (ZIsOne)
+                {
+                    lhs = L.square().add(L).add(A);
+                    rhs = X2.square().add(B);
+                }
+                else
+                {
+                    ECFieldElement Z2 = Z.square(), Z4 = Z2.square();
+                    lhs = L.add(Z).multiplyPlusProduct(L, A, Z2);
+                    // TODO If sqrt(b) is precomputed this can be simplified to a single square
+                    rhs = X2.squarePlusProduct(B, Z4);
+                }
+                lhs = lhs.multiply(X2);
+                return lhs.equals(rhs);
+            }
+
+            ECFieldElement Y = this.y;
+            ECFieldElement lhs = Y.add(X).multiply(Y);
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+                break;
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Z = this.zs[0];
+                if (!Z.isOne())
+                {
+                    ECFieldElement Z2 = Z.square(), Z3 = Z.multiply(Z2);
+                    lhs = lhs.multiply(Z);
+                    A = A.multiply(Z);
+                    B = B.multiply(Z3);
+                }
+                break;
+            }
+            default:
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+
+            ECFieldElement rhs = X.add(A).multiply(X.square()).add(B);
+            return lhs.equals(rhs);
+        }
+
+        protected boolean satisfiesOrder()
+        {
+            BigInteger cofactor = curve.getCofactor();
+            if (ECConstants.TWO.equals(cofactor))
+            {
+                /*
+                 *  Check that the trace of (X + A) is 0, then there exists a solution to L^2 + L = X + A,
+                 *  and so a halving is possible, so this point is the double of another.  
+                 */
+                ECPoint N = this.normalize();
+                ECFieldElement X = N.getAffineXCoord();
+                ECFieldElement rhs = X.add(curve.getA());
+                return ((ECFieldElement.AbstractF2m)rhs).trace() == 0;
+            }
+            if (ECConstants.FOUR.equals(cofactor))
+            {
+                /*
+                 * Solve L^2 + L = X + A to find the half of this point, if it exists (fail if not).
+                 * Generate both possibilities for the square of the half-point's x-coordinate (w),
+                 * and check if Tr(w + A) == 0 for at least one; then a second halving is possible
+                 * (see comments for cofactor 2 above), so this point is four times another.
+                 * 
+                 * Note: Tr(x^2) == Tr(x). 
+                 */
+                ECPoint N = this.normalize();
+                ECFieldElement X = N.getAffineXCoord();
+                ECFieldElement lambda = ((ECCurve.AbstractF2m)curve).solveQuadraticEquation(X.add(curve.getA()));
+                if (lambda == null)
+                {
+                    return false;
+                }
+                ECFieldElement w = X.multiply(lambda).add(N.getAffineYCoord()); 
+                ECFieldElement t = w.add(curve.getA());
+                return ((ECFieldElement.AbstractF2m)t).trace() == 0
+                    || ((ECFieldElement.AbstractF2m)(t.add(X))).trace() == 0;
+            }
+
+            return super.satisfiesOrder();
+        }
+
+        public ECPoint scaleX(ECFieldElement scale)
+        {
+            if (this.isInfinity())
+            {
+                return this;
+            }
+
+            int coord = this.getCurveCoordinateSystem();
+
+            switch (coord)
+            {
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            {
+                // Y is actually Lambda (X + Y/X) here
+                ECFieldElement X = this.getRawXCoord(), L = this.getRawYCoord(); // earlier JDK
+
+                ECFieldElement X2 = X.multiply(scale);
+                ECFieldElement L2 = L.add(X).divide(scale).add(X2);
+
+                return this.getCurve().createRawPoint(X, L2, this.getRawZCoords(), this.withCompression); // earlier JDK
+            }
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                // Y is actually Lambda (X + Y/X) here
+                ECFieldElement X = this.getRawXCoord(), L = this.getRawYCoord(), Z = this.getRawZCoords()[0]; // earlier JDK
+
+                // We scale the Z coordinate also, to avoid an inversion
+                ECFieldElement X2 = X.multiply(scale.square());
+                ECFieldElement L2 = L.add(X).add(X2);
+                ECFieldElement Z2 = Z.multiply(scale);
+
+                return this.getCurve().createRawPoint(X2, L2, new ECFieldElement[]{ Z2 }, this.withCompression); // earlier JDK
+            }
+            default:
+            {
+                return super.scaleX(scale);
+            }
+            }
+        }
+
+        public ECPoint scaleY(ECFieldElement scale)
+        {
+            if (this.isInfinity())
+            {
+                return this;
+            }
+
+            int coord = this.getCurveCoordinateSystem();
+
+            switch (coord)
+            {
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                ECFieldElement X = this.getRawXCoord(), L = this.getRawYCoord(); // earlier JDK
+
+                // Y is actually Lambda (X + Y/X) here
+                ECFieldElement L2 = L.add(X).multiply(scale).add(X);
+
+                return this.getCurve().createRawPoint(X, L2, this.getRawZCoords(), this.withCompression); // earlier JDK
+            }
+            default:
+            {
+                return super.scaleY(scale);
+            }
+            }
+        }
+
+        public ECPoint subtract(ECPoint b)
+        {
+            if (b.isInfinity())
+            {
+                return this;
+            }
+
+            // Add -b
+            return this.add(b.negate());
+        }
+
+        public ECPoint.AbstractF2m tau()
+        {
+            if (this.isInfinity())
+            {
+                return this;
+            }
+
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
+
+            ECFieldElement X1 = this.x;
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            {
+                ECFieldElement Y1 = this.y;
+                return (ECPoint.AbstractF2m)curve.createRawPoint(X1.square(), Y1.square(), this.withCompression);
+            }
+            case ECCurve.COORD_HOMOGENEOUS:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                ECFieldElement Y1 = this.y, Z1 = this.zs[0];
+                return (ECPoint.AbstractF2m)curve.createRawPoint(X1.square(), Y1.square(),
+                    new ECFieldElement[]{ Z1.square() }, this.withCompression);
+            }
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
+        }
+
+        public ECPoint.AbstractF2m tauPow(int pow)
+        {
+            if (this.isInfinity())
+            {
+                return this;
+            }
+
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
+
+            ECFieldElement X1 = this.x;
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            {
+                ECFieldElement Y1 = this.y;
+                return (ECPoint.AbstractF2m)curve.createRawPoint(X1.squarePow(pow), Y1.squarePow(pow), this.withCompression);
+            }
+            case ECCurve.COORD_HOMOGENEOUS:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                ECFieldElement Y1 = this.y, Z1 = this.zs[0];
+                return (ECPoint.AbstractF2m)curve.createRawPoint(X1.squarePow(pow), Y1.squarePow(pow),
+                    new ECFieldElement[]{ Z1.squarePow(pow) }, this.withCompression);
+            }
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
+        }
+    }
+
+    /**
+     * Elliptic curve points over F2m
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class F2m extends AbstractF2m
+    {
+        /**
+         * @param curve base curve
+         * @param x x point
+         * @param y y point
+         * @param withCompression true if encode with point compression.
+         * 
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)}
+         */
+        public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+        {
+            super(curve, x, y);
+
+            if ((x == null) != (y == null))
+            {
+                throw new IllegalArgumentException("Exactly one of the field elements is null");
+            }
+
+            if (x != null)
+            {
+                // Check if x and y are elements of the same field
+                ECFieldElement.F2m.checkFieldElements(this.x, this.y);
+
+                // Check if x and a are elements of the same field
+                if (curve != null)
+                {
+                    ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA());
+                }
+            }
+
+            this.withCompression = withCompression;
+
+//            checkCurveEquation();
+        }
+
+        F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+        {
+            super(curve, x, y, zs);
+
+            this.withCompression = withCompression;
+
+//            checkCurveEquation();
+        }
+
+        protected ECPoint detach()
+        {
+            return new ECPoint.F2m(null, this.getAffineXCoord(), this.getAffineYCoord(), false); // earlier JDK
+        }
+
+        public ECFieldElement getYCoord()
+        {
+            int coord = this.getCurveCoordinateSystem();
+
+            switch (coord)
+            {
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                ECFieldElement X = x, L = y;
+
+                if (this.isInfinity() || X.isZero())
+                {
+                    return L;
+                }
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.add(X).multiply(X);
+                if (ECCurve.COORD_LAMBDA_PROJECTIVE == coord)
+                {
+                    ECFieldElement Z = zs[0];
+                    if (!Z.isOne())
+                    {
+                        Y = Y.divide(Z);
+                    }
+                }
+                return Y;
+            }
+            default:
+            {
+                return y;
+            }
+            }
+        }
+
+        protected boolean getCompressionYTilde()
+        {
+            ECFieldElement X = this.getRawXCoord();
+            if (X.isZero())
+            {
+                return false;
+            }
+
+            ECFieldElement Y = this.getRawYCoord();
+
+            switch (this.getCurveCoordinateSystem())
+            {
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                // Y is actually Lambda (X + Y/X) here
+                return Y.testBitZero() != X.testBitZero();
+            }
+            default:
+            {
+                return Y.divide(X).testBitZero();
+            }
+            }
+        }
+
+        public ECPoint add(ECPoint b)
+        {
+            if (this.isInfinity())
+            {
+                return b;
+            }
+            if (b.isInfinity())
+            {
+                return this;
+            }
+
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
+
+            ECFieldElement X1 = this.x;
+            ECFieldElement X2 = b.x;
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement Y1 = this.y;
+                ECFieldElement Y2 = b.y;
+
+                ECFieldElement dx = X1.add(X2), dy = Y1.add(Y2);
+                if (dx.isZero())
+                {
+                    if (dy.isZero())
+                    {
+                        return twice();
+                    }
+
+                    return curve.getInfinity();
+                }
+
+                ECFieldElement L = dy.divide(dx);
+
+                ECFieldElement X3 = L.square().add(L).add(dx).add(curve.getA());
+                ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1);
+
+                return new ECPoint.F2m(curve, X3, Y3, this.withCompression);
+            }
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Y1 = this.y, Z1 = this.zs[0];
+                ECFieldElement Y2 = b.y, Z2 = b.zs[0];
+
+                boolean Z2IsOne = Z2.isOne();
+
+                ECFieldElement U1 = Z1.multiply(Y2);
+                ECFieldElement U2 = Z2IsOne ? Y1 : Y1.multiply(Z2);
+                ECFieldElement U = U1.add(U2);
+                ECFieldElement V1 = Z1.multiply(X2);
+                ECFieldElement V2 = Z2IsOne ? X1 : X1.multiply(Z2);
+                ECFieldElement V = V1.add(V2);
+
+                if (V.isZero())
+                {
+                    if (U.isZero())
+                    {
+                        return twice();
+                    }
+
+                    return curve.getInfinity();
+                }
+
+                ECFieldElement VSq = V.square();
+                ECFieldElement VCu = VSq.multiply(V);
+                ECFieldElement W = Z2IsOne ? Z1 : Z1.multiply(Z2);
+                ECFieldElement uv = U.add(V);
+                ECFieldElement A = uv.multiplyPlusProduct(U, VSq, curve.getA()).multiply(W).add(VCu);
+
+                ECFieldElement X3 = V.multiply(A);
+                ECFieldElement VSqZ2 = Z2IsOne ? VSq : VSq.multiply(Z2);
+                ECFieldElement Y3 = U.multiplyPlusProduct(X1, V, Y1).multiplyPlusProduct(VSqZ2, uv, A);
+                ECFieldElement Z3 = VCu.multiply(W);
+
+                return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                if (X1.isZero())
+                {
+                    if (X2.isZero())
+                    {
+                        return curve.getInfinity();
+                    }
+
+                    return b.add(this);
+                }
+
+                ECFieldElement L1 = this.y, Z1 = this.zs[0];
+                ECFieldElement L2 = b.y, Z2 = b.zs[0];
+
+                boolean Z1IsOne = Z1.isOne();
+                ECFieldElement U2 = X2, S2 = L2;
+                if (!Z1IsOne)
+                {
+                    U2 = U2.multiply(Z1);
+                    S2 = S2.multiply(Z1);
+                }
+
+                boolean Z2IsOne = Z2.isOne();
+                ECFieldElement U1 = X1, S1 = L1;
+                if (!Z2IsOne)
+                {
+                    U1 = U1.multiply(Z2);
+                    S1 = S1.multiply(Z2);
+                }
+
+                ECFieldElement A = S1.add(S2);
+                ECFieldElement B = U1.add(U2);
+
+                if (B.isZero())
+                {
+                    if (A.isZero())
+                    {
+                        return twice();
+                    }
+
+                    return curve.getInfinity();
+                }
+
+                ECFieldElement X3, L3, Z3;
+                if (X2.isZero())
+                {
+                    // TODO This can probably be optimized quite a bit
+                    ECPoint p = this.normalize();
+                    X1 = p.getXCoord();
+                    ECFieldElement Y1 = p.getYCoord();
+
+                    ECFieldElement Y2 = L2;
+                    ECFieldElement L = Y1.add(Y2).divide(X1);
+
+                    X3 = L.square().add(L).add(X1).add(curve.getA());
+                    if (X3.isZero())
+                    {
+                        return new ECPoint.F2m(curve, X3, curve.getB().sqrt(), this.withCompression);
+                    }
+
+                    ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1);
+                    L3 = Y3.divide(X3).add(X3);
+                    Z3 = curve.fromBigInteger(ECConstants.ONE);
+                }
+                else
+                {
+                    B = B.square();
+    
+                    ECFieldElement AU1 = A.multiply(U1);
+                    ECFieldElement AU2 = A.multiply(U2);
+
+                    X3 = AU1.multiply(AU2);
+                    if (X3.isZero())
+                    {
+                        return new ECPoint.F2m(curve, X3, curve.getB().sqrt(), this.withCompression);
+                    }
+
+                    ECFieldElement ABZ2 = A.multiply(B);
+                    if (!Z2IsOne)
+                    {
+                        ABZ2 = ABZ2.multiply(Z2);
+                    }
+
+                    L3 = AU2.add(B).squarePlusProduct(ABZ2, L1.add(Z1));
+
+                    Z3 = ABZ2;
+                    if (!Z1IsOne)
+                    {
+                        Z3 = Z3.multiply(Z1);
+                    }
+                }
+
+                return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
+        }
+
+        public ECPoint twice()
+        {
+            if (this.isInfinity()) 
+            {
+                return this;
+            }
+
+            ECCurve curve = this.getCurve();
+
+            ECFieldElement X1 = this.x;
+            if (X1.isZero()) 
+            {
+                // A point with X == 0 is it's own additive inverse
+                return curve.getInfinity();
+            }
+
+            int coord = curve.getCoordinateSystem();
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement Y1 = this.y;
+
+                ECFieldElement L1 = Y1.divide(X1).add(X1);
+
+                ECFieldElement X3 = L1.square().add(L1).add(curve.getA());
+                ECFieldElement Y3 = X1.squarePlusProduct(X3, L1.addOne());
+
+                return new ECPoint.F2m(curve, X3, Y3, this.withCompression);
+            }
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Y1 = this.y, Z1 = this.zs[0];
+
+                boolean Z1IsOne = Z1.isOne();
+                ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1);
+                ECFieldElement Y1Z1 = Z1IsOne ? Y1 : Y1.multiply(Z1);
+
+                ECFieldElement X1Sq = X1.square();
+                ECFieldElement S = X1Sq.add(Y1Z1);
+                ECFieldElement V = X1Z1;
+                ECFieldElement vSquared = V.square();
+                ECFieldElement sv = S.add(V);
+                ECFieldElement h = sv.multiplyPlusProduct(S, vSquared, curve.getA());
+
+                ECFieldElement X3 = V.multiply(h);
+                ECFieldElement Y3 = X1Sq.square().multiplyPlusProduct(V, h, sv);
+                ECFieldElement Z3 = V.multiply(vSquared);    
+
+                return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                ECFieldElement L1 = this.y, Z1 = this.zs[0];
+
+                boolean Z1IsOne = Z1.isOne();
+                ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.multiply(Z1);
+                ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.square();
+                ECFieldElement a = curve.getA();
+                ECFieldElement aZ1Sq = Z1IsOne ? a : a.multiply(Z1Sq);
+                ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq);
+                if (T.isZero())
+                {
+                    return new ECPoint.F2m(curve, T, curve.getB().sqrt(), withCompression);
+                }
+
+                ECFieldElement X3 = T.square();
+                ECFieldElement Z3 = Z1IsOne ? T : T.multiply(Z1Sq);
+
+                ECFieldElement b = curve.getB();
+                ECFieldElement L3;
+                if (b.bitLength() < (curve.getFieldSize() >> 1))
+                {
+                    ECFieldElement t1 = L1.add(X1).square();
+                    ECFieldElement t2;
+                    if (b.isOne())
+                    {
+                        t2 = aZ1Sq.add(Z1Sq).square();
+                    }
+                    else
+                    {
+                        // TODO Can be calculated with one square if we pre-compute sqrt(b)
+                        t2 = aZ1Sq.squarePlusProduct(b, Z1Sq.square());
+                    }
+                    L3 = t1.add(T).add(Z1Sq).multiply(t1).add(t2).add(X3);
+                    if (a.isZero())
+                    {
+                        L3 = L3.add(Z3);
+                    }
+                    else if (!a.isOne())
+                    {
+                        L3 = L3.add(a.addOne().multiply(Z3));
+                    }
+                }
+                else
+                {
+                    ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1);
+                    L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3);
+                }
+
+                return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
+        }
+
+        public ECPoint twicePlus(ECPoint b)
+        {
+            if (this.isInfinity()) 
+            {
+                return b;
+            }
+            if (b.isInfinity())
+            {
+                return twice();
+            }
+
+            ECCurve curve = this.getCurve();
+
+            ECFieldElement X1 = this.x;
+            if (X1.isZero()) 
+            {
+                // A point with X == 0 is it's own additive inverse
+                return b;
+            }
+
+            int coord = curve.getCoordinateSystem();
+
+            switch (coord)
+            {
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                // NOTE: twicePlus() only optimized for lambda-affine argument
+                ECFieldElement X2 = b.x, Z2 = b.zs[0];
+                if (X2.isZero() || !Z2.isOne())
+                {
+                    return twice().add(b);
+                }
+
+                ECFieldElement L1 = this.y, Z1 = this.zs[0];
+                ECFieldElement L2 = b.y;
+
+                ECFieldElement X1Sq = X1.square();
+                ECFieldElement L1Sq = L1.square();
+                ECFieldElement Z1Sq = Z1.square();
+                ECFieldElement L1Z1 = L1.multiply(Z1);
+
+                ECFieldElement T = curve.getA().multiply(Z1Sq).add(L1Sq).add(L1Z1);
+                ECFieldElement L2plus1 = L2.addOne();
+                ECFieldElement A = curve.getA().add(L2plus1).multiply(Z1Sq).add(L1Sq).multiplyPlusProduct(T, X1Sq, Z1Sq);
+                ECFieldElement X2Z1Sq = X2.multiply(Z1Sq);
+                ECFieldElement B = X2Z1Sq.add(T).square();
+
+                if (B.isZero())
+                {
+                    if (A.isZero())
+                    {
+                        return b.twice();
+                    }
+
+                    return curve.getInfinity();
+                }
+
+                if (A.isZero())
+                {
+                    return new ECPoint.F2m(curve, A, curve.getB().sqrt(), withCompression);
+                }
+
+                ECFieldElement X3 = A.square().multiply(X2Z1Sq);
+                ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq);
+                ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3);
+
+                return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+            default:
+            {
+                return twice().add(b);
+            }
+            }
+        }
+
+        public ECPoint negate()
+        {
+            if (this.isInfinity())
+            {
+                return this;
+            }
+
+            ECFieldElement X = this.x;
+            if (X.isZero())
+            {
+                return this;
+            }
+
+            switch (this.getCurveCoordinateSystem())
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement Y = this.y;
+                return new ECPoint.F2m(curve, X, Y.add(X), this.withCompression);
+            }
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Y = this.y, Z = this.zs[0];
+                return new ECPoint.F2m(curve, X, Y.add(X), new ECFieldElement[]{ Z }, this.withCompression);
+            }
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            {
+                ECFieldElement L = this.y;
+                return new ECPoint.F2m(curve, X, L.addOne(), this.withCompression);
+            }
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                // L is actually Lambda (X + Y/X) here
+                ECFieldElement L = this.y, Z = this.zs[0];
+                return new ECPoint.F2m(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression);
+            }
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECPointMap.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECPointMap.java
new file mode 100644
index 0000000..7ca86bc
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ECPointMap.java
@@ -0,0 +1,10 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ECPointMap
+{
+    ECPoint map(ECPoint p);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/FixedPointCombMultiplier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/FixedPointCombMultiplier.java
new file mode 100644
index 0000000..fdea98b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/FixedPointCombMultiplier.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class FixedPointCombMultiplier extends AbstractECMultiplier
+{
+    protected ECPoint multiplyPositive(ECPoint p, BigInteger k)
+    {
+        ECCurve c = p.getCurve();
+        int size = FixedPointUtil.getCombSize(c);
+
+        if (k.bitLength() > size)
+        {
+            /*
+             * TODO The comb works best when the scalars are less than the (possibly unknown) order.
+             * Still, if we want to handle larger scalars, we could allow customization of the comb
+             * size, or alternatively we could deal with the 'extra' bits either by running the comb
+             * multiple times as necessary, or by using an alternative multiplier as prelude.
+             */
+            throw new IllegalStateException("fixed-point comb doesn't support scalars larger than the curve order");
+        }
+
+        FixedPointPreCompInfo info = FixedPointUtil.precompute(p);
+        ECLookupTable lookupTable = info.getLookupTable();
+        int width = info.getWidth();
+
+        int d = (size + width - 1) / width;
+
+        ECPoint R = c.getInfinity();
+
+        int fullComb = d * width;
+        int[] K = Nat.fromBigInteger(fullComb, k);
+
+        int top = fullComb - 1; 
+        for (int i = 0; i < d; ++i)
+        {
+            int secretIndex = 0;
+
+            for (int j = top - i; j >= 0; j -= d)
+            {
+                int secretBit = K[j >>> 5] >>> (j & 0x1F);
+                secretIndex ^= secretBit >>> 1;
+                secretIndex <<= 1;
+                secretIndex ^= secretBit;
+            }
+
+            ECPoint add = lookupTable.lookup(secretIndex);
+
+            R = R.twicePlus(add);
+        }
+
+        return R.add(info.getOffset());
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/FixedPointPreCompInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/FixedPointPreCompInfo.java
new file mode 100644
index 0000000..9df7d80
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/FixedPointPreCompInfo.java
@@ -0,0 +1,53 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+/**
+ * Class holding precomputation data for fixed-point multiplications.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class FixedPointPreCompInfo implements PreCompInfo
+{
+    protected ECPoint offset = null;
+
+    /**
+     * Lookup table for the precomputed {@link ECPoint}s used for a fixed point multiplication.
+     */
+    protected ECLookupTable lookupTable = null;
+
+    /**
+     * The width used for the precomputation. If a larger width precomputation
+     * is already available this may be larger than was requested, so calling
+     * code should refer to the actual width.
+     */
+    protected int width = -1;
+
+    public ECLookupTable getLookupTable()
+    {
+        return lookupTable;
+    }
+
+    public void setLookupTable(ECLookupTable lookupTable)
+    {
+        this.lookupTable = lookupTable;
+    }
+
+    public ECPoint getOffset()
+    {
+        return offset;
+    }
+
+    public void setOffset(ECPoint offset)
+    {
+        this.offset = offset;
+    }
+
+    public int getWidth()
+    {
+        return width;
+    }
+
+    public void setWidth(int width)
+    {
+        this.width = width;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/FixedPointUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/FixedPointUtil.java
new file mode 100644
index 0000000..44290cb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/FixedPointUtil.java
@@ -0,0 +1,91 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class FixedPointUtil
+{
+    public static final String PRECOMP_NAME = "bc_fixed_point";
+
+    public static int getCombSize(ECCurve c)
+    {
+        BigInteger order = c.getOrder();
+        return order == null ? c.getFieldSize() + 1 : order.bitLength(); 
+    }
+
+    public static FixedPointPreCompInfo getFixedPointPreCompInfo(PreCompInfo preCompInfo)
+    {
+        return (preCompInfo instanceof FixedPointPreCompInfo) ? (FixedPointPreCompInfo)preCompInfo : null;
+    }
+
+    public static FixedPointPreCompInfo precompute(final ECPoint p)
+    {
+        final ECCurve c = p.getCurve();
+
+        return (FixedPointPreCompInfo)c.precompute(p, PRECOMP_NAME, new PreCompCallback()
+        {
+            public PreCompInfo precompute(PreCompInfo existing)
+            {
+                FixedPointPreCompInfo existingFP = (existing instanceof FixedPointPreCompInfo) ? (FixedPointPreCompInfo)existing : null;
+
+                int bits = getCombSize(c);
+                int minWidth = bits > 250 ? 6 : 5;
+                int n = 1 << minWidth;
+
+                if (checkExisting(existingFP, n))
+                {
+                    return existingFP;
+                }
+
+                int d = (bits + minWidth - 1) / minWidth;
+
+                ECPoint[] pow2Table = new ECPoint[minWidth + 1];
+                pow2Table[0] = p;
+                for (int i = 1; i < minWidth; ++i)
+                {
+                    pow2Table[i] = pow2Table[i - 1].timesPow2(d);
+                }
+
+                // This will be the 'offset' value 
+                pow2Table[minWidth] = pow2Table[0].subtract(pow2Table[1]);
+
+                c.normalizeAll(pow2Table);
+
+                ECPoint[] lookupTable = new ECPoint[n];
+                lookupTable[0] = pow2Table[0];
+
+                for (int bit = minWidth - 1; bit >= 0; --bit)
+                {
+                    ECPoint pow2 = pow2Table[bit];
+
+                    int step = 1 << bit;
+                    for (int i = step; i < n; i += (step << 1))
+                    {
+                        lookupTable[i] = lookupTable[i - step].add(pow2);
+                    }
+                }
+
+                c.normalizeAll(lookupTable);
+
+                FixedPointPreCompInfo result = new FixedPointPreCompInfo();
+                result.setLookupTable(c.createCacheSafeLookupTable(lookupTable, 0, lookupTable.length));
+                result.setOffset(pow2Table[minWidth]);
+                result.setWidth(minWidth);
+                return result;
+            }
+
+            private boolean checkExisting(FixedPointPreCompInfo existingFP, int n)
+            {
+                return existingFP != null && checkTable(existingFP.getLookupTable(), n);
+            }
+
+            private boolean checkTable(ECLookupTable table, int n)
+            {
+                return table != null && table.getSize() >= n;
+            }
+        });
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/GLVMultiplier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/GLVMultiplier.java
new file mode 100644
index 0000000..1a1101e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/GLVMultiplier.java
@@ -0,0 +1,46 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.endo.GLVEndomorphism;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class GLVMultiplier extends AbstractECMultiplier
+{
+    protected final ECCurve curve;
+    protected final GLVEndomorphism glvEndomorphism;
+
+    public GLVMultiplier(ECCurve curve, GLVEndomorphism glvEndomorphism)
+    {
+        if (curve == null || curve.getOrder() == null)
+        {
+            throw new IllegalArgumentException("Need curve with known group order");
+        }
+
+        this.curve = curve;
+        this.glvEndomorphism = glvEndomorphism;
+    }
+
+    protected ECPoint multiplyPositive(ECPoint p, BigInteger k)
+    {
+        if (!curve.equals(p.getCurve()))
+        {
+            throw new IllegalStateException();
+        }
+
+        BigInteger n = p.getCurve().getOrder();
+        BigInteger[] ab = glvEndomorphism.decomposeScalar(k.mod(n));
+        BigInteger a = ab[0], b = ab[1];
+
+        ECPointMap pointMap = glvEndomorphism.getPointMap();
+        if (glvEndomorphism.hasEfficientPointMap())
+        {
+            return ECAlgorithms.implShamirsTrickWNaf(p, a, pointMap, b);
+        }
+
+        return ECAlgorithms.implShamirsTrickWNaf(p, a, pointMap.map(p), b);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/LongArray.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/LongArray.java
new file mode 100644
index 0000000..504542a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/LongArray.java
@@ -0,0 +1,2203 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+import java.math.BigInteger;
+
+class LongArray implements Cloneable
+{
+//    private static long DEINTERLEAVE_MASK = 0x5555555555555555L;
+
+    /*
+     * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
+     * In a binary field, this operation is the same as squaring an 8 bit number.
+     * 
+     * NOTE: All entries are positive so sign-extension is not an issue.
+     */
+    private static final short[] INTERLEAVE2_TABLE = new short[]
+    {
+        0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+        0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+        0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+        0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+        0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+        0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+        0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+        0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+        0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+        0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+        0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+        0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+        0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+        0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+        0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+        0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+        0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+        0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+        0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+        0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+        0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+        0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+        0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+        0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+        0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+        0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+        0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+        0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+        0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+        0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+        0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+        0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+    };
+
+    /*
+     * This expands 7 bit indices into 21 bit contents (high bit 18), by inserting 0s between bits.
+     */
+    private static final int[] INTERLEAVE3_TABLE = new  int[]
+    {
+        0x00000, 0x00001, 0x00008, 0x00009, 0x00040, 0x00041, 0x00048, 0x00049,
+        0x00200, 0x00201, 0x00208, 0x00209, 0x00240, 0x00241, 0x00248, 0x00249,
+        0x01000, 0x01001, 0x01008, 0x01009, 0x01040, 0x01041, 0x01048, 0x01049,
+        0x01200, 0x01201, 0x01208, 0x01209, 0x01240, 0x01241, 0x01248, 0x01249,
+        0x08000, 0x08001, 0x08008, 0x08009, 0x08040, 0x08041, 0x08048, 0x08049,
+        0x08200, 0x08201, 0x08208, 0x08209, 0x08240, 0x08241, 0x08248, 0x08249,
+        0x09000, 0x09001, 0x09008, 0x09009, 0x09040, 0x09041, 0x09048, 0x09049,
+        0x09200, 0x09201, 0x09208, 0x09209, 0x09240, 0x09241, 0x09248, 0x09249,
+        0x40000, 0x40001, 0x40008, 0x40009, 0x40040, 0x40041, 0x40048, 0x40049,
+        0x40200, 0x40201, 0x40208, 0x40209, 0x40240, 0x40241, 0x40248, 0x40249,
+        0x41000, 0x41001, 0x41008, 0x41009, 0x41040, 0x41041, 0x41048, 0x41049,
+        0x41200, 0x41201, 0x41208, 0x41209, 0x41240, 0x41241, 0x41248, 0x41249,
+        0x48000, 0x48001, 0x48008, 0x48009, 0x48040, 0x48041, 0x48048, 0x48049,
+        0x48200, 0x48201, 0x48208, 0x48209, 0x48240, 0x48241, 0x48248, 0x48249,
+        0x49000, 0x49001, 0x49008, 0x49009, 0x49040, 0x49041, 0x49048, 0x49049,
+        0x49200, 0x49201, 0x49208, 0x49209, 0x49240, 0x49241, 0x49248, 0x49249
+    };
+
+    /*
+     * This expands 8 bit indices into 32 bit contents (high bit 28), by inserting 0s between bits.
+     */
+    private static final int[] INTERLEAVE4_TABLE = new int[]
+    {
+        0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100, 0x00000101, 0x00000110, 0x00000111,
+        0x00001000, 0x00001001, 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110, 0x00001111,
+        0x00010000, 0x00010001, 0x00010010, 0x00010011, 0x00010100, 0x00010101, 0x00010110, 0x00010111,
+        0x00011000, 0x00011001, 0x00011010, 0x00011011, 0x00011100, 0x00011101, 0x00011110, 0x00011111,
+        0x00100000, 0x00100001, 0x00100010, 0x00100011, 0x00100100, 0x00100101, 0x00100110, 0x00100111,
+        0x00101000, 0x00101001, 0x00101010, 0x00101011, 0x00101100, 0x00101101, 0x00101110, 0x00101111,
+        0x00110000, 0x00110001, 0x00110010, 0x00110011, 0x00110100, 0x00110101, 0x00110110, 0x00110111,
+        0x00111000, 0x00111001, 0x00111010, 0x00111011, 0x00111100, 0x00111101, 0x00111110, 0x00111111,
+        0x01000000, 0x01000001, 0x01000010, 0x01000011, 0x01000100, 0x01000101, 0x01000110, 0x01000111,
+        0x01001000, 0x01001001, 0x01001010, 0x01001011, 0x01001100, 0x01001101, 0x01001110, 0x01001111,
+        0x01010000, 0x01010001, 0x01010010, 0x01010011, 0x01010100, 0x01010101, 0x01010110, 0x01010111,
+        0x01011000, 0x01011001, 0x01011010, 0x01011011, 0x01011100, 0x01011101, 0x01011110, 0x01011111,
+        0x01100000, 0x01100001, 0x01100010, 0x01100011, 0x01100100, 0x01100101, 0x01100110, 0x01100111,
+        0x01101000, 0x01101001, 0x01101010, 0x01101011, 0x01101100, 0x01101101, 0x01101110, 0x01101111,
+        0x01110000, 0x01110001, 0x01110010, 0x01110011, 0x01110100, 0x01110101, 0x01110110, 0x01110111,
+        0x01111000, 0x01111001, 0x01111010, 0x01111011, 0x01111100, 0x01111101, 0x01111110, 0x01111111,
+        0x10000000, 0x10000001, 0x10000010, 0x10000011, 0x10000100, 0x10000101, 0x10000110, 0x10000111,
+        0x10001000, 0x10001001, 0x10001010, 0x10001011, 0x10001100, 0x10001101, 0x10001110, 0x10001111,
+        0x10010000, 0x10010001, 0x10010010, 0x10010011, 0x10010100, 0x10010101, 0x10010110, 0x10010111,
+        0x10011000, 0x10011001, 0x10011010, 0x10011011, 0x10011100, 0x10011101, 0x10011110, 0x10011111,
+        0x10100000, 0x10100001, 0x10100010, 0x10100011, 0x10100100, 0x10100101, 0x10100110, 0x10100111,
+        0x10101000, 0x10101001, 0x10101010, 0x10101011, 0x10101100, 0x10101101, 0x10101110, 0x10101111,
+        0x10110000, 0x10110001, 0x10110010, 0x10110011, 0x10110100, 0x10110101, 0x10110110, 0x10110111,
+        0x10111000, 0x10111001, 0x10111010, 0x10111011, 0x10111100, 0x10111101, 0x10111110, 0x10111111,
+        0x11000000, 0x11000001, 0x11000010, 0x11000011, 0x11000100, 0x11000101, 0x11000110, 0x11000111,
+        0x11001000, 0x11001001, 0x11001010, 0x11001011, 0x11001100, 0x11001101, 0x11001110, 0x11001111,
+        0x11010000, 0x11010001, 0x11010010, 0x11010011, 0x11010100, 0x11010101, 0x11010110, 0x11010111,
+        0x11011000, 0x11011001, 0x11011010, 0x11011011, 0x11011100, 0x11011101, 0x11011110, 0x11011111,
+        0x11100000, 0x11100001, 0x11100010, 0x11100011, 0x11100100, 0x11100101, 0x11100110, 0x11100111,
+        0x11101000, 0x11101001, 0x11101010, 0x11101011, 0x11101100, 0x11101101, 0x11101110, 0x11101111,
+        0x11110000, 0x11110001, 0x11110010, 0x11110011, 0x11110100, 0x11110101, 0x11110110, 0x11110111,
+        0x11111000, 0x11111001, 0x11111010, 0x11111011, 0x11111100, 0x11111101, 0x11111110, 0x11111111
+    };
+
+    /*
+     * This expands 7 bit indices into 35 bit contents (high bit 30), by inserting 0s between bits.
+     */
+    private static final int[] INTERLEAVE5_TABLE = new int[] {
+        0x00000000, 0x00000001, 0x00000020, 0x00000021, 0x00000400, 0x00000401, 0x00000420, 0x00000421,
+        0x00008000, 0x00008001, 0x00008020, 0x00008021, 0x00008400, 0x00008401, 0x00008420, 0x00008421,
+        0x00100000, 0x00100001, 0x00100020, 0x00100021, 0x00100400, 0x00100401, 0x00100420, 0x00100421,
+        0x00108000, 0x00108001, 0x00108020, 0x00108021, 0x00108400, 0x00108401, 0x00108420, 0x00108421,
+        0x02000000, 0x02000001, 0x02000020, 0x02000021, 0x02000400, 0x02000401, 0x02000420, 0x02000421,
+        0x02008000, 0x02008001, 0x02008020, 0x02008021, 0x02008400, 0x02008401, 0x02008420, 0x02008421,
+        0x02100000, 0x02100001, 0x02100020, 0x02100021, 0x02100400, 0x02100401, 0x02100420, 0x02100421,
+        0x02108000, 0x02108001, 0x02108020, 0x02108021, 0x02108400, 0x02108401, 0x02108420, 0x02108421,
+        0x40000000, 0x40000001, 0x40000020, 0x40000021, 0x40000400, 0x40000401, 0x40000420, 0x40000421,
+        0x40008000, 0x40008001, 0x40008020, 0x40008021, 0x40008400, 0x40008401, 0x40008420, 0x40008421,
+        0x40100000, 0x40100001, 0x40100020, 0x40100021, 0x40100400, 0x40100401, 0x40100420, 0x40100421,
+        0x40108000, 0x40108001, 0x40108020, 0x40108021, 0x40108400, 0x40108401, 0x40108420, 0x40108421,
+        0x42000000, 0x42000001, 0x42000020, 0x42000021, 0x42000400, 0x42000401, 0x42000420, 0x42000421,
+        0x42008000, 0x42008001, 0x42008020, 0x42008021, 0x42008400, 0x42008401, 0x42008420, 0x42008421,
+        0x42100000, 0x42100001, 0x42100020, 0x42100021, 0x42100400, 0x42100401, 0x42100420, 0x42100421,
+        0x42108000, 0x42108001, 0x42108020, 0x42108021, 0x42108400, 0x42108401, 0x42108420, 0x42108421
+    };
+
+    /*
+     * This expands 9 bit indices into 63 bit (long) contents (high bit 56), by inserting 0s between bits.
+     */
+    private static final long[] INTERLEAVE7_TABLE = new long[]
+    {
+        0x0000000000000000L, 0x0000000000000001L, 0x0000000000000080L, 0x0000000000000081L,
+        0x0000000000004000L, 0x0000000000004001L, 0x0000000000004080L, 0x0000000000004081L,
+        0x0000000000200000L, 0x0000000000200001L, 0x0000000000200080L, 0x0000000000200081L,
+        0x0000000000204000L, 0x0000000000204001L, 0x0000000000204080L, 0x0000000000204081L,
+        0x0000000010000000L, 0x0000000010000001L, 0x0000000010000080L, 0x0000000010000081L,
+        0x0000000010004000L, 0x0000000010004001L, 0x0000000010004080L, 0x0000000010004081L,
+        0x0000000010200000L, 0x0000000010200001L, 0x0000000010200080L, 0x0000000010200081L,
+        0x0000000010204000L, 0x0000000010204001L, 0x0000000010204080L, 0x0000000010204081L,
+        0x0000000800000000L, 0x0000000800000001L, 0x0000000800000080L, 0x0000000800000081L,
+        0x0000000800004000L, 0x0000000800004001L, 0x0000000800004080L, 0x0000000800004081L,
+        0x0000000800200000L, 0x0000000800200001L, 0x0000000800200080L, 0x0000000800200081L,
+        0x0000000800204000L, 0x0000000800204001L, 0x0000000800204080L, 0x0000000800204081L,
+        0x0000000810000000L, 0x0000000810000001L, 0x0000000810000080L, 0x0000000810000081L,
+        0x0000000810004000L, 0x0000000810004001L, 0x0000000810004080L, 0x0000000810004081L,
+        0x0000000810200000L, 0x0000000810200001L, 0x0000000810200080L, 0x0000000810200081L,
+        0x0000000810204000L, 0x0000000810204001L, 0x0000000810204080L, 0x0000000810204081L,
+        0x0000040000000000L, 0x0000040000000001L, 0x0000040000000080L, 0x0000040000000081L,
+        0x0000040000004000L, 0x0000040000004001L, 0x0000040000004080L, 0x0000040000004081L,
+        0x0000040000200000L, 0x0000040000200001L, 0x0000040000200080L, 0x0000040000200081L,
+        0x0000040000204000L, 0x0000040000204001L, 0x0000040000204080L, 0x0000040000204081L,
+        0x0000040010000000L, 0x0000040010000001L, 0x0000040010000080L, 0x0000040010000081L,
+        0x0000040010004000L, 0x0000040010004001L, 0x0000040010004080L, 0x0000040010004081L,
+        0x0000040010200000L, 0x0000040010200001L, 0x0000040010200080L, 0x0000040010200081L,
+        0x0000040010204000L, 0x0000040010204001L, 0x0000040010204080L, 0x0000040010204081L,
+        0x0000040800000000L, 0x0000040800000001L, 0x0000040800000080L, 0x0000040800000081L,
+        0x0000040800004000L, 0x0000040800004001L, 0x0000040800004080L, 0x0000040800004081L,
+        0x0000040800200000L, 0x0000040800200001L, 0x0000040800200080L, 0x0000040800200081L,
+        0x0000040800204000L, 0x0000040800204001L, 0x0000040800204080L, 0x0000040800204081L,
+        0x0000040810000000L, 0x0000040810000001L, 0x0000040810000080L, 0x0000040810000081L,
+        0x0000040810004000L, 0x0000040810004001L, 0x0000040810004080L, 0x0000040810004081L,
+        0x0000040810200000L, 0x0000040810200001L, 0x0000040810200080L, 0x0000040810200081L,
+        0x0000040810204000L, 0x0000040810204001L, 0x0000040810204080L, 0x0000040810204081L,
+        0x0002000000000000L, 0x0002000000000001L, 0x0002000000000080L, 0x0002000000000081L,
+        0x0002000000004000L, 0x0002000000004001L, 0x0002000000004080L, 0x0002000000004081L,
+        0x0002000000200000L, 0x0002000000200001L, 0x0002000000200080L, 0x0002000000200081L,
+        0x0002000000204000L, 0x0002000000204001L, 0x0002000000204080L, 0x0002000000204081L,
+        0x0002000010000000L, 0x0002000010000001L, 0x0002000010000080L, 0x0002000010000081L,
+        0x0002000010004000L, 0x0002000010004001L, 0x0002000010004080L, 0x0002000010004081L,
+        0x0002000010200000L, 0x0002000010200001L, 0x0002000010200080L, 0x0002000010200081L,
+        0x0002000010204000L, 0x0002000010204001L, 0x0002000010204080L, 0x0002000010204081L,
+        0x0002000800000000L, 0x0002000800000001L, 0x0002000800000080L, 0x0002000800000081L,
+        0x0002000800004000L, 0x0002000800004001L, 0x0002000800004080L, 0x0002000800004081L,
+        0x0002000800200000L, 0x0002000800200001L, 0x0002000800200080L, 0x0002000800200081L,
+        0x0002000800204000L, 0x0002000800204001L, 0x0002000800204080L, 0x0002000800204081L,
+        0x0002000810000000L, 0x0002000810000001L, 0x0002000810000080L, 0x0002000810000081L,
+        0x0002000810004000L, 0x0002000810004001L, 0x0002000810004080L, 0x0002000810004081L,
+        0x0002000810200000L, 0x0002000810200001L, 0x0002000810200080L, 0x0002000810200081L,
+        0x0002000810204000L, 0x0002000810204001L, 0x0002000810204080L, 0x0002000810204081L,
+        0x0002040000000000L, 0x0002040000000001L, 0x0002040000000080L, 0x0002040000000081L,
+        0x0002040000004000L, 0x0002040000004001L, 0x0002040000004080L, 0x0002040000004081L,
+        0x0002040000200000L, 0x0002040000200001L, 0x0002040000200080L, 0x0002040000200081L,
+        0x0002040000204000L, 0x0002040000204001L, 0x0002040000204080L, 0x0002040000204081L,
+        0x0002040010000000L, 0x0002040010000001L, 0x0002040010000080L, 0x0002040010000081L,
+        0x0002040010004000L, 0x0002040010004001L, 0x0002040010004080L, 0x0002040010004081L,
+        0x0002040010200000L, 0x0002040010200001L, 0x0002040010200080L, 0x0002040010200081L,
+        0x0002040010204000L, 0x0002040010204001L, 0x0002040010204080L, 0x0002040010204081L,
+        0x0002040800000000L, 0x0002040800000001L, 0x0002040800000080L, 0x0002040800000081L,
+        0x0002040800004000L, 0x0002040800004001L, 0x0002040800004080L, 0x0002040800004081L,
+        0x0002040800200000L, 0x0002040800200001L, 0x0002040800200080L, 0x0002040800200081L,
+        0x0002040800204000L, 0x0002040800204001L, 0x0002040800204080L, 0x0002040800204081L,
+        0x0002040810000000L, 0x0002040810000001L, 0x0002040810000080L, 0x0002040810000081L,
+        0x0002040810004000L, 0x0002040810004001L, 0x0002040810004080L, 0x0002040810004081L,
+        0x0002040810200000L, 0x0002040810200001L, 0x0002040810200080L, 0x0002040810200081L,
+        0x0002040810204000L, 0x0002040810204001L, 0x0002040810204080L, 0x0002040810204081L,
+        0x0100000000000000L, 0x0100000000000001L, 0x0100000000000080L, 0x0100000000000081L,
+        0x0100000000004000L, 0x0100000000004001L, 0x0100000000004080L, 0x0100000000004081L,
+        0x0100000000200000L, 0x0100000000200001L, 0x0100000000200080L, 0x0100000000200081L,
+        0x0100000000204000L, 0x0100000000204001L, 0x0100000000204080L, 0x0100000000204081L,
+        0x0100000010000000L, 0x0100000010000001L, 0x0100000010000080L, 0x0100000010000081L,
+        0x0100000010004000L, 0x0100000010004001L, 0x0100000010004080L, 0x0100000010004081L,
+        0x0100000010200000L, 0x0100000010200001L, 0x0100000010200080L, 0x0100000010200081L,
+        0x0100000010204000L, 0x0100000010204001L, 0x0100000010204080L, 0x0100000010204081L,
+        0x0100000800000000L, 0x0100000800000001L, 0x0100000800000080L, 0x0100000800000081L,
+        0x0100000800004000L, 0x0100000800004001L, 0x0100000800004080L, 0x0100000800004081L,
+        0x0100000800200000L, 0x0100000800200001L, 0x0100000800200080L, 0x0100000800200081L,
+        0x0100000800204000L, 0x0100000800204001L, 0x0100000800204080L, 0x0100000800204081L,
+        0x0100000810000000L, 0x0100000810000001L, 0x0100000810000080L, 0x0100000810000081L,
+        0x0100000810004000L, 0x0100000810004001L, 0x0100000810004080L, 0x0100000810004081L,
+        0x0100000810200000L, 0x0100000810200001L, 0x0100000810200080L, 0x0100000810200081L,
+        0x0100000810204000L, 0x0100000810204001L, 0x0100000810204080L, 0x0100000810204081L,
+        0x0100040000000000L, 0x0100040000000001L, 0x0100040000000080L, 0x0100040000000081L,
+        0x0100040000004000L, 0x0100040000004001L, 0x0100040000004080L, 0x0100040000004081L,
+        0x0100040000200000L, 0x0100040000200001L, 0x0100040000200080L, 0x0100040000200081L,
+        0x0100040000204000L, 0x0100040000204001L, 0x0100040000204080L, 0x0100040000204081L,
+        0x0100040010000000L, 0x0100040010000001L, 0x0100040010000080L, 0x0100040010000081L,
+        0x0100040010004000L, 0x0100040010004001L, 0x0100040010004080L, 0x0100040010004081L,
+        0x0100040010200000L, 0x0100040010200001L, 0x0100040010200080L, 0x0100040010200081L,
+        0x0100040010204000L, 0x0100040010204001L, 0x0100040010204080L, 0x0100040010204081L,
+        0x0100040800000000L, 0x0100040800000001L, 0x0100040800000080L, 0x0100040800000081L,
+        0x0100040800004000L, 0x0100040800004001L, 0x0100040800004080L, 0x0100040800004081L,
+        0x0100040800200000L, 0x0100040800200001L, 0x0100040800200080L, 0x0100040800200081L,
+        0x0100040800204000L, 0x0100040800204001L, 0x0100040800204080L, 0x0100040800204081L,
+        0x0100040810000000L, 0x0100040810000001L, 0x0100040810000080L, 0x0100040810000081L,
+        0x0100040810004000L, 0x0100040810004001L, 0x0100040810004080L, 0x0100040810004081L,
+        0x0100040810200000L, 0x0100040810200001L, 0x0100040810200080L, 0x0100040810200081L,
+        0x0100040810204000L, 0x0100040810204001L, 0x0100040810204080L, 0x0100040810204081L,
+        0x0102000000000000L, 0x0102000000000001L, 0x0102000000000080L, 0x0102000000000081L,
+        0x0102000000004000L, 0x0102000000004001L, 0x0102000000004080L, 0x0102000000004081L,
+        0x0102000000200000L, 0x0102000000200001L, 0x0102000000200080L, 0x0102000000200081L,
+        0x0102000000204000L, 0x0102000000204001L, 0x0102000000204080L, 0x0102000000204081L,
+        0x0102000010000000L, 0x0102000010000001L, 0x0102000010000080L, 0x0102000010000081L,
+        0x0102000010004000L, 0x0102000010004001L, 0x0102000010004080L, 0x0102000010004081L,
+        0x0102000010200000L, 0x0102000010200001L, 0x0102000010200080L, 0x0102000010200081L,
+        0x0102000010204000L, 0x0102000010204001L, 0x0102000010204080L, 0x0102000010204081L,
+        0x0102000800000000L, 0x0102000800000001L, 0x0102000800000080L, 0x0102000800000081L,
+        0x0102000800004000L, 0x0102000800004001L, 0x0102000800004080L, 0x0102000800004081L,
+        0x0102000800200000L, 0x0102000800200001L, 0x0102000800200080L, 0x0102000800200081L,
+        0x0102000800204000L, 0x0102000800204001L, 0x0102000800204080L, 0x0102000800204081L,
+        0x0102000810000000L, 0x0102000810000001L, 0x0102000810000080L, 0x0102000810000081L,
+        0x0102000810004000L, 0x0102000810004001L, 0x0102000810004080L, 0x0102000810004081L,
+        0x0102000810200000L, 0x0102000810200001L, 0x0102000810200080L, 0x0102000810200081L,
+        0x0102000810204000L, 0x0102000810204001L, 0x0102000810204080L, 0x0102000810204081L,
+        0x0102040000000000L, 0x0102040000000001L, 0x0102040000000080L, 0x0102040000000081L,
+        0x0102040000004000L, 0x0102040000004001L, 0x0102040000004080L, 0x0102040000004081L,
+        0x0102040000200000L, 0x0102040000200001L, 0x0102040000200080L, 0x0102040000200081L,
+        0x0102040000204000L, 0x0102040000204001L, 0x0102040000204080L, 0x0102040000204081L,
+        0x0102040010000000L, 0x0102040010000001L, 0x0102040010000080L, 0x0102040010000081L,
+        0x0102040010004000L, 0x0102040010004001L, 0x0102040010004080L, 0x0102040010004081L,
+        0x0102040010200000L, 0x0102040010200001L, 0x0102040010200080L, 0x0102040010200081L,
+        0x0102040010204000L, 0x0102040010204001L, 0x0102040010204080L, 0x0102040010204081L,
+        0x0102040800000000L, 0x0102040800000001L, 0x0102040800000080L, 0x0102040800000081L,
+        0x0102040800004000L, 0x0102040800004001L, 0x0102040800004080L, 0x0102040800004081L,
+        0x0102040800200000L, 0x0102040800200001L, 0x0102040800200080L, 0x0102040800200081L,
+        0x0102040800204000L, 0x0102040800204001L, 0x0102040800204080L, 0x0102040800204081L,
+        0x0102040810000000L, 0x0102040810000001L, 0x0102040810000080L, 0x0102040810000081L,
+        0x0102040810004000L, 0x0102040810004001L, 0x0102040810004080L, 0x0102040810004081L,
+        0x0102040810200000L, 0x0102040810200001L, 0x0102040810200080L, 0x0102040810200081L,
+        0x0102040810204000L, 0x0102040810204001L, 0x0102040810204080L, 0x0102040810204081L
+    };
+
+    // For toString(); must have length 64
+    private static final String ZEROES = "0000000000000000000000000000000000000000000000000000000000000000";
+
+    final static byte[] bitLengths =
+    {
+        0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
+    };
+
+    // TODO make m fixed for the LongArray, and hence compute T once and for all
+
+    private long[] m_ints;
+
+    public LongArray(int intLen)
+    {
+        m_ints = new long[intLen];
+    }
+
+    public LongArray(long[] ints)
+    {
+        m_ints = ints;
+    }
+
+    public LongArray(long[] ints, int off, int len)
+    {
+        if (off == 0 && len == ints.length)
+        {
+            m_ints = ints;
+        }
+        else
+        {
+            m_ints = new long[len];
+            System.arraycopy(ints, off, m_ints, 0, len);
+        }
+    }
+
+    public LongArray(BigInteger bigInt)
+    {
+        if (bigInt == null || bigInt.signum() < 0)
+        {
+            throw new IllegalArgumentException("invalid F2m field value");
+        }
+
+        if (bigInt.signum() == 0)
+        {
+            m_ints = new long[] { 0L };
+            return;
+        }
+
+        byte[] barr = bigInt.toByteArray();
+        int barrLen = barr.length;
+        int barrStart = 0;
+        if (barr[0] == 0)
+        {
+            // First byte is 0 to enforce highest (=sign) bit is zero.
+            // In this case ignore barr[0].
+            barrLen--;
+            barrStart = 1;
+        }
+        int intLen = (barrLen + 7) / 8;
+        m_ints = new long[intLen];
+
+        int iarrJ = intLen - 1;
+        int rem = barrLen % 8 + barrStart;
+        long temp = 0;
+        int barrI = barrStart;
+        if (barrStart < rem)
+        {
+            for (; barrI < rem; barrI++)
+            {
+                temp <<= 8;
+                int barrBarrI = barr[barrI] & 0xFF;
+                temp |= barrBarrI;
+            }
+            m_ints[iarrJ--] = temp;
+        }
+
+        for (; iarrJ >= 0; iarrJ--)
+        {
+            temp = 0;
+            for (int i = 0; i < 8; i++)
+            {
+                temp <<= 8;
+                int barrBarrI = barr[barrI++] & 0xFF;
+                temp |= barrBarrI;
+            }
+            m_ints[iarrJ] = temp;
+        }
+    }
+
+    void copyTo(long[] z, int zOff)
+    {
+        System.arraycopy(m_ints, 0, z, zOff, m_ints.length);
+    }
+
+    public boolean isOne()
+    {
+        long[] a = m_ints;
+        if (a[0] != 1L)
+        {
+            return false;
+        }
+        for (int i = 1; i < a.length; ++i)
+        {
+            if (a[i] != 0L)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public boolean isZero()
+    {
+        long[] a = m_ints;
+        for (int i = 0; i < a.length; ++i)
+        {
+            if (a[i] != 0L)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public int getUsedLength()
+    {
+        return getUsedLengthFrom(m_ints.length);
+    }
+
+    public int getUsedLengthFrom(int from)
+    {
+        long[] a = m_ints;
+        from = Math.min(from, a.length);
+
+        if (from < 1)
+        {
+            return 0;
+        }
+
+        // Check if first element will act as sentinel
+        if (a[0] != 0)
+        {
+            while (a[--from] == 0)
+            {
+            }
+            return from + 1;
+        }
+
+        do
+        {
+            if (a[--from] != 0)
+            {
+                return from + 1;
+            }
+        }
+        while (from > 0);
+
+        return 0;
+    }
+
+    public int degree()
+    {
+        int i = m_ints.length;
+        long w;
+        do
+        {
+            if (i == 0)
+            {
+                return 0;
+            }
+            w = m_ints[--i];
+        }
+        while (w == 0);
+
+        return (i << 6) + bitLength(w);
+    }
+
+    private int degreeFrom(int limit)
+    {
+        int i = (limit + 62) >>> 6;
+        long w;
+        do
+        {
+            if (i == 0)
+            {
+                return 0;
+            }
+            w = m_ints[--i];
+        }
+        while (w == 0);
+
+        return (i << 6) + bitLength(w);
+    }
+
+//    private int lowestCoefficient()
+//    {
+//        for (int i = 0; i < m_ints.length; ++i)
+//        {
+//            long mi = m_ints[i];
+//            if (mi != 0)
+//            {
+//                int j = 0;
+//                while ((mi & 0xFFL) == 0)
+//                {
+//                    j += 8;
+//                    mi >>>= 8;
+//                }
+//                while ((mi & 1L) == 0)
+//                {
+//                    ++j;
+//                    mi >>>= 1;
+//                }
+//                return (i << 6) + j;
+//            }
+//        }
+//        return -1;
+//    }
+
+    private static int bitLength(long w)
+    {
+        int u = (int)(w >>> 32), b;
+        if (u == 0)
+        {
+            u = (int)w;
+            b = 0;
+        }
+        else
+        {
+            b = 32;
+        }
+
+        int t = u >>> 16, k;
+        if (t == 0)
+        {
+            t = u >>> 8;
+            k = (t == 0) ? bitLengths[u] : 8 + bitLengths[t];
+        }
+        else
+        {
+            int v = t >>> 8;
+            k = (v == 0) ? 16 + bitLengths[t] : 24 + bitLengths[v];
+        }
+
+        return b + k;
+    }
+
+    private long[] resizedInts(int newLen)
+    {
+        long[] newInts = new long[newLen];
+        System.arraycopy(m_ints, 0, newInts, 0, Math.min(m_ints.length, newLen));
+        return newInts;
+    }
+
+    public BigInteger toBigInteger()
+    {
+        int usedLen = getUsedLength();
+        if (usedLen == 0)
+        {
+            return ECConstants.ZERO;
+        }
+
+        long highestInt = m_ints[usedLen - 1];
+        byte[] temp = new byte[8];
+        int barrI = 0;
+        boolean trailingZeroBytesDone = false;
+        for (int j = 7; j >= 0; j--)
+        {
+            byte thisByte = (byte)(highestInt >>> (8 * j));
+            if (trailingZeroBytesDone || (thisByte != 0))
+            {
+                trailingZeroBytesDone = true;
+                temp[barrI++] = thisByte;
+            }
+        }
+
+        int barrLen = 8 * (usedLen - 1) + barrI;
+        byte[] barr = new byte[barrLen];
+        for (int j = 0; j < barrI; j++)
+        {
+            barr[j] = temp[j];
+        }
+        // Highest value int is done now
+
+        for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+        {
+            long mi = m_ints[iarrJ];
+            for (int j = 7; j >= 0; j--)
+            {
+                barr[barrI++] = (byte)(mi >>> (8 * j));
+            }
+        }
+        return new BigInteger(1, barr);
+    }
+
+//    private static long shiftUp(long[] x, int xOff, int count)
+//    {
+//        long prev = 0;
+//        for (int i = 0; i < count; ++i)
+//        {
+//            long next = x[xOff + i];
+//            x[xOff + i] = (next << 1) | prev;
+//            prev = next >>> 63;
+//        }
+//        return prev;
+//    }
+
+    private static long shiftUp(long[] x, int xOff, int count, int shift)
+    {
+        int shiftInv = 64 - shift;
+        long prev = 0;
+        for (int i = 0; i < count; ++i)
+        {
+            long next = x[xOff + i];
+            x[xOff + i] = (next << shift) | prev;
+            prev = next >>> shiftInv;
+        }
+        return prev;
+    }
+
+    private static long shiftUp(long[] x, int xOff, long[] z, int zOff, int count, int shift)
+    {
+        int shiftInv = 64 - shift;
+        long prev = 0;
+        for (int i = 0; i < count; ++i)
+        {
+            long next = x[xOff + i];
+            z[zOff + i] = (next << shift) | prev;
+            prev = next >>> shiftInv;
+        }
+        return prev;
+    }
+
+    public LongArray addOne()
+    {
+        if (m_ints.length == 0)
+        {
+            return new LongArray(new long[]{ 1L });
+        }
+
+        int resultLen = Math.max(1, getUsedLength());
+        long[] ints = resizedInts(resultLen);
+        ints[0] ^= 1L;
+        return new LongArray(ints);
+    }
+
+//    private void addShiftedByBits(LongArray other, int bits)
+//    {
+//        int words = bits >>> 6;
+//        int shift = bits & 0x3F;
+//
+//        if (shift == 0)
+//        {
+//            addShiftedByWords(other, words);
+//            return;
+//        }
+//
+//        int otherUsedLen = other.getUsedLength();
+//        if (otherUsedLen == 0)
+//        {
+//            return;
+//        }
+//
+//        int minLen = otherUsedLen + words + 1;
+//        if (minLen > m_ints.length)
+//        {
+//            m_ints = resizedInts(minLen);
+//        }
+//
+//        long carry = addShiftedByBits(m_ints, words, other.m_ints, 0, otherUsedLen, shift);
+//        m_ints[otherUsedLen + words] ^= carry;
+//    }
+
+    private void addShiftedByBitsSafe(LongArray other, int otherDegree, int bits)
+    {
+        int otherLen = (otherDegree + 63) >>> 6;
+
+        int words = bits >>> 6;
+        int shift = bits & 0x3F;
+
+        if (shift == 0)
+        {
+            add(m_ints, words, other.m_ints, 0, otherLen);
+            return;
+        }
+
+        long carry = addShiftedUp(m_ints, words, other.m_ints, 0, otherLen, shift);
+        if (carry != 0L)
+        {
+            m_ints[otherLen + words] ^= carry;
+        }
+    }
+
+    private static long addShiftedUp(long[] x, int xOff, long[] y, int yOff, int count, int shift)
+    {
+        int shiftInv = 64 - shift;
+        long prev = 0;
+        for (int i = 0; i < count; ++i)
+        {
+            long next = y[yOff + i];
+            x[xOff + i] ^= (next << shift) | prev;
+            prev = next >>> shiftInv;
+        }
+        return prev;
+    }
+
+    private static long addShiftedDown(long[] x, int xOff, long[] y, int yOff, int count, int shift)
+    {
+        int shiftInv = 64 - shift;
+        long prev = 0;
+        int i = count;
+        while (--i >= 0)
+        {
+            long next = y[yOff + i];
+            x[xOff + i] ^= (next >>> shift) | prev;
+            prev = next << shiftInv;
+        }
+        return prev;
+    }
+
+    public void addShiftedByWords(LongArray other, int words)
+    {
+        int otherUsedLen = other.getUsedLength();
+        if (otherUsedLen == 0)
+        {
+            return;
+        }
+
+        int minLen = otherUsedLen + words;
+        if (minLen > m_ints.length)
+        {
+            m_ints = resizedInts(minLen);
+        }
+
+        add(m_ints, words, other.m_ints, 0, otherUsedLen);
+    }
+
+    private static void add(long[] x, int xOff, long[] y, int yOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            x[xOff + i] ^= y[yOff + i];
+        }
+    }
+
+    private static void add(long[] x, int xOff, long[] y, int yOff, long[] z, int zOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            z[zOff + i] = x[xOff + i] ^ y[yOff + i];
+        }
+    }
+
+    private static void addBoth(long[] x, int xOff, long[] y1, int y1Off, long[] y2, int y2Off, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            x[xOff + i] ^= y1[y1Off + i] ^ y2[y2Off + i];
+        }
+    }
+
+    private static void distribute(long[] x, int src, int dst1, int dst2, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            long v = x[src + i];
+            x[dst1 + i] ^= v;
+            x[dst2 + i] ^= v;
+        }
+    }
+
+    public int getLength()
+    {
+        return m_ints.length;
+    }
+
+    private static void flipWord(long[] buf, int off, int bit, long word)
+    {
+        int n = off + (bit >>> 6);
+        int shift = bit & 0x3F;
+        if (shift == 0)
+        {
+            buf[n] ^= word;
+        }
+        else
+        {
+            buf[n] ^= word << shift;
+            word >>>= (64 - shift);
+            if (word != 0)
+            {
+                buf[++n] ^= word;
+            }
+        }
+    }
+
+//    private static long getWord(long[] buf, int off, int len, int bit)
+//    {
+//        int n = off + (bit >>> 6);
+//        int shift = bit & 0x3F;
+//        if (shift == 0)
+//        {
+//            return buf[n];
+//        }
+//        long result = buf[n] >>> shift;
+//        if (++n < len)
+//        {
+//            result |= buf[n] << (64 - shift);
+//        }
+//        return result;
+//    }
+
+    public boolean testBitZero()
+    {
+        return m_ints.length > 0 && (m_ints[0] & 1L) != 0;
+    }
+
+    private static boolean testBit(long[] buf, int off, int n)
+    {
+        // theInt = n / 64
+        int theInt = n >>> 6;
+        // theBit = n % 64
+        int theBit = n & 0x3F;
+        long tester = 1L << theBit;
+        return (buf[off + theInt] & tester) != 0;
+    }
+
+    private static void flipBit(long[] buf, int off, int n)
+    {
+        // theInt = n / 64
+        int theInt = n >>> 6;
+        // theBit = n % 64
+        int theBit = n & 0x3F;
+        long flipper = 1L << theBit;
+        buf[off + theInt] ^= flipper;
+    }
+
+//    private static void setBit(long[] buf, int off, int n)
+//    {
+//        // theInt = n / 64
+//        int theInt = n >>> 6;
+//        // theBit = n % 64
+//        int theBit = n & 0x3F;
+//        long setter = 1L << theBit;
+//        buf[off + theInt] |= setter;
+//    }
+//
+//    private static void clearBit(long[] buf, int off, int n)
+//    {
+//        // theInt = n / 64
+//        int theInt = n >>> 6;
+//        // theBit = n % 64
+//        int theBit = n & 0x3F;
+//        long setter = 1L << theBit;
+//        buf[off + theInt] &= ~setter;
+//    }
+
+    private static void multiplyWord(long a, long[] b, int bLen, long[] c, int cOff)
+    {
+        if ((a & 1L) != 0L)
+        {
+            add(c, cOff, b, 0, bLen);
+        }
+        int k = 1;
+        while ((a >>>= 1) != 0L)
+        {
+            if ((a & 1L) != 0L)
+            {
+                long carry = addShiftedUp(c, cOff, b, 0, bLen, k);
+                if (carry != 0L)
+                {
+                    c[cOff + bLen] ^= carry;
+                }
+            }
+            ++k;
+        }
+    }
+
+    public LongArray modMultiplyLD(LongArray other, int m, int[] ks)
+    {
+        /*
+         * Find out the degree of each argument and handle the zero cases
+         */
+        int aDeg = degree();
+        if (aDeg == 0)
+        {
+            return this;
+        }
+        int bDeg = other.degree();
+        if (bDeg == 0)
+        {
+            return other;
+        }
+
+        /*
+         * Swap if necessary so that A is the smaller argument
+         */
+        LongArray A = this, B = other;
+        if (aDeg > bDeg)
+        {
+            A = other; B = this;
+            int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+        }
+
+        /*
+         * Establish the word lengths of the arguments and result
+         */
+        int aLen = (aDeg + 63) >>> 6;
+        int bLen = (bDeg + 63) >>> 6;
+        int cLen = (aDeg + bDeg + 62) >>> 6;
+
+        if (aLen == 1)
+        {
+            long a0 = A.m_ints[0];
+            if (a0 == 1L)
+            {
+                return B;
+            }
+
+            /*
+             * Fast path for small A, with performance dependent only on the number of set bits
+             */
+            long[] c0 = new long[cLen];
+            multiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+            /*
+             * Reduce the raw answer against the reduction coefficients
+             */
+            return reduceResult(c0, 0, cLen, m, ks);
+        }
+
+        /*
+         * Determine if B will get bigger during shifting
+         */
+        int bMax = (bDeg + 7 + 63) >>> 6;
+
+        /*
+         * Lookup table for the offset of each B in the tables
+         */
+        int[] ti = new int[16];
+
+        /*
+         * Precompute table of all 4-bit products of B
+         */
+        long[] T0 = new long[bMax << 4];
+        int tOff = bMax;
+        ti[1] = tOff;
+        System.arraycopy(B.m_ints, 0, T0, tOff, bLen);
+        for (int i = 2; i < 16; ++i)
+        {
+            ti[i] = (tOff += bMax);
+            if ((i & 1) == 0)
+            {
+                shiftUp(T0, tOff >>> 1, T0, tOff, bMax, 1);
+            }
+            else
+            {
+                add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
+            }
+        }
+
+        /*
+         * Second table with all 4-bit products of B shifted 4 bits
+         */
+        long[] T1 = new long[T0.length];
+        shiftUp(T0, 0, T1, 0, T0.length, 4);
+//        shiftUp(T0, bMax, T1, bMax, tOff, 4);
+
+        long[] a = A.m_ints;
+        long[] c = new long[cLen];
+
+        int MASK = 0xF;
+
+        /*
+         * Lopez-Dahab algorithm
+         */
+
+        for (int k = 56; k >= 0; k -= 8)
+        {
+            for (int j = 1; j < aLen; j += 2)
+            {
+                int aVal = (int)(a[j] >>> k);
+                int u = aVal & MASK;
+                int v = (aVal >>> 4) & MASK;
+                addBoth(c, j - 1, T0, ti[u], T1, ti[v], bMax);
+            }
+            shiftUp(c, 0, cLen, 8);
+        }
+
+        for (int k = 56; k >= 0; k -= 8)
+        {
+            for (int j = 0; j < aLen; j += 2)
+            {
+                int aVal = (int)(a[j] >>> k);
+                int u = aVal & MASK;
+                int v = (aVal >>> 4) & MASK;
+                addBoth(c, j, T0, ti[u], T1, ti[v], bMax);
+            }
+            if (k > 0)
+            {
+                shiftUp(c, 0, cLen, 8);
+            }
+        }
+
+        /*
+         * Finally the raw answer is collected, reduce it against the reduction coefficients
+         */
+        return reduceResult(c, 0, cLen, m, ks);
+    }
+
+    public LongArray modMultiply(LongArray other, int m, int[] ks)
+    {
+        /*
+         * Find out the degree of each argument and handle the zero cases
+         */
+        int aDeg = degree();
+        if (aDeg == 0)
+        {
+            return this;
+        }
+        int bDeg = other.degree();
+        if (bDeg == 0)
+        {
+            return other;
+        }
+
+        /*
+         * Swap if necessary so that A is the smaller argument
+         */
+        LongArray A = this, B = other;
+        if (aDeg > bDeg)
+        {
+            A = other; B = this;
+            int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+        }
+
+        /*
+         * Establish the word lengths of the arguments and result
+         */
+        int aLen = (aDeg + 63) >>> 6;
+        int bLen = (bDeg + 63) >>> 6;
+        int cLen = (aDeg + bDeg + 62) >>> 6;
+
+        if (aLen == 1)
+        {
+            long a0 = A.m_ints[0];
+            if (a0 == 1L)
+            {
+                return B;
+            }
+
+            /*
+             * Fast path for small A, with performance dependent only on the number of set bits
+             */
+            long[] c0 = new long[cLen];
+            multiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+            /*
+             * Reduce the raw answer against the reduction coefficients
+             */
+            return reduceResult(c0, 0, cLen, m, ks);
+        }
+
+        /*
+         * Determine if B will get bigger during shifting
+         */
+        int bMax = (bDeg + 7 + 63) >>> 6;
+
+        /*
+         * Lookup table for the offset of each B in the tables
+         */
+        int[] ti = new int[16];
+
+        /*
+         * Precompute table of all 4-bit products of B
+         */
+        long[] T0 = new long[bMax << 4];
+        int tOff = bMax;
+        ti[1] = tOff;
+        System.arraycopy(B.m_ints, 0, T0, tOff, bLen);
+        for (int i = 2; i < 16; ++i)
+        {
+            ti[i] = (tOff += bMax);
+            if ((i & 1) == 0)
+            {
+                shiftUp(T0, tOff >>> 1, T0, tOff, bMax, 1);
+            }
+            else
+            {
+                add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
+            }
+        }
+
+        /*
+         * Second table with all 4-bit products of B shifted 4 bits
+         */
+        long[] T1 = new long[T0.length];
+        shiftUp(T0, 0, T1, 0, T0.length, 4);
+//        shiftUp(T0, bMax, T1, bMax, tOff, 4);
+
+        long[] a = A.m_ints;
+        long[] c = new long[cLen << 3];
+
+        int MASK = 0xF;
+
+        /*
+         * Lopez-Dahab (Modified) algorithm
+         */
+
+        for (int aPos = 0; aPos < aLen; ++aPos)
+        {
+            long aVal = a[aPos];
+            int cOff = aPos;
+            for (;;)
+            {
+                int u = (int)aVal & MASK;
+                aVal >>>= 4;
+                int v = (int)aVal & MASK;
+                addBoth(c, cOff, T0, ti[u], T1, ti[v], bMax);
+                aVal >>>= 4;
+                if (aVal == 0L)
+                {
+                    break;
+                }
+                cOff += cLen;
+            }
+        }
+
+        {
+            int cOff = c.length;
+            while ((cOff -= cLen) != 0)
+            {
+                addShiftedUp(c, cOff - cLen, c, cOff, cLen, 8);
+            }
+        }
+
+        /*
+         * Finally the raw answer is collected, reduce it against the reduction coefficients
+         */
+        return reduceResult(c, 0, cLen, m, ks);
+    }
+
+    public LongArray modMultiplyAlt(LongArray other, int m, int[] ks)
+    {
+        /*
+         * Find out the degree of each argument and handle the zero cases
+         */
+        int aDeg = degree();
+        if (aDeg == 0)
+        {
+            return this;
+        }
+        int bDeg = other.degree();
+        if (bDeg == 0)
+        {
+            return other;
+        }
+
+        /*
+         * Swap if necessary so that A is the smaller argument
+         */
+        LongArray A = this, B = other;
+        if (aDeg > bDeg)
+        {
+            A = other; B = this;
+            int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+        }
+
+        /*
+         * Establish the word lengths of the arguments and result
+         */
+        int aLen = (aDeg + 63) >>> 6;
+        int bLen = (bDeg + 63) >>> 6;
+        int cLen = (aDeg + bDeg + 62) >>> 6;
+
+        if (aLen == 1)
+        {
+            long a0 = A.m_ints[0];
+            if (a0 == 1L)
+            {
+                return B;
+            }
+
+            /*
+             * Fast path for small A, with performance dependent only on the number of set bits
+             */
+            long[] c0 = new long[cLen];
+            multiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+            /*
+             * Reduce the raw answer against the reduction coefficients
+             */
+            return reduceResult(c0, 0, cLen, m, ks);
+        }
+
+        // NOTE: This works, but is slower than width 4 processing
+//        if (aLen == 2)
+//        {
+//            /*
+//             * Use common-multiplicand optimization to save ~1/4 of the adds
+//             */
+//            long a1 = A.m_ints[0], a2 = A.m_ints[1];
+//            long aa = a1 & a2; a1 ^= aa; a2 ^= aa;
+//
+//            long[] b = B.m_ints;
+//            long[] c = new long[cLen];
+//            multiplyWord(aa, b, bLen, c, 1);
+//            add(c, 0, c, 1, cLen - 1);
+//            multiplyWord(a1, b, bLen, c, 0);
+//            multiplyWord(a2, b, bLen, c, 1);
+//
+//            /*
+//             * Reduce the raw answer against the reduction coefficients
+//             */
+//            return reduceResult(c, 0, cLen, m, ks);
+//        }
+
+        /*
+         * Determine the parameters of the interleaved window algorithm: the 'width' in bits to
+         * process together, the number of evaluation 'positions' implied by that width, and the
+         * 'top' position at which the regular window algorithm stops.
+         */
+        int width, positions, top, banks;
+
+        // NOTE: width 4 is the fastest over the entire range of sizes used in current crypto 
+//        width = 1; positions = 64; top = 64; banks = 4;
+//        width = 2; positions = 32; top = 64; banks = 4;
+//        width = 3; positions = 21; top = 63; banks = 3;
+        width = 4; positions = 16; top = 64; banks = 8;
+//        width = 5; positions = 13; top = 65; banks = 7;
+//        width = 7; positions = 9; top = 63; banks = 9;
+//        width = 8; positions = 8; top = 64; banks = 8;
+
+        /*
+         * Determine if B will get bigger during shifting
+         */
+        int shifts = top < 64 ? positions : positions - 1;
+        int bMax = (bDeg + shifts + 63) >>> 6;
+
+        int bTotal = bMax * banks, stride = width * banks;
+
+        /*
+         * Create a single temporary buffer, with an offset table to find the positions of things in it 
+         */
+        int[] ci = new int[1 << width];
+        int cTotal = aLen;
+        {
+            ci[0] = cTotal;
+            cTotal += bTotal;
+            ci[1] = cTotal;
+            for (int i = 2; i < ci.length; ++i)
+            {
+                cTotal += cLen;
+                ci[i] = cTotal;
+            }
+            cTotal += cLen;
+        }
+        // NOTE: Provide a safe dump for "high zeroes" since we are adding 'bMax' and not 'bLen'
+        ++cTotal;
+
+        long[] c = new long[cTotal];
+
+        // Prepare A in interleaved form, according to the chosen width
+        interleave(A.m_ints, 0, c, 0, aLen, width);
+
+        // Make a working copy of B, since we will be shifting it
+        {
+            int bOff = aLen;
+            System.arraycopy(B.m_ints, 0, c, bOff, bLen);
+            for (int bank = 1; bank < banks; ++bank)
+            {
+                shiftUp(c, aLen, c, bOff += bMax, bMax, bank);
+            }
+        }
+
+        /*
+         * The main loop analyzes the interleaved windows in A, and for each non-zero window
+         * a single word-array XOR is performed to a carefully selected slice of 'c'. The loop is
+         * breadth-first, checking the lowest window in each word, then looping again for the
+         * next higher window position.
+         */
+        int MASK = (1 << width) - 1;
+
+        int k = 0;
+        for (;;)
+        {
+            int aPos = 0;
+            do
+            {
+                long aVal = c[aPos] >>> k;
+                int bank = 0, bOff = aLen;
+                for (;;)
+                {
+                    int index = (int)(aVal) & MASK;
+                    if (index != 0)
+                    {
+                        /*
+                         * Add to a 'c' buffer based on the bit-pattern of 'index'. Since A is in
+                         * interleaved form, the bits represent the current B shifted by 0, 'positions',
+                         * 'positions' * 2, ..., 'positions' * ('width' - 1)
+                         */
+                        add(c, aPos + ci[index], c, bOff, bMax);
+                    }
+                    if (++bank == banks)
+                    {
+                        break;
+                    }
+                    bOff += bMax;
+                    aVal >>>= width;
+                }
+            }
+            while (++aPos < aLen);
+
+            if ((k += stride) >= top)
+            {
+                if (k >= 64)
+                {
+                    break;
+                }
+
+                /*
+                 * Adjustment for window setups with top == 63, the final bit (if any) is processed
+                 * as the top-bit of a window
+                 */
+                k = 64 - width;
+                MASK &= MASK << (top - k);
+            }
+
+            /*
+             * After each position has been checked for all words of A, B is shifted up 1 place
+             */
+            shiftUp(c, aLen, bTotal, banks);
+        }
+
+        int ciPos = ci.length;
+        while (--ciPos > 1)
+        {
+            if ((ciPos & 1L) == 0L)
+            {
+                /*
+                 * For even numbers, shift contents and add to the half-position
+                 */
+                addShiftedUp(c, ci[ciPos >>> 1], c, ci[ciPos], cLen, positions);
+            }
+            else
+            {
+                /*
+                 * For odd numbers, 'distribute' contents to the result and the next-lowest position
+                 */
+                distribute(c, ci[ciPos], ci[ciPos - 1], ci[1], cLen);
+            }
+        }
+
+        /*
+         * Finally the raw answer is collected, reduce it against the reduction coefficients
+         */
+        return reduceResult(c, ci[1], cLen, m, ks);
+    }
+
+    public LongArray modReduce(int m, int[] ks)
+    {
+        long[] buf = Arrays.clone(m_ints);
+        int rLen = reduceInPlace(buf, 0, buf.length, m, ks);
+        return new LongArray(buf, 0, rLen);
+    }
+
+    public LongArray multiply(LongArray other, int m, int[] ks)
+    {
+        /*
+         * Find out the degree of each argument and handle the zero cases
+         */
+        int aDeg = degree();
+        if (aDeg == 0)
+        {
+            return this;
+        }
+        int bDeg = other.degree();
+        if (bDeg == 0)
+        {
+            return other;
+        }
+
+        /*
+         * Swap if necessary so that A is the smaller argument
+         */
+        LongArray A = this, B = other;
+        if (aDeg > bDeg)
+        {
+            A = other; B = this;
+            int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+        }
+
+        /*
+         * Establish the word lengths of the arguments and result
+         */
+        int aLen = (aDeg + 63) >>> 6;
+        int bLen = (bDeg + 63) >>> 6;
+        int cLen = (aDeg + bDeg + 62) >>> 6;
+
+        if (aLen == 1)
+        {
+            long a0 = A.m_ints[0];
+            if (a0 == 1L)
+            {
+                return B;
+            }
+
+            /*
+             * Fast path for small A, with performance dependent only on the number of set bits
+             */
+            long[] c0 = new long[cLen];
+            multiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+            /*
+             * Reduce the raw answer against the reduction coefficients
+             */
+//            return reduceResult(c0, 0, cLen, m, ks);
+            return new LongArray(c0, 0, cLen);
+        }
+
+        /*
+         * Determine if B will get bigger during shifting
+         */
+        int bMax = (bDeg + 7 + 63) >>> 6;
+
+        /*
+         * Lookup table for the offset of each B in the tables
+         */
+        int[] ti = new int[16];
+
+        /*
+         * Precompute table of all 4-bit products of B
+         */
+        long[] T0 = new long[bMax << 4];
+        int tOff = bMax;
+        ti[1] = tOff;
+        System.arraycopy(B.m_ints, 0, T0, tOff, bLen);
+        for (int i = 2; i < 16; ++i)
+        {
+            ti[i] = (tOff += bMax);
+            if ((i & 1) == 0)
+            {
+                shiftUp(T0, tOff >>> 1, T0, tOff, bMax, 1);
+            }
+            else
+            {
+                add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
+            }
+        }
+
+        /*
+         * Second table with all 4-bit products of B shifted 4 bits
+         */
+        long[] T1 = new long[T0.length];
+        shiftUp(T0, 0, T1, 0, T0.length, 4);
+//        shiftUp(T0, bMax, T1, bMax, tOff, 4);
+
+        long[] a = A.m_ints;
+        long[] c = new long[cLen << 3];
+
+        int MASK = 0xF;
+
+        /*
+         * Lopez-Dahab (Modified) algorithm
+         */
+
+        for (int aPos = 0; aPos < aLen; ++aPos)
+        {
+            long aVal = a[aPos];
+            int cOff = aPos;
+            for (;;)
+            {
+                int u = (int)aVal & MASK;
+                aVal >>>= 4;
+                int v = (int)aVal & MASK;
+                addBoth(c, cOff, T0, ti[u], T1, ti[v], bMax);
+                aVal >>>= 4;
+                if (aVal == 0L)
+                {
+                    break;
+                }
+                cOff += cLen;
+            }
+        }
+
+        {
+            int cOff = c.length;
+            while ((cOff -= cLen) != 0)
+            {
+                addShiftedUp(c, cOff - cLen, c, cOff, cLen, 8);
+            }
+        }
+
+        /*
+         * Finally the raw answer is collected, reduce it against the reduction coefficients
+         */
+//        return reduceResult(c, 0, cLen, m, ks);
+        return new LongArray(c, 0, cLen);
+    }
+
+    public void reduce(int m, int[] ks)
+    {
+        long[] buf = m_ints;
+        int rLen = reduceInPlace(buf, 0, buf.length, m, ks);
+        if (rLen < buf.length)
+        {
+            m_ints = new long[rLen];
+            System.arraycopy(buf, 0, m_ints, 0, rLen);
+        }
+    }
+
+    private static LongArray reduceResult(long[] buf, int off, int len, int m, int[] ks)
+    {
+        int rLen = reduceInPlace(buf, off, len, m, ks);
+        return new LongArray(buf, off, rLen);
+    }
+
+//    private static void deInterleave(long[] x, int xOff, long[] z, int zOff, int count, int rounds)
+//    {
+//        for (int i = 0; i < count; ++i)
+//        {
+//            z[zOff + i] = deInterleave(x[zOff + i], rounds);
+//        }
+//    }
+//
+//    private static long deInterleave(long x, int rounds)
+//    {
+//        while (--rounds >= 0)
+//        {
+//            x = deInterleave32(x & DEINTERLEAVE_MASK) | (deInterleave32((x >>> 1) & DEINTERLEAVE_MASK) << 32);
+//        }
+//        return x;
+//    }
+//
+//    private static long deInterleave32(long x)
+//    {
+//        x = (x | (x >>> 1)) & 0x3333333333333333L;
+//        x = (x | (x >>> 2)) & 0x0F0F0F0F0F0F0F0FL;
+//        x = (x | (x >>> 4)) & 0x00FF00FF00FF00FFL;
+//        x = (x | (x >>> 8)) & 0x0000FFFF0000FFFFL;
+//        x = (x | (x >>> 16)) & 0x00000000FFFFFFFFL;
+//        return x;
+//    }
+
+    private static int reduceInPlace(long[] buf, int off, int len, int m, int[] ks)
+    {
+        int mLen = (m + 63) >>> 6;
+        if (len < mLen)
+        {
+            return len;
+        }
+
+        int numBits = Math.min(len << 6, (m << 1) - 1); // TODO use actual degree?
+        int excessBits = (len << 6) - numBits;
+        while (excessBits >= 64)
+        {
+            --len;
+            excessBits -= 64;
+        }
+
+        int kLen = ks.length, kMax = ks[kLen - 1], kNext = kLen > 1 ? ks[kLen - 2] : 0;
+        int wordWiseLimit = Math.max(m, kMax + 64);
+        int vectorableWords = (excessBits + Math.min(numBits - wordWiseLimit, m - kNext)) >> 6;
+        if (vectorableWords > 1)
+        {
+            int vectorWiseWords = len - vectorableWords;
+            reduceVectorWise(buf, off, len, vectorWiseWords, m, ks);
+            while (len > vectorWiseWords)
+            {
+                buf[off + --len] = 0L;
+            }
+            numBits = vectorWiseWords << 6;
+        }
+
+        if (numBits > wordWiseLimit)
+        {
+            reduceWordWise(buf, off, len, wordWiseLimit, m, ks);
+            numBits = wordWiseLimit;
+        }
+
+        if (numBits > m)
+        {
+            reduceBitWise(buf, off, numBits, m, ks);
+        }
+
+        return mLen;
+    }
+
+    private static void reduceBitWise(long[] buf, int off, int bitlength, int m, int[] ks)
+    {
+        while (--bitlength >= m)
+        {
+            if (testBit(buf, off, bitlength))
+            {
+                reduceBit(buf, off, bitlength, m, ks);
+            }
+        }
+    }
+
+    private static void reduceBit(long[] buf, int off, int bit, int m, int[] ks)
+    {
+        flipBit(buf, off, bit);
+        int n = bit - m;
+        int j = ks.length;
+        while (--j >= 0)
+        {
+            flipBit(buf, off, ks[j] + n);
+        }
+        flipBit(buf, off, n);
+    }
+
+    private static void reduceWordWise(long[] buf, int off, int len, int toBit, int m, int[] ks)
+    {
+        int toPos = toBit >>> 6;
+
+        while (--len > toPos)
+        {
+            long word = buf[off + len];
+            if (word != 0)
+            {
+                buf[off + len] = 0;
+                reduceWord(buf, off, (len << 6), word, m, ks);
+            }
+        }
+
+        {
+            int partial = toBit & 0x3F;
+            long word = buf[off + toPos] >>> partial;
+            if (word != 0)
+            {
+                buf[off + toPos] ^= word << partial;
+                reduceWord(buf, off, toBit, word, m, ks);
+            }
+        }
+    }
+
+    private static void reduceWord(long[] buf, int off, int bit, long word, int m, int[] ks)
+    {
+        int offset = bit - m;
+        int j = ks.length;
+        while (--j >= 0)
+        {
+            flipWord(buf, off, offset + ks[j], word);
+        }
+        flipWord(buf, off, offset, word);
+    }
+
+    private static void reduceVectorWise(long[] buf, int off, int len, int words, int m, int[] ks)
+    {
+        /*
+         * NOTE: It's important we go from highest coefficient to lowest, because for the highest
+         * one (only) we allow the ranges to partially overlap, and therefore any changes must take
+         * effect for the subsequent lower coefficients.
+         */
+        int baseBit = (words << 6) - m;
+        int j = ks.length;
+        while (--j >= 0)
+        {
+            flipVector(buf, off, buf, off + words, len - words, baseBit + ks[j]);
+        }
+        flipVector(buf, off, buf, off + words, len - words, baseBit);
+    }
+
+    private static void flipVector(long[] x, int xOff, long[] y, int yOff, int yLen, int bits)
+    {
+        xOff += bits >>> 6;
+        bits &= 0x3F;
+
+        if (bits == 0)
+        {
+            add(x, xOff, y, yOff, yLen);
+        }
+        else
+        {
+            long carry = addShiftedDown(x, xOff + 1, y, yOff, yLen, 64 - bits);
+            x[xOff] ^= carry;
+        }
+    }
+
+    public LongArray modSquare(int m, int[] ks)
+    {
+        int len = getUsedLength();
+        if (len == 0)
+        {
+            return this;
+        }
+
+        int _2len = len << 1;
+        long[] r = new long[_2len];
+
+        int pos = 0;
+        while (pos < _2len)
+        {
+            long mi = m_ints[pos >>> 1];
+            r[pos++] = interleave2_32to64((int)mi);
+            r[pos++] = interleave2_32to64((int)(mi >>> 32));
+        }
+
+        return new LongArray(r, 0, reduceInPlace(r, 0, r.length, m, ks));
+    }
+
+    public LongArray modSquareN(int n, int m, int[] ks)
+    {
+        int len = getUsedLength();
+        if (len == 0)
+        {
+            return this;
+        }
+
+        int mLen = (m + 63) >>> 6;
+        long[] r = new long[mLen << 1];
+        System.arraycopy(m_ints, 0, r, 0, len);
+
+        while (--n >= 0)
+        {
+            squareInPlace(r, len, m, ks);
+            len = reduceInPlace(r, 0, r.length, m, ks);
+        }
+
+        return new LongArray(r, 0, len);
+    }
+
+    public LongArray square(int m, int[] ks)
+    {
+        int len = getUsedLength();
+        if (len == 0)
+        {
+            return this;
+        }
+
+        int _2len = len << 1;
+        long[] r = new long[_2len];
+
+        int pos = 0;
+        while (pos < _2len)
+        {
+            long mi = m_ints[pos >>> 1];
+            r[pos++] = interleave2_32to64((int)mi);
+            r[pos++] = interleave2_32to64((int)(mi >>> 32));
+        }
+
+        return new LongArray(r, 0, r.length);
+    }
+
+    private static void squareInPlace(long[] x, int xLen, int m, int[] ks)
+    {
+        int pos = xLen << 1;
+        while (--xLen >= 0)
+        {
+            long xVal = x[xLen];
+            x[--pos] = interleave2_32to64((int)(xVal >>> 32));
+            x[--pos] = interleave2_32to64((int)xVal);
+        }
+    }
+
+    private static void interleave(long[] x, int xOff, long[] z, int zOff, int count, int width)
+    {
+        switch (width)
+        {
+        case 3:
+            interleave3(x, xOff, z, zOff, count);
+            break;
+        case 5:
+            interleave5(x, xOff, z, zOff, count);
+            break;
+        case 7:
+            interleave7(x, xOff, z, zOff, count);
+            break;
+        default:
+            interleave2_n(x, xOff, z, zOff, count, bitLengths[width] - 1);
+            break;
+        }
+    }
+
+    private static void interleave3(long[] x, int xOff, long[] z, int zOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            z[zOff + i] = interleave3(x[xOff + i]);
+        }
+    }
+
+    private static long interleave3(long x)
+    {
+        long z = x & (1L << 63);
+        return z
+            | interleave3_21to63((int)x & 0x1FFFFF)
+            | interleave3_21to63((int)(x >>> 21) & 0x1FFFFF) << 1
+            | interleave3_21to63((int)(x >>> 42) & 0x1FFFFF) << 2;
+
+//        int zPos = 0, wPos = 0, xPos = 0;
+//        for (;;)
+//        {
+//            z |= ((x >>> xPos) & 1L) << zPos;
+//            if (++zPos == 63)
+//            {
+//                String sz2 = Long.toBinaryString(z);
+//                return z;
+//            }
+//            if ((xPos += 21) >= 63)
+//            {
+//                xPos = ++wPos;
+//            }
+//        }
+    }
+
+    private static long interleave3_21to63(int x)
+    {
+        int r00 = INTERLEAVE3_TABLE[x & 0x7F];
+        int r21 = INTERLEAVE3_TABLE[(x >>> 7) & 0x7F];
+        int r42 = INTERLEAVE3_TABLE[x >>> 14];
+        return (r42 & 0xFFFFFFFFL) << 42 | (r21 & 0xFFFFFFFFL) << 21 | (r00 & 0xFFFFFFFFL);
+    }
+
+    private static void interleave5(long[] x, int xOff, long[] z, int zOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            z[zOff + i] = interleave5(x[xOff + i]);
+        }
+    }
+
+    private static long interleave5(long x)
+    {
+        return interleave3_13to65((int)x & 0x1FFF)
+            | interleave3_13to65((int)(x >>> 13) & 0x1FFF) << 1
+            | interleave3_13to65((int)(x >>> 26) & 0x1FFF) << 2
+            | interleave3_13to65((int)(x >>> 39) & 0x1FFF) << 3
+            | interleave3_13to65((int)(x >>> 52) & 0x1FFF) << 4;
+
+//        long z = 0;
+//        int zPos = 0, wPos = 0, xPos = 0;
+//        for (;;)
+//        {
+//            z |= ((x >>> xPos) & 1L) << zPos;
+//            if (++zPos == 64)
+//            {
+//                return z;
+//            }
+//            if ((xPos += 13) >= 64)
+//            {
+//                xPos = ++wPos;
+//            }
+//        }
+    }
+
+    private static long interleave3_13to65(int x)
+    {
+        int r00 = INTERLEAVE5_TABLE[x & 0x7F];
+        int r35 = INTERLEAVE5_TABLE[x >>> 7];
+        return (r35 & 0xFFFFFFFFL) << 35 | (r00 & 0xFFFFFFFFL);
+    }
+
+    private static void interleave7(long[] x, int xOff, long[] z, int zOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            z[zOff + i] = interleave7(x[xOff + i]);
+        }
+    }
+
+    private static long interleave7(long x)
+    {
+        long z = x & (1L << 63);
+        return z
+            | INTERLEAVE7_TABLE[(int)x & 0x1FF]
+            | INTERLEAVE7_TABLE[(int)(x >>> 9) & 0x1FF] << 1
+            | INTERLEAVE7_TABLE[(int)(x >>> 18) & 0x1FF] << 2
+            | INTERLEAVE7_TABLE[(int)(x >>> 27) & 0x1FF] << 3
+            | INTERLEAVE7_TABLE[(int)(x >>> 36) & 0x1FF] << 4
+            | INTERLEAVE7_TABLE[(int)(x >>> 45) & 0x1FF] << 5
+            | INTERLEAVE7_TABLE[(int)(x >>> 54) & 0x1FF] << 6;
+
+//        int zPos = 0, wPos = 0, xPos = 0;
+//        for (;;)
+//        {
+//            z |= ((x >>> xPos) & 1L) << zPos;
+//            if (++zPos == 63)
+//            {
+//                return z;
+//            }
+//            if ((xPos += 9) >= 63)
+//            {
+//                xPos = ++wPos;
+//            }
+//        }
+    }
+
+    private static void interleave2_n(long[] x, int xOff, long[] z, int zOff, int count, int rounds)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            z[zOff + i] = interleave2_n(x[xOff + i], rounds);
+        }
+    }
+
+    private static long interleave2_n(long x, int rounds)
+    {
+        while (rounds > 1)
+        {
+            rounds -= 2;
+            x = interleave4_16to64((int)x & 0xFFFF)
+                | interleave4_16to64((int)(x >>> 16) & 0xFFFF) << 1
+                | interleave4_16to64((int)(x >>> 32) & 0xFFFF) << 2
+                | interleave4_16to64((int)(x >>> 48) & 0xFFFF) << 3;
+        }
+        if (rounds > 0)
+        {
+            x = interleave2_32to64((int)x) | interleave2_32to64((int)(x >>> 32)) << 1;
+        }
+        return x;
+    }
+
+    private static long interleave4_16to64(int x)
+    {
+        int r00 = INTERLEAVE4_TABLE[x & 0xFF];
+        int r32 = INTERLEAVE4_TABLE[x >>> 8];
+        return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL);
+    }
+
+    private static long interleave2_32to64(int x)
+    {
+        int r00 = INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >>> 8) & 0xFF] << 16;
+        int r32 = INTERLEAVE2_TABLE[(x >>> 16) & 0xFF] | INTERLEAVE2_TABLE[x >>> 24] << 16;
+        return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL);
+    }
+
+//    private static LongArray expItohTsujii2(LongArray B, int n, int m, int[] ks)
+//    {
+//        LongArray t1 = B, t3 = new LongArray(new long[]{ 1L });
+//        int scale = 1;
+//
+//        int numTerms = n;
+//        while (numTerms > 1)
+//        {
+//            if ((numTerms & 1) != 0)
+//            {
+//                t3 = t3.modMultiply(t1, m, ks);
+//                t1 = t1.modSquareN(scale, m, ks);
+//            }
+//
+//            LongArray t2 = t1.modSquareN(scale, m, ks);
+//            t1 = t1.modMultiply(t2, m, ks);
+//            numTerms >>>= 1; scale <<= 1;
+//        }
+//
+//        return t3.modMultiply(t1, m, ks);
+//    }
+//
+//    private static LongArray expItohTsujii23(LongArray B, int n, int m, int[] ks)
+//    {
+//        LongArray t1 = B, t3 = new LongArray(new long[]{ 1L });
+//        int scale = 1;
+//
+//        int numTerms = n;
+//        while (numTerms > 1)
+//        {
+//            boolean m03 = numTerms % 3 == 0;
+//            boolean m14 = !m03 && (numTerms & 1) != 0;
+//
+//            if (m14)
+//            {
+//                t3 = t3.modMultiply(t1, m, ks);
+//                t1 = t1.modSquareN(scale, m, ks);
+//            }
+//
+//            LongArray t2 = t1.modSquareN(scale, m, ks);
+//            t1 = t1.modMultiply(t2, m, ks);
+//
+//            if (m03)
+//            {
+//                t2 = t2.modSquareN(scale, m, ks);
+//                t1 = t1.modMultiply(t2, m, ks);
+//                numTerms /= 3; scale *= 3;
+//            }
+//            else
+//            {
+//                numTerms >>>= 1; scale <<= 1;
+//            }
+//        }
+//
+//        return t3.modMultiply(t1, m, ks);
+//    }
+//
+//    private static LongArray expItohTsujii235(LongArray B, int n, int m, int[] ks)
+//    {
+//        LongArray t1 = B, t4 = new LongArray(new long[]{ 1L });
+//        int scale = 1;
+//
+//        int numTerms = n;
+//        while (numTerms > 1)
+//        {
+//            if (numTerms % 5 == 0)
+//            {
+////                t1 = expItohTsujii23(t1, 5, m, ks);
+//
+//                LongArray t3 = t1;
+//                t1 = t1.modSquareN(scale, m, ks);
+//
+//                LongArray t2 = t1.modSquareN(scale, m, ks);
+//                t1 = t1.modMultiply(t2, m, ks);
+//                t2 = t1.modSquareN(scale << 1, m, ks);
+//                t1 = t1.modMultiply(t2, m, ks);
+//
+//                t1 = t1.modMultiply(t3, m, ks);
+//
+//                numTerms /= 5; scale *= 5;
+//                continue;
+//            }
+//
+//            boolean m03 = numTerms % 3 == 0;
+//            boolean m14 = !m03 && (numTerms & 1) != 0;
+//
+//            if (m14)
+//            {
+//                t4 = t4.modMultiply(t1, m, ks);
+//                t1 = t1.modSquareN(scale, m, ks);
+//            }
+//
+//            LongArray t2 = t1.modSquareN(scale, m, ks);
+//            t1 = t1.modMultiply(t2, m, ks);
+//
+//            if (m03)
+//            {
+//                t2 = t2.modSquareN(scale, m, ks);
+//                t1 = t1.modMultiply(t2, m, ks);
+//                numTerms /= 3; scale *= 3;
+//            }
+//            else
+//            {
+//                numTerms >>>= 1; scale <<= 1;
+//            }
+//        }
+//
+//        return t4.modMultiply(t1, m, ks);
+//    }
+
+    public LongArray modInverse(int m, int[] ks)
+    {
+        /*
+         * Fermat's Little Theorem
+         */
+//        LongArray A = this;
+//        LongArray B = A.modSquare(m, ks);
+//        LongArray R0 = B, R1 = B;
+//        for (int i = 2; i < m; ++i)
+//        {
+//            R1 = R1.modSquare(m, ks);
+//            R0 = R0.modMultiply(R1, m, ks);
+//        }
+//
+//        return R0;
+
+        /*
+         * Itoh-Tsujii
+         */
+//        LongArray B = modSquare(m, ks);
+//        switch (m)
+//        {
+//        case 409:
+//            return expItohTsujii23(B, m - 1, m, ks);
+//        case 571:
+//            return expItohTsujii235(B, m - 1, m, ks);
+//        case 163:
+//        case 233:
+//        case 283:
+//        default:
+//            return expItohTsujii2(B, m - 1, m, ks);
+//        }
+
+        /*
+         * Inversion in F2m using the extended Euclidean algorithm
+         * 
+         * Input: A nonzero polynomial a(z) of degree at most m-1
+         * Output: a(z)^(-1) mod f(z)
+         */
+        int uzDegree = degree();
+        if (uzDegree == 0)
+        {
+            throw new IllegalStateException();
+        }
+        if (uzDegree == 1)
+        {
+            return this;
+        }
+
+        // u(z) := a(z)
+        LongArray uz = (LongArray)clone();
+
+        int t = (m + 63) >>> 6;
+
+        // v(z) := f(z)
+        LongArray vz = new LongArray(t);
+        reduceBit(vz.m_ints, 0, m, m, ks);
+
+        // g1(z) := 1, g2(z) := 0
+        LongArray g1z = new LongArray(t);
+        g1z.m_ints[0] = 1L;
+        LongArray g2z = new LongArray(t);
+
+        int[] uvDeg = new int[]{ uzDegree, m + 1 };
+        LongArray[] uv = new LongArray[]{ uz, vz };
+
+        int[] ggDeg = new int[]{ 1, 0 };
+        LongArray[] gg = new LongArray[]{ g1z, g2z };
+
+        int b = 1;
+        int duv1 = uvDeg[b];
+        int dgg1 = ggDeg[b];
+        int j = duv1 - uvDeg[1 - b];
+
+        for (;;)
+        {
+            if (j < 0)
+            {
+                j = -j;
+                uvDeg[b] = duv1;
+                ggDeg[b] = dgg1;
+                b = 1 - b;
+                duv1 = uvDeg[b];
+                dgg1 = ggDeg[b];
+            }
+
+            uv[b].addShiftedByBitsSafe(uv[1 - b], uvDeg[1 - b], j);
+
+            int duv2 = uv[b].degreeFrom(duv1);
+            if (duv2 == 0)
+            {
+                return gg[1 - b];
+            }
+
+            {
+                int dgg2 = ggDeg[1 - b];
+                gg[b].addShiftedByBitsSafe(gg[1 - b], dgg2, j);
+                dgg2 += j;
+
+                if (dgg2 > dgg1)
+                {
+                    dgg1 = dgg2;
+                }
+                else if (dgg2 == dgg1)
+                {
+                    dgg1 = gg[b].degreeFrom(dgg1);
+                }
+            }
+
+            j += (duv2 - duv1);
+            duv1 = duv2;
+        }
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof LongArray))
+        {
+            return false;
+        }
+        LongArray other = (LongArray) o;
+        int usedLen = getUsedLength();
+        if (other.getUsedLength() != usedLen)
+        {
+            return false;
+        }
+        for (int i = 0; i < usedLen; i++)
+        {
+            if (m_ints[i] != other.m_ints[i])
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public int hashCode()
+    {
+        int usedLen = getUsedLength();
+        int hash = 1;
+        for (int i = 0; i < usedLen; i++)
+        {
+            long mi = m_ints[i];
+            hash *= 31;
+            hash ^= (int)mi;
+            hash *= 31;
+            hash ^= (int)(mi >>> 32);
+        }
+        return hash;
+    }
+
+    public Object clone()
+    {
+        return new LongArray(Arrays.clone(m_ints));
+    }
+
+    public String toString()
+    {
+        int i = getUsedLength();
+        if (i == 0)
+        {
+            return "0";
+        }
+
+        StringBuffer sb = new StringBuffer(Long.toBinaryString(m_ints[--i]));
+        while (--i >= 0)
+        {
+            String s = Long.toBinaryString(m_ints[i]);
+
+            // Add leading zeroes, except for highest significant word
+            int len = s.length();
+            if (len < 64)
+            {
+                sb.append(ZEROES.substring(len));
+            }
+
+            sb.append(s);
+        }
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/PreCompCallback.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/PreCompCallback.java
new file mode 100644
index 0000000..4f4132e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/PreCompCallback.java
@@ -0,0 +1,10 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface PreCompCallback
+{
+    PreCompInfo precompute(PreCompInfo existing);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/PreCompInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/PreCompInfo.java
new file mode 100644
index 0000000..0c440e5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/PreCompInfo.java
@@ -0,0 +1,12 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+/**
+ * Interface for classes storing precomputation data for multiplication
+ * algorithms. Used as a Memento (see GOF patterns) by e.g. 
+ * <code>WNafL2RMultiplier</code>.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface PreCompInfo
+{
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ScaleXPointMap.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ScaleXPointMap.java
new file mode 100644
index 0000000..e67dc78
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ScaleXPointMap.java
@@ -0,0 +1,20 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ScaleXPointMap implements ECPointMap
+{
+    protected final ECFieldElement scale;
+
+    public ScaleXPointMap(ECFieldElement scale)
+    {
+        this.scale = scale;
+    }
+
+    public ECPoint map(ECPoint p)
+    {
+        return p.scaleX(scale);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/SimpleBigDecimal.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/SimpleBigDecimal.java
new file mode 100644
index 0000000..d9ceecd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/SimpleBigDecimal.java
@@ -0,0 +1,248 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class representing a simple version of a big decimal. A
+ * <code>SimpleBigDecimal</code> is basically a
+ * {@link java.math.BigInteger BigInteger} with a few digits on the right of
+ * the decimal point. The number of (binary) digits on the right of the decimal
+ * point is called the <code>scale</code> of the <code>SimpleBigDecimal</code>.
+ * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted
+ * automatically, but must be set manually. All <code>SimpleBigDecimal</code>s
+ * taking part in the same arithmetic operation must have equal scale. The
+ * result of a multiplication of two <code>SimpleBigDecimal</code>s returns a
+ * <code>SimpleBigDecimal</code> with double scale.
+ */
+class SimpleBigDecimal
+    //extends Number   // not in J2ME - add compatibility class?
+{
+    private static final long serialVersionUID = 1L;
+
+    private final BigInteger bigInt;
+    private final int scale;
+
+    /**
+     * Returns a <code>SimpleBigDecimal</code> representing the same numerical
+     * value as <code>value</code>.
+     * @param value The value of the <code>SimpleBigDecimal</code> to be
+     * created. 
+     * @param scale The scale of the <code>SimpleBigDecimal</code> to be
+     * created. 
+     * @return The such created <code>SimpleBigDecimal</code>.
+     */
+    public static SimpleBigDecimal getInstance(BigInteger value, int scale)
+    {
+        return new SimpleBigDecimal(value.shiftLeft(scale), scale);
+    }
+
+    /**
+     * Constructor for <code>SimpleBigDecimal</code>. The value of the
+     * constructed <code>SimpleBigDecimal</code> equals <code>bigInt / 
+     * 2<sup>scale</sup></code>.
+     * @param bigInt The <code>bigInt</code> value parameter.
+     * @param scale The scale of the constructed <code>SimpleBigDecimal</code>.
+     */
+    public SimpleBigDecimal(BigInteger bigInt, int scale)
+    {
+        if (scale < 0)
+        {
+            throw new IllegalArgumentException("scale may not be negative");
+        }
+
+        this.bigInt = bigInt;
+        this.scale = scale;
+    }
+
+    private void checkScale(SimpleBigDecimal b)
+    {
+        if (scale != b.scale)
+        {
+            throw new IllegalArgumentException("Only SimpleBigDecimal of " +
+                "same scale allowed in arithmetic operations");
+        }
+    }
+
+    public SimpleBigDecimal adjustScale(int newScale)
+    {
+        if (newScale < 0)
+        {
+            throw new IllegalArgumentException("scale may not be negative");
+        }
+
+        if (newScale == scale)
+        {
+            return this;
+        }
+
+        return new SimpleBigDecimal(bigInt.shiftLeft(newScale - scale),
+                newScale);
+    }
+
+    public SimpleBigDecimal add(SimpleBigDecimal b)
+    {
+        checkScale(b);
+        return new SimpleBigDecimal(bigInt.add(b.bigInt), scale);
+    }
+
+    public SimpleBigDecimal add(BigInteger b)
+    {
+        return new SimpleBigDecimal(bigInt.add(b.shiftLeft(scale)), scale);
+    }
+
+    public SimpleBigDecimal negate()
+    {
+        return new SimpleBigDecimal(bigInt.negate(), scale);
+    }
+
+    public SimpleBigDecimal subtract(SimpleBigDecimal b)
+    {
+        return add(b.negate());
+    }
+
+    public SimpleBigDecimal subtract(BigInteger b)
+    {
+        return new SimpleBigDecimal(bigInt.subtract(b.shiftLeft(scale)),
+                scale);
+    }
+
+    public SimpleBigDecimal multiply(SimpleBigDecimal b)
+    {
+        checkScale(b);
+        return new SimpleBigDecimal(bigInt.multiply(b.bigInt), scale + scale);
+    }
+
+    public SimpleBigDecimal multiply(BigInteger b)
+    {
+        return new SimpleBigDecimal(bigInt.multiply(b), scale);
+    }
+
+    public SimpleBigDecimal divide(SimpleBigDecimal b)
+    {
+        checkScale(b);
+        BigInteger dividend = bigInt.shiftLeft(scale);
+        return new SimpleBigDecimal(dividend.divide(b.bigInt), scale);
+    }
+
+    public SimpleBigDecimal divide(BigInteger b)
+    {
+        return new SimpleBigDecimal(bigInt.divide(b), scale);
+    }
+
+    public SimpleBigDecimal shiftLeft(int n)
+    {
+        return new SimpleBigDecimal(bigInt.shiftLeft(n), scale);
+    }
+
+    public int compareTo(SimpleBigDecimal val)
+    {
+        checkScale(val);
+        return bigInt.compareTo(val.bigInt);
+    }
+
+    public int compareTo(BigInteger val)
+    {
+        return bigInt.compareTo(val.shiftLeft(scale));
+    }
+
+    public BigInteger floor()
+    {
+        return bigInt.shiftRight(scale);
+    }
+
+    public BigInteger round()
+    {
+        SimpleBigDecimal oneHalf = new SimpleBigDecimal(ECConstants.ONE, 1);
+        return add(oneHalf.adjustScale(scale)).floor();
+    }
+
+    public int intValue()
+    {
+        return floor().intValue();
+    }
+    
+    public long longValue()
+    {
+        return floor().longValue();
+    }
+          /* NON-J2ME compliant.
+    public double doubleValue()
+    {
+        return Double.valueOf(toString()).doubleValue();
+    }
+
+    public float floatValue()
+    {
+        return Float.valueOf(toString()).floatValue();
+    }
+       */
+    public int getScale()
+    {
+        return scale;
+    }
+
+    public String toString()
+    {
+        if (scale == 0)
+        {
+            return bigInt.toString();
+        }
+
+        BigInteger floorBigInt = floor();
+        
+        BigInteger fract = bigInt.subtract(floorBigInt.shiftLeft(scale));
+        if (bigInt.signum() == -1)
+        {
+            fract = ECConstants.ONE.shiftLeft(scale).subtract(fract);
+        }
+
+        if ((floorBigInt.signum() == -1) && (!(fract.equals(ECConstants.ZERO))))
+        {
+            floorBigInt = floorBigInt.add(ECConstants.ONE);
+        }
+        String leftOfPoint = floorBigInt.toString();
+
+        char[] fractCharArr = new char[scale];
+        String fractStr = fract.toString(2);
+        int fractLen = fractStr.length();
+        int zeroes = scale - fractLen;
+        for (int i = 0; i < zeroes; i++)
+        {
+            fractCharArr[i] = '0';
+        }
+        for (int j = 0; j < fractLen; j++)
+        {
+            fractCharArr[zeroes + j] = fractStr.charAt(j);
+        }
+        String rightOfPoint = new String(fractCharArr);
+
+        StringBuffer sb = new StringBuffer(leftOfPoint);
+        sb.append(".");
+        sb.append(rightOfPoint);
+
+        return sb.toString();
+    }
+
+    public boolean equals(Object o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+
+        if (!(o instanceof SimpleBigDecimal))
+        {
+            return false;
+        }
+
+        SimpleBigDecimal other = (SimpleBigDecimal)o;
+        return ((bigInt.equals(other.bigInt)) && (scale == other.scale));
+    }
+
+    public int hashCode()
+    {
+        return bigInt.hashCode() ^ scale;
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/Tnaf.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/Tnaf.java
new file mode 100644
index 0000000..f326608
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/Tnaf.java
@@ -0,0 +1,850 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class holding methods for point multiplication based on the window
+ * &tau;-adic nonadjacent form (WTNAF). The algorithms are based on the
+ * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves"
+ * by Jerome A. Solinas. The paper first appeared in the Proceedings of
+ * Crypto 1997.
+ */
+class Tnaf
+{
+    private static final BigInteger MINUS_ONE = ECConstants.ONE.negate();
+    private static final BigInteger MINUS_TWO = ECConstants.TWO.negate();
+    private static final BigInteger MINUS_THREE = ECConstants.THREE.negate();
+
+    /**
+     * The window width of WTNAF. The standard value of 4 is slightly less
+     * than optimal for running time, but keeps space requirements for
+     * precomputation low. For typical curves, a value of 5 or 6 results in
+     * a better running time. When changing this value, the
+     * <code>&alpha;<sub>u</sub></code>'s must be computed differently, see
+     * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson,
+     * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,
+     * p. 121-122
+     */
+    public static final byte WIDTH = 4;
+
+    /**
+     * 2<sup>4</sup>
+     */
+    public static final byte POW_2_WIDTH = 16;
+
+    /**
+     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=0</code> as an array
+     * of <code>ZTauElement</code>s.
+     */
+    public static final ZTauElement[] alpha0 = {
+        null,
+        new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
+        new ZTauElement(MINUS_THREE, MINUS_ONE), null,
+        new ZTauElement(MINUS_ONE, MINUS_ONE), null,
+        new ZTauElement(ECConstants.ONE, MINUS_ONE), null
+    };
+
+    /**
+     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=0</code> as an array
+     * of TNAFs.
+     */
+    public static final byte[][] alpha0Tnaf = {
+        null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, 1}
+    };
+
+    /**
+     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=1</code> as an array
+     * of <code>ZTauElement</code>s.
+     */
+    public static final ZTauElement[] alpha1 = {null,
+        new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
+        new ZTauElement(MINUS_THREE, ECConstants.ONE), null,
+        new ZTauElement(MINUS_ONE, ECConstants.ONE), null,
+        new ZTauElement(ECConstants.ONE, ECConstants.ONE), null
+    };
+
+    /**
+     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=1</code> as an array
+     * of TNAFs.
+     */
+    public static final byte[][] alpha1Tnaf = {
+        null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, -1}
+    };
+
+    /**
+     * Computes the norm of an element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code>.
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+     * @param lambda The element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code>.
+     * @return The norm of <code>&lambda;</code>.
+     */
+    public static BigInteger norm(final byte mu, ZTauElement lambda)
+    {
+        BigInteger norm;
+
+        // s1 = u^2
+        BigInteger s1 = lambda.u.multiply(lambda.u);
+
+        // s2 = u * v
+        BigInteger s2 = lambda.u.multiply(lambda.v);
+
+        // s3 = 2 * v^2
+        BigInteger s3 = lambda.v.multiply(lambda.v).shiftLeft(1);
+
+        if (mu == 1)
+        {
+            norm = s1.add(s2).add(s3);
+        }
+        else if (mu == -1)
+        {
+            norm = s1.subtract(s2).add(s3);
+        }
+        else
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+
+        return norm;
+    }
+
+    /**
+     * Computes the norm of an element <code>&lambda;</code> of
+     * <code><b>R</b>[&tau;]</code>, where <code>&lambda; = u + v&tau;</code>
+     * and <code>u</code> and <code>u</code> are real numbers (elements of
+     * <code><b>R</b></code>). 
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+     * @param u The real part of the element <code>&lambda;</code> of
+     * <code><b>R</b>[&tau;]</code>.
+     * @param v The <code>&tau;</code>-adic part of the element
+     * <code>&lambda;</code> of <code><b>R</b>[&tau;]</code>.
+     * @return The norm of <code>&lambda;</code>.
+     */
+    public static SimpleBigDecimal norm(final byte mu, SimpleBigDecimal u,
+            SimpleBigDecimal v)
+    {
+        SimpleBigDecimal norm;
+
+        // s1 = u^2
+        SimpleBigDecimal s1 = u.multiply(u);
+
+        // s2 = u * v
+        SimpleBigDecimal s2 = u.multiply(v);
+
+        // s3 = 2 * v^2
+        SimpleBigDecimal s3 = v.multiply(v).shiftLeft(1);
+
+        if (mu == 1)
+        {
+            norm = s1.add(s2).add(s3);
+        }
+        else if (mu == -1)
+        {
+            norm = s1.subtract(s2).add(s3);
+        }
+        else
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+
+        return norm;
+    }
+
+    /**
+     * Rounds an element <code>&lambda;</code> of <code><b>R</b>[&tau;]</code>
+     * to an element of <code><b>Z</b>[&tau;]</code>, such that their difference
+     * has minimal norm. <code>&lambda;</code> is given as
+     * <code>&lambda; = &lambda;<sub>0</sub> + &lambda;<sub>1</sub>&tau;</code>.
+     * @param lambda0 The component <code>&lambda;<sub>0</sub></code>.
+     * @param lambda1 The component <code>&lambda;<sub>1</sub></code>.
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve. Must
+     * equal 1 or -1.
+     * @return The rounded element of <code><b>Z</b>[&tau;]</code>.
+     * @throws IllegalArgumentException if <code>lambda0</code> and
+     * <code>lambda1</code> do not have same scale.
+     */
+    public static ZTauElement round(SimpleBigDecimal lambda0,
+            SimpleBigDecimal lambda1, byte mu)
+    {
+        int scale = lambda0.getScale();
+        if (lambda1.getScale() != scale)
+        {
+            throw new IllegalArgumentException("lambda0 and lambda1 do not " +
+                    "have same scale");
+        }
+
+        if (!((mu == 1) || (mu == -1)))
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+
+        BigInteger f0 = lambda0.round();
+        BigInteger f1 = lambda1.round();
+
+        SimpleBigDecimal eta0 = lambda0.subtract(f0);
+        SimpleBigDecimal eta1 = lambda1.subtract(f1);
+
+        // eta = 2*eta0 + mu*eta1
+        SimpleBigDecimal eta = eta0.add(eta0);
+        if (mu == 1)
+        {
+            eta = eta.add(eta1);
+        }
+        else
+        {
+            // mu == -1
+            eta = eta.subtract(eta1);
+        }
+
+        // check1 = eta0 - 3*mu*eta1
+        // check2 = eta0 + 4*mu*eta1
+        SimpleBigDecimal threeEta1 = eta1.add(eta1).add(eta1);
+        SimpleBigDecimal fourEta1 = threeEta1.add(eta1);
+        SimpleBigDecimal check1;
+        SimpleBigDecimal check2;
+        if (mu == 1)
+        {
+            check1 = eta0.subtract(threeEta1);
+            check2 = eta0.add(fourEta1);
+        }
+        else
+        {
+            // mu == -1
+            check1 = eta0.add(threeEta1);
+            check2 = eta0.subtract(fourEta1);
+        }
+
+        byte h0 = 0;
+        byte h1 = 0;
+
+        // if eta >= 1
+        if (eta.compareTo(ECConstants.ONE) >= 0)
+        {
+            if (check1.compareTo(MINUS_ONE) < 0)
+            {
+                h1 = mu;
+            }
+            else
+            {
+                h0 = 1;
+            }
+        }
+        else
+        {
+            // eta < 1
+            if (check2.compareTo(ECConstants.TWO) >= 0)
+            {
+                h1 = mu;
+            }
+        }
+
+        // if eta < -1
+        if (eta.compareTo(MINUS_ONE) < 0)
+        {
+            if (check1.compareTo(ECConstants.ONE) >= 0)
+            {
+                h1 = (byte)-mu;
+            }
+            else
+            {
+                h0 = -1;
+            }
+        }
+        else
+        {
+            // eta >= -1
+            if (check2.compareTo(MINUS_TWO) < 0)
+            {
+                h1 = (byte)-mu;
+            }
+        }
+
+        BigInteger q0 = f0.add(BigInteger.valueOf(h0));
+        BigInteger q1 = f1.add(BigInteger.valueOf(h1));
+        return new ZTauElement(q0, q1);
+    }
+
+    /**
+     * Approximate division by <code>n</code>. For an integer
+     * <code>k</code>, the value <code>&lambda; = s k / n</code> is
+     * computed to <code>c</code> bits of accuracy.
+     * @param k The parameter <code>k</code>.
+     * @param s The curve parameter <code>s<sub>0</sub></code> or
+     * <code>s<sub>1</sub></code>.
+     * @param vm The Lucas Sequence element <code>V<sub>m</sub></code>.
+     * @param a The parameter <code>a</code> of the elliptic curve.
+     * @param m The bit length of the finite field
+     * <code><b>F</b><sub>m</sub></code>.
+     * @param c The number of bits of accuracy, i.e. the scale of the returned
+     * <code>SimpleBigDecimal</code>.
+     * @return The value <code>&lambda; = s k / n</code> computed to
+     * <code>c</code> bits of accuracy.
+     */
+    public static SimpleBigDecimal approximateDivisionByN(BigInteger k,
+            BigInteger s, BigInteger vm, byte a, int m, int c)
+    {
+        int _k = (m + 5)/2 + c;
+        BigInteger ns = k.shiftRight(m - _k - 2 + a);
+
+        BigInteger gs = s.multiply(ns);
+
+        BigInteger hs = gs.shiftRight(m);
+
+        BigInteger js = vm.multiply(hs);
+
+        BigInteger gsPlusJs = gs.add(js);
+        BigInteger ls = gsPlusJs.shiftRight(_k-c);
+        if (gsPlusJs.testBit(_k-c-1))
+        {
+            // round up
+            ls = ls.add(ECConstants.ONE);
+        }
+
+        return new SimpleBigDecimal(ls, c);
+    }
+
+    /**
+     * Computes the <code>&tau;</code>-adic NAF (non-adjacent form) of an
+     * element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>.
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+     * @param lambda The element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code>.
+     * @return The <code>&tau;</code>-adic NAF of <code>&lambda;</code>.
+     */
+    public static byte[] tauAdicNaf(byte mu, ZTauElement lambda)
+    {
+        if (!((mu == 1) || (mu == -1)))
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+        
+        BigInteger norm = norm(mu, lambda);
+
+        // Ceiling of log2 of the norm 
+        int log2Norm = norm.bitLength();
+
+        // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+        int maxLength = log2Norm > 30 ? log2Norm + 4 : 34;
+
+        // The array holding the TNAF
+        byte[] u = new byte[maxLength];
+        int i = 0;
+
+        // The actual length of the TNAF
+        int length = 0;
+
+        BigInteger r0 = lambda.u;
+        BigInteger r1 = lambda.v;
+
+        while(!((r0.equals(ECConstants.ZERO)) && (r1.equals(ECConstants.ZERO))))
+        {
+            // If r0 is odd
+            if (r0.testBit(0))
+            {
+                u[i] = (byte) ECConstants.TWO.subtract((r0.subtract(r1.shiftLeft(1))).mod(ECConstants.FOUR)).intValue();
+
+                // r0 = r0 - u[i]
+                if (u[i] == 1)
+                {
+                    r0 = r0.clearBit(0);
+                }
+                else
+                {
+                    // u[i] == -1
+                    r0 = r0.add(ECConstants.ONE);
+                }
+                length = i;
+            }
+            else
+            {
+                u[i] = 0;
+            }
+
+            BigInteger t = r0;
+            BigInteger s = r0.shiftRight(1);
+            if (mu == 1)
+            {
+                r0 = r1.add(s);
+            }
+            else
+            {
+                // mu == -1
+                r0 = r1.subtract(s);
+            }
+
+            r1 = t.shiftRight(1).negate();
+            i++;
+        }
+
+        length++;
+
+        // Reduce the TNAF array to its actual length
+        byte[] tnaf = new byte[length];
+        System.arraycopy(u, 0, tnaf, 0, length);
+        return tnaf;
+    }
+
+    /**
+     * Applies the operation <code>&tau;()</code> to an
+     * <code>ECPoint.AbstractF2m</code>. 
+     * @param p The ECPoint.AbstractF2m to which <code>&tau;()</code> is applied.
+     * @return <code>&tau;(p)</code>
+     */
+    public static ECPoint.AbstractF2m tau(ECPoint.AbstractF2m p)
+    {
+        return p.tau();
+    }
+
+    /**
+     * Returns the parameter <code>&mu;</code> of the elliptic curve.
+     * @param curve The elliptic curve from which to obtain <code>&mu;</code>.
+     * The curve must be a Koblitz curve, i.e. <code>a</code> equals
+     * <code>0</code> or <code>1</code> and <code>b</code> equals
+     * <code>1</code>. 
+     * @return <code>&mu;</code> of the elliptic curve.
+     * @throws IllegalArgumentException if the given ECCurve is not a Koblitz
+     * curve.
+     */
+    public static byte getMu(ECCurve.AbstractF2m curve)
+    {
+        if (!curve.isKoblitz())
+        {
+            throw new IllegalArgumentException("No Koblitz curve (ABC), TNAF multiplication not possible");
+        }
+
+        if (curve.getA().isZero())
+        {
+            return -1;
+        }
+
+        return 1;
+    }
+
+    public static byte getMu(ECFieldElement curveA)
+    {
+        return (byte)(curveA.isZero() ? -1 : 1);
+    }
+
+    public static byte getMu(int curveA)
+    {
+        return (byte)(curveA == 0 ? -1 : 1);
+    }
+
+    /**
+     * Calculates the Lucas Sequence elements <code>U<sub>k-1</sub></code> and
+     * <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code> and
+     * <code>V<sub>k</sub></code>.
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+     * @param k The index of the second element of the Lucas Sequence to be
+     * returned.
+     * @param doV If set to true, computes <code>V<sub>k-1</sub></code> and
+     * <code>V<sub>k</sub></code>, otherwise <code>U<sub>k-1</sub></code> and
+     * <code>U<sub>k</sub></code>.
+     * @return An array with 2 elements, containing <code>U<sub>k-1</sub></code>
+     * and <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code>
+     * and <code>V<sub>k</sub></code>.
+     */
+    public static BigInteger[] getLucas(byte mu, int k, boolean doV)
+    {
+        if (!((mu == 1) || (mu == -1)))
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+
+        BigInteger u0;
+        BigInteger u1;
+        BigInteger u2;
+
+        if (doV)
+        {
+            u0 = ECConstants.TWO;
+            u1 = BigInteger.valueOf(mu);
+        }
+        else
+        {
+            u0 = ECConstants.ZERO;
+            u1 = ECConstants.ONE;
+        }
+
+        for (int i = 1; i < k; i++)
+        {
+            // u2 = mu*u1 - 2*u0;
+            BigInteger s = null;
+            if (mu == 1)
+            {
+                s = u1;
+            }
+            else
+            {
+                // mu == -1
+                s = u1.negate();
+            }
+            
+            u2 = s.subtract(u0.shiftLeft(1));
+            u0 = u1;
+            u1 = u2;
+//            System.out.println(i + ": " + u2);
+//            System.out.println();
+        }
+
+        BigInteger[] retVal = {u0, u1};
+        return retVal;
+    }
+
+    /**
+     * Computes the auxiliary value <code>t<sub>w</sub></code>. If the width is
+     * 4, then for <code>mu = 1</code>, <code>t<sub>w</sub> = 6</code> and for
+     * <code>mu = -1</code>, <code>t<sub>w</sub> = 10</code> 
+     * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+     * @param w The window width of the WTNAF.
+     * @return the auxiliary value <code>t<sub>w</sub></code>
+     */
+    public static BigInteger getTw(byte mu, int w)
+    {
+        if (w == 4)
+        {
+            if (mu == 1)
+            {
+                return BigInteger.valueOf(6);
+            }
+            else
+            {
+                // mu == -1
+                return BigInteger.valueOf(10);
+            }
+        }
+        else
+        {
+            // For w <> 4, the values must be computed
+            BigInteger[] us = getLucas(mu, w, false);
+            BigInteger twoToW = ECConstants.ZERO.setBit(w);
+            BigInteger u1invert = us[1].modInverse(twoToW);
+            BigInteger tw;
+            tw = ECConstants.TWO.multiply(us[0]).multiply(u1invert).mod(twoToW);
+//            System.out.println("mu = " + mu);
+//            System.out.println("tw = " + tw);
+            return tw;
+        }
+    }
+
+    /**
+     * Computes the auxiliary values <code>s<sub>0</sub></code> and
+     * <code>s<sub>1</sub></code> used for partial modular reduction. 
+     * @param curve The elliptic curve for which to compute
+     * <code>s<sub>0</sub></code> and <code>s<sub>1</sub></code>.
+     * @throws IllegalArgumentException if <code>curve</code> is not a
+     * Koblitz curve (Anomalous Binary Curve, ABC).
+     */
+    public static BigInteger[] getSi(ECCurve.AbstractF2m curve)
+    {
+        if (!curve.isKoblitz())
+        {
+            throw new IllegalArgumentException("si is defined for Koblitz curves only");
+        }
+
+        int m = curve.getFieldSize();
+        int a = curve.getA().toBigInteger().intValue();
+        byte mu = getMu(a);
+        int shifts = getShiftsForCofactor(curve.getCofactor());
+        int index = m + 3 - a;
+        BigInteger[] ui = getLucas(mu, index, false);
+        if (mu == 1)
+        {
+            ui[0] = ui[0].negate();
+            ui[1] = ui[1].negate();
+        }
+
+        BigInteger dividend0 = ECConstants.ONE.add(ui[1]).shiftRight(shifts);
+        BigInteger dividend1 = ECConstants.ONE.add(ui[0]).shiftRight(shifts).negate();
+
+        return new BigInteger[] { dividend0, dividend1 };
+    }
+
+    public static BigInteger[] getSi(int fieldSize, int curveA, BigInteger cofactor)
+    {
+        byte mu = getMu(curveA);
+        int shifts = getShiftsForCofactor(cofactor);
+        int index = fieldSize + 3 - curveA;
+        BigInteger[] ui = getLucas(mu, index, false);
+        if (mu == 1)
+        {
+            ui[0] = ui[0].negate();
+            ui[1] = ui[1].negate();
+        }
+
+        BigInteger dividend0 = ECConstants.ONE.add(ui[1]).shiftRight(shifts);
+        BigInteger dividend1 = ECConstants.ONE.add(ui[0]).shiftRight(shifts).negate();
+
+        return new BigInteger[] { dividend0, dividend1 };
+    }
+
+    protected static int getShiftsForCofactor(BigInteger h)
+    {
+        if (h != null)
+        {
+            if (h.equals(ECConstants.TWO))
+            {
+                return 1;
+            }
+            if (h.equals(ECConstants.FOUR))
+            {
+                return 2;
+            }
+        }
+
+        throw new IllegalArgumentException("h (Cofactor) must be 2 or 4");
+    }
+
+    /**
+     * Partial modular reduction modulo
+     * <code>(&tau;<sup>m</sup> - 1)/(&tau; - 1)</code>.
+     * @param k The integer to be reduced.
+     * @param m The bitlength of the underlying finite field.
+     * @param a The parameter <code>a</code> of the elliptic curve.
+     * @param s The auxiliary values <code>s<sub>0</sub></code> and
+     * <code>s<sub>1</sub></code>.
+     * @param mu The parameter &mu; of the elliptic curve.
+     * @param c The precision (number of bits of accuracy) of the partial
+     * modular reduction.
+     * @return <code>&rho; := k partmod (&tau;<sup>m</sup> - 1)/(&tau; - 1)</code>
+     */
+    public static ZTauElement partModReduction(BigInteger k, int m, byte a,
+            BigInteger[] s, byte mu, byte c)
+    {
+        // d0 = s[0] + mu*s[1]; mu is either 1 or -1
+        BigInteger d0;
+        if (mu == 1)
+        {
+            d0 = s[0].add(s[1]);
+        }
+        else
+        {
+            d0 = s[0].subtract(s[1]);
+        }
+
+        BigInteger[] v = getLucas(mu, m, true);
+        BigInteger vm = v[1];
+
+        SimpleBigDecimal lambda0 = approximateDivisionByN(
+                k, s[0], vm, a, m, c);
+        
+        SimpleBigDecimal lambda1 = approximateDivisionByN(
+                k, s[1], vm, a, m, c);
+
+        ZTauElement q = round(lambda0, lambda1, mu);
+
+        // r0 = n - d0*q0 - 2*s1*q1
+        BigInteger r0 = k.subtract(d0.multiply(q.u)).subtract(
+                BigInteger.valueOf(2).multiply(s[1]).multiply(q.v));
+
+        // r1 = s1*q0 - s0*q1
+        BigInteger r1 = s[1].multiply(q.u).subtract(s[0].multiply(q.v));
+        
+        return new ZTauElement(r0, r1);
+    }
+
+    /**
+     * Multiplies a {@link com.android.internal.org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m}
+     * by a <code>BigInteger</code> using the reduced <code>&tau;</code>-adic
+     * NAF (RTNAF) method.
+     * @param p The ECPoint.AbstractF2m to multiply.
+     * @param k The <code>BigInteger</code> by which to multiply <code>p</code>.
+     * @return <code>k * p</code>
+     */
+    public static ECPoint.AbstractF2m multiplyRTnaf(ECPoint.AbstractF2m p, BigInteger k)
+    {
+        ECCurve.AbstractF2m curve = (ECCurve.AbstractF2m) p.getCurve();
+        int m = curve.getFieldSize();
+        int a = curve.getA().toBigInteger().intValue();
+        byte mu = getMu(a);
+        BigInteger[] s = curve.getSi();
+        ZTauElement rho = partModReduction(k, m, (byte)a, s, mu, (byte)10);
+
+        return multiplyTnaf(p, rho);
+    }
+
+    /**
+     * Multiplies a {@link com.android.internal.org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m}
+     * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>
+     * using the <code>&tau;</code>-adic NAF (TNAF) method.
+     * @param p The ECPoint.AbstractF2m to multiply.
+     * @param lambda The element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code>.
+     * @return <code>&lambda; * p</code>
+     */
+    public static ECPoint.AbstractF2m multiplyTnaf(ECPoint.AbstractF2m p, ZTauElement lambda)
+    {
+        ECCurve.AbstractF2m curve = (ECCurve.AbstractF2m)p.getCurve();
+        byte mu = getMu(curve.getA());
+        byte[] u = tauAdicNaf(mu, lambda);
+
+        ECPoint.AbstractF2m q = multiplyFromTnaf(p, u);
+
+        return q;
+    }
+
+    /**
+    * Multiplies a {@link com.android.internal.org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m}
+    * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>
+    * using the <code>&tau;</code>-adic NAF (TNAF) method, given the TNAF
+    * of <code>&lambda;</code>.
+    * @param p The ECPoint.AbstractF2m to multiply.
+    * @param u The the TNAF of <code>&lambda;</code>..
+    * @return <code>&lambda; * p</code>
+    */
+    public static ECPoint.AbstractF2m multiplyFromTnaf(ECPoint.AbstractF2m p, byte[] u)
+    {
+        ECCurve curve = p.getCurve();
+        ECPoint.AbstractF2m q = (ECPoint.AbstractF2m)curve.getInfinity();
+        ECPoint.AbstractF2m pNeg = (ECPoint.AbstractF2m)p.negate();
+        int tauCount = 0;
+        for (int i = u.length - 1; i >= 0; i--)
+        {
+            ++tauCount;
+            byte ui = u[i];
+            if (ui != 0)
+            {
+                q = q.tauPow(tauCount);
+                tauCount = 0;
+
+                ECPoint x = ui > 0 ? p : pNeg;
+                q = (ECPoint.AbstractF2m)q.add(x);
+            }
+        }
+        if (tauCount > 0)
+        {
+            q = q.tauPow(tauCount);
+        }
+        return q;
+    }
+
+    /**
+     * Computes the <code>[&tau;]</code>-adic window NAF of an element
+     * <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>.
+     * @param mu The parameter &mu; of the elliptic curve.
+     * @param lambda The element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code> of which to compute the
+     * <code>[&tau;]</code>-adic NAF.
+     * @param width The window width of the resulting WNAF.
+     * @param pow2w 2<sup>width</sup>.
+     * @param tw The auxiliary value <code>t<sub>w</sub></code>.
+     * @param alpha The <code>&alpha;<sub>u</sub></code>'s for the window width.
+     * @return The <code>[&tau;]</code>-adic window NAF of
+     * <code>&lambda;</code>.
+     */
+    public static byte[] tauAdicWNaf(byte mu, ZTauElement lambda,
+            byte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
+    {
+        if (!((mu == 1) || (mu == -1)))
+        {
+            throw new IllegalArgumentException("mu must be 1 or -1");
+        }
+
+        BigInteger norm = norm(mu, lambda);
+
+        // Ceiling of log2 of the norm 
+        int log2Norm = norm.bitLength();
+
+        // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+        int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width;
+
+        // The array holding the TNAF
+        byte[] u = new byte[maxLength];
+
+        // 2^(width - 1)
+        BigInteger pow2wMin1 = pow2w.shiftRight(1);
+
+        // Split lambda into two BigIntegers to simplify calculations
+        BigInteger r0 = lambda.u;
+        BigInteger r1 = lambda.v;
+        int i = 0;
+
+        // while lambda <> (0, 0)
+        while (!((r0.equals(ECConstants.ZERO))&&(r1.equals(ECConstants.ZERO))))
+        {
+            // if r0 is odd
+            if (r0.testBit(0))
+            {
+                // uUnMod = r0 + r1*tw mod 2^width
+                BigInteger uUnMod
+                    = r0.add(r1.multiply(tw)).mod(pow2w);
+                
+                byte uLocal;
+                // if uUnMod >= 2^(width - 1)
+                if (uUnMod.compareTo(pow2wMin1) >= 0)
+                {
+                    uLocal = (byte) uUnMod.subtract(pow2w).intValue();
+                }
+                else
+                {
+                    uLocal = (byte) uUnMod.intValue();
+                }
+                // uLocal is now in [-2^(width-1), 2^(width-1)-1]
+
+                u[i] = uLocal;
+                boolean s = true;
+                if (uLocal < 0)
+                {
+                    s = false;
+                    uLocal = (byte)-uLocal;
+                }
+                // uLocal is now >= 0
+
+                if (s)
+                {
+                    r0 = r0.subtract(alpha[uLocal].u);
+                    r1 = r1.subtract(alpha[uLocal].v);
+                }
+                else
+                {
+                    r0 = r0.add(alpha[uLocal].u);
+                    r1 = r1.add(alpha[uLocal].v);
+                }
+            }
+            else
+            {
+                u[i] = 0;
+            }
+
+            BigInteger t = r0;
+
+            if (mu == 1)
+            {
+                r0 = r1.add(r0.shiftRight(1));
+            }
+            else
+            {
+                // mu == -1
+                r0 = r1.subtract(r0.shiftRight(1));
+            }
+            r1 = t.shiftRight(1).negate();
+            i++;
+        }
+        return u;
+    }
+
+    /**
+     * Does the precomputation for WTNAF multiplication.
+     * @param p The <code>ECPoint</code> for which to do the precomputation.
+     * @param a The parameter <code>a</code> of the elliptic curve.
+     * @return The precomputation array for <code>p</code>. 
+     */
+    public static ECPoint.AbstractF2m[] getPreComp(ECPoint.AbstractF2m p, byte a)
+    {
+        byte[][] alphaTnaf = (a == 0) ? Tnaf.alpha0Tnaf : Tnaf.alpha1Tnaf;
+
+        ECPoint.AbstractF2m[] pu = new ECPoint.AbstractF2m[(alphaTnaf.length + 1) >>> 1];
+        pu[0] = p;
+
+        int precompLen = alphaTnaf.length;
+        for (int i = 3; i < precompLen; i += 2)
+        {
+            pu[i >>> 1] = Tnaf.multiplyFromTnaf(p, alphaTnaf[i]);
+        }
+
+        p.getCurve().normalizeAll(pu);
+
+        return pu;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ValidityPrecompInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ValidityPrecompInfo.java
new file mode 100644
index 0000000..183c11a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ValidityPrecompInfo.java
@@ -0,0 +1,41 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+class ValidityPrecompInfo implements PreCompInfo
+{
+    static final String PRECOMP_NAME = "bc_validity";
+
+    private boolean failed = false;
+    private boolean curveEquationPassed = false;
+    private boolean orderPassed = false;
+
+    boolean hasFailed()
+    {
+        return failed;
+    }
+
+    void reportFailed()
+    {
+        failed = true;
+    }
+
+    boolean hasCurveEquationPassed()
+    {
+        return curveEquationPassed;
+    }
+
+    void reportCurveEquationPassed()
+    {
+        curveEquationPassed = true;
+    }
+
+    boolean hasOrderPassed()
+    {
+        return orderPassed;
+    }
+
+    void reportOrderPassed()
+    {
+        orderPassed = true;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WNafL2RMultiplier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WNafL2RMultiplier.java
new file mode 100644
index 0000000..04b785d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WNafL2RMultiplier.java
@@ -0,0 +1,98 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the WNAF (Window Non-Adjacent Form) multiplication
+ * algorithm.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class WNafL2RMultiplier extends AbstractECMultiplier
+{
+    /**
+     * Multiplies <code>this</code> by an integer <code>k</code> using the
+     * Window NAF method.
+     * @param k The integer by which <code>this</code> is multiplied.
+     * @return A new <code>ECPoint</code> which equals <code>this</code>
+     * multiplied by <code>k</code>.
+     */
+    protected ECPoint multiplyPositive(ECPoint p, BigInteger k)
+    {
+        // Clamp the window width in the range [2, 16]
+        int width = Math.max(2, Math.min(16, getWindowSize(k.bitLength())));
+
+        WNafPreCompInfo wnafPreCompInfo = WNafUtil.precompute(p, width, true);
+        ECPoint[] preComp = wnafPreCompInfo.getPreComp();
+        ECPoint[] preCompNeg = wnafPreCompInfo.getPreCompNeg();
+
+        int[] wnaf = WNafUtil.generateCompactWindowNaf(width, k);
+
+        ECPoint R = p.getCurve().getInfinity();
+
+        int i = wnaf.length;
+
+        /*
+         * NOTE: We try to optimize the first window using the precomputed points to substitute an
+         * addition for 2 or more doublings.
+         */
+        if (i > 1)
+        {
+            int wi = wnaf[--i];
+            int digit = wi >> 16, zeroes = wi & 0xFFFF;
+
+            int n = Math.abs(digit);
+            ECPoint[] table = digit < 0 ? preCompNeg : preComp;
+
+            // Optimization can only be used for values in the lower half of the table
+            if ((n << 2) < (1 << width))
+            {
+                int highest = LongArray.bitLengths[n];
+
+                // TODO Get addition/doubling cost ratio from curve and compare to 'scale' to see if worth substituting?
+                int scale = width - highest;
+                int lowBits =  n ^ (1 << (highest - 1));
+
+                int i1 = ((1 << (width - 1)) - 1);
+                int i2 = (lowBits << scale) + 1;
+                R = table[i1 >>> 1].add(table[i2 >>> 1]);
+
+                zeroes -= scale;
+
+//              System.out.println("Optimized: 2^" + scale + " * " + n + " = " + i1 + " + " + i2);
+            }
+            else
+            {
+                R = table[n >>> 1];
+            }
+
+            R = R.timesPow2(zeroes);
+        }
+
+        while (i > 0)
+        {
+            int wi = wnaf[--i];
+            int digit = wi >> 16, zeroes = wi & 0xFFFF;
+
+            int n = Math.abs(digit);
+            ECPoint[] table = digit < 0 ? preCompNeg : preComp;
+            ECPoint r = table[n >>> 1];
+
+            R = R.twicePlus(r);
+            R = R.timesPow2(zeroes);
+        }
+
+        return R;
+    }
+
+    /**
+     * Determine window width to use for a scalar multiplication of the given size.
+     * 
+     * @param bits the bit-length of the scalar to multiply by
+     * @return the window size to use
+     */
+    protected int getWindowSize(int bits)
+    {
+        return WNafUtil.getWindowSize(bits);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WNafPreCompInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WNafPreCompInfo.java
new file mode 100644
index 0000000..4a0dfec
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WNafPreCompInfo.java
@@ -0,0 +1,58 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+/**
+ * Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
+ * algorithm.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class WNafPreCompInfo implements PreCompInfo
+{
+    /**
+     * Array holding the precomputed <code>ECPoint</code>s used for a Window
+     * NAF multiplication.
+     */
+    protected ECPoint[] preComp = null;
+
+    /**
+     * Array holding the negations of the precomputed <code>ECPoint</code>s used
+     * for a Window NAF multiplication.
+     */
+    protected ECPoint[] preCompNeg = null;
+
+    /**
+     * Holds an <code>ECPoint</code> representing twice(this). Used for the
+     * Window NAF multiplication to create or extend the precomputed values.
+     */
+    protected ECPoint twice = null;
+
+    public ECPoint[] getPreComp()
+    {
+        return preComp;
+    }
+
+    public void setPreComp(ECPoint[] preComp)
+    {
+        this.preComp = preComp;
+    }
+
+    public ECPoint[] getPreCompNeg()
+    {
+        return preCompNeg;
+    }
+
+    public void setPreCompNeg(ECPoint[] preCompNeg)
+    {
+        this.preCompNeg = preCompNeg;
+    }
+
+    public ECPoint getTwice()
+    {
+        return twice;
+    }
+
+    public void setTwice(ECPoint twice)
+    {
+        this.twice = twice;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WNafUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WNafUtil.java
new file mode 100644
index 0000000..2569817
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WNafUtil.java
@@ -0,0 +1,575 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class WNafUtil
+{
+    public static final String PRECOMP_NAME = "bc_wnaf";
+
+    private static final int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 };
+
+    private static final byte[] EMPTY_BYTES = new byte[0];
+    private static final int[] EMPTY_INTS = new int[0];
+    private static final ECPoint[] EMPTY_POINTS = new ECPoint[0];
+
+    public static int[] generateCompactNaf(BigInteger k)
+    {
+        if ((k.bitLength() >>> 16) != 0)
+        {
+            throw new IllegalArgumentException("'k' must have bitlength < 2^16");
+        }
+        if (k.signum() == 0)
+        {
+            return EMPTY_INTS;
+        }
+
+        BigInteger _3k = k.shiftLeft(1).add(k);
+
+        int bits = _3k.bitLength();
+        int[] naf = new int[bits >> 1];
+
+        BigInteger diff = _3k.xor(k);
+
+        int highBit = bits - 1, length = 0, zeroes = 0;
+        for (int i = 1; i < highBit; ++i)
+        {
+            if (!diff.testBit(i))
+            {
+                ++zeroes;
+                continue;
+            }
+
+            int digit  = k.testBit(i) ? -1 : 1;
+            naf[length++] = (digit << 16) | zeroes;
+            zeroes = 1;
+            ++i;
+        }
+
+        naf[length++] = (1 << 16) | zeroes;
+
+        if (naf.length > length)
+        {
+            naf = trim(naf, length);
+        }
+
+        return naf;
+    }
+
+    public static int[] generateCompactWindowNaf(int width, BigInteger k)
+    {
+        if (width == 2)
+        {
+            return generateCompactNaf(k);
+        }
+
+        if (width < 2 || width > 16)
+        {
+            throw new IllegalArgumentException("'width' must be in the range [2, 16]");
+        }
+        if ((k.bitLength() >>> 16) != 0)
+        {
+            throw new IllegalArgumentException("'k' must have bitlength < 2^16");
+        }
+        if (k.signum() == 0)
+        {
+            return EMPTY_INTS;
+        }
+
+        int[] wnaf = new int[k.bitLength() / width + 1];
+
+        // 2^width and a mask and sign bit set accordingly
+        int pow2 = 1 << width;
+        int mask = pow2 - 1;
+        int sign = pow2 >>> 1;
+
+        boolean carry = false;
+        int length = 0, pos = 0;
+
+        while (pos <= k.bitLength())
+        {
+            if (k.testBit(pos) == carry)
+            {
+                ++pos;
+                continue;
+            }
+
+            k = k.shiftRight(pos);
+
+            int digit = k.intValue() & mask;
+            if (carry)
+            {
+                ++digit;
+            }
+
+            carry = (digit & sign) != 0;
+            if (carry)
+            {
+                digit -= pow2;
+            }
+
+            int zeroes = length > 0 ? pos - 1 : pos;
+            wnaf[length++] = (digit << 16) | zeroes;
+            pos = width;
+        }
+
+        // Reduce the WNAF array to its actual length
+        if (wnaf.length > length)
+        {
+            wnaf = trim(wnaf, length);
+        }
+
+        return wnaf;
+    }
+
+    public static byte[] generateJSF(BigInteger g, BigInteger h)
+    {
+        int digits = Math.max(g.bitLength(), h.bitLength()) + 1;
+        byte[] jsf = new byte[digits];
+
+        BigInteger k0 = g, k1 = h;
+        int j = 0, d0 = 0, d1 = 0;
+
+        int offset = 0;
+        while ((d0 | d1) != 0 || k0.bitLength() > offset || k1.bitLength() > offset)
+        {
+            int n0 = ((k0.intValue() >>> offset) + d0) & 7, n1 = ((k1.intValue() >>> offset) + d1) & 7;
+
+            int u0 = n0 & 1;
+            if (u0 != 0)
+            {
+                u0 -= (n0 & 2);
+                if ((n0 + u0) == 4 && (n1 & 3) == 2)
+                {
+                    u0 = -u0;
+                }
+            }
+
+            int u1 = n1 & 1;
+            if (u1 != 0)
+            {
+                u1 -= (n1 & 2);
+                if ((n1 + u1) == 4 && (n0 & 3) == 2)
+                {
+                    u1 = -u1;
+                }
+            }
+
+            if ((d0 << 1) == 1 + u0)
+            {
+                d0 ^= 1;
+            }
+            if ((d1 << 1) == 1 + u1)
+            {
+                d1 ^= 1;
+            }
+
+            if (++offset == 30)
+            {
+                offset = 0;
+                k0 = k0.shiftRight(30);
+                k1 = k1.shiftRight(30);
+            }
+
+            jsf[j++] = (byte)((u0 << 4) | (u1 & 0xF));
+        }
+
+        // Reduce the JSF array to its actual length
+        if (jsf.length > j)
+        {
+            jsf = trim(jsf, j);
+        }
+
+        return jsf;
+    }
+
+    public static byte[] generateNaf(BigInteger k)
+    {
+        if (k.signum() == 0)
+        {
+            return EMPTY_BYTES;
+        }
+
+        BigInteger _3k = k.shiftLeft(1).add(k);
+
+        int digits = _3k.bitLength() - 1;
+        byte[] naf = new byte[digits];
+
+        BigInteger diff = _3k.xor(k);
+
+        for (int i = 1; i < digits; ++i)
+        {
+            if (diff.testBit(i))
+            {
+                naf[i - 1] = (byte)(k.testBit(i) ? -1 : 1);
+                ++i;
+            }
+        }
+
+        naf[digits - 1] = 1;
+
+        return naf;
+    }
+
+    /**
+     * Computes the Window NAF (non-adjacent Form) of an integer.
+     * @param width The width <code>w</code> of the Window NAF. The width is
+     * defined as the minimal number <code>w</code>, such that for any
+     * <code>w</code> consecutive digits in the resulting representation, at
+     * most one is non-zero.
+     * @param k The integer of which the Window NAF is computed.
+     * @return The Window NAF of the given width, such that the following holds:
+     * <code>k = &sum;<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup>
+     * </code>, where the <code>k<sub>i</sub></code> denote the elements of the
+     * returned <code>byte[]</code>.
+     */
+    public static byte[] generateWindowNaf(int width, BigInteger k)
+    {
+        if (width == 2)
+        {
+            return generateNaf(k);
+        }
+
+        if (width < 2 || width > 8)
+        {
+            throw new IllegalArgumentException("'width' must be in the range [2, 8]");
+        }
+        if (k.signum() == 0)
+        {
+            return EMPTY_BYTES;
+        }
+
+        byte[] wnaf = new byte[k.bitLength() + 1];
+
+        // 2^width and a mask and sign bit set accordingly
+        int pow2 = 1 << width;
+        int mask = pow2 - 1;
+        int sign = pow2 >>> 1;
+
+        boolean carry = false;
+        int length = 0, pos = 0;
+
+        while (pos <= k.bitLength())
+        {
+            if (k.testBit(pos) == carry)
+            {
+                ++pos;
+                continue;
+            }
+
+            k = k.shiftRight(pos);
+
+            int digit = k.intValue() & mask;
+            if (carry)
+            {
+                ++digit;
+            }
+
+            carry = (digit & sign) != 0;
+            if (carry)
+            {
+                digit -= pow2;
+            }
+
+            length += (length > 0) ? pos - 1 : pos;
+            wnaf[length++] = (byte)digit;
+            pos = width;
+        }
+
+        // Reduce the WNAF array to its actual length
+        if (wnaf.length > length)
+        {
+            wnaf = trim(wnaf, length);
+        }
+        
+        return wnaf;
+    }
+
+    public static int getNafWeight(BigInteger k)
+    {
+        if (k.signum() == 0)
+        {
+            return 0;
+        }
+
+        BigInteger _3k = k.shiftLeft(1).add(k);
+        BigInteger diff = _3k.xor(k);
+
+        return diff.bitCount();
+    }
+
+    public static WNafPreCompInfo getWNafPreCompInfo(ECPoint p)
+    {
+        return getWNafPreCompInfo(p.getCurve().getPreCompInfo(p, PRECOMP_NAME));
+    }
+
+    public static WNafPreCompInfo getWNafPreCompInfo(PreCompInfo preCompInfo)
+    {
+        return (preCompInfo instanceof WNafPreCompInfo) ? (WNafPreCompInfo)preCompInfo : null;
+    }
+
+    /**
+     * Determine window width to use for a scalar multiplication of the given size.
+     * 
+     * @param bits the bit-length of the scalar to multiply by
+     * @return the window size to use
+     */
+    public static int getWindowSize(int bits)
+    {
+        return getWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS);
+    }
+
+    /**
+     * Determine window width to use for a scalar multiplication of the given size.
+     * 
+     * @param bits the bit-length of the scalar to multiply by
+     * @param windowSizeCutoffs a monotonically increasing list of bit sizes at which to increment the window width
+     * @return the window size to use
+     */
+    public static int getWindowSize(int bits, int[] windowSizeCutoffs)
+    {
+        int w = 0;
+        for (; w < windowSizeCutoffs.length; ++w)
+        {
+            if (bits < windowSizeCutoffs[w])
+            {
+                break;
+            }
+        }
+        return w + 2;
+    }
+
+    public static ECPoint mapPointWithPrecomp(ECPoint p, final int width, final boolean includeNegated,
+        final ECPointMap pointMap)
+    {
+        final ECCurve c = p.getCurve();
+        final WNafPreCompInfo wnafPreCompP = precompute(p, width, includeNegated);
+
+        ECPoint q = pointMap.map(p);
+        c.precompute(q, PRECOMP_NAME, new PreCompCallback()
+        {
+            public PreCompInfo precompute(PreCompInfo existing)
+            {
+                WNafPreCompInfo result = new WNafPreCompInfo();
+
+                ECPoint twiceP = wnafPreCompP.getTwice();
+                if (twiceP != null)
+                {
+                    ECPoint twiceQ = pointMap.map(twiceP);
+                    result.setTwice(twiceQ);
+                }
+
+                ECPoint[] preCompP = wnafPreCompP.getPreComp();
+                ECPoint[] preCompQ = new ECPoint[preCompP.length];
+                for (int i = 0; i < preCompP.length; ++i)
+                {
+                    preCompQ[i] = pointMap.map(preCompP[i]);
+                }
+                result.setPreComp(preCompQ);
+
+                if (includeNegated)
+                {
+                    ECPoint[] preCompNegQ = new ECPoint[preCompQ.length];
+                    for (int i = 0; i < preCompNegQ.length; ++i)
+                    {
+                        preCompNegQ[i] = preCompQ[i].negate();
+                    }
+                    result.setPreCompNeg(preCompNegQ);
+                }
+
+                return result;
+            }
+        });
+
+        return q;
+    }
+
+    public static WNafPreCompInfo precompute(final ECPoint p, final int width, final boolean includeNegated)
+    {
+        final ECCurve c = p.getCurve();
+
+        return (WNafPreCompInfo)c.precompute(p, PRECOMP_NAME, new PreCompCallback()
+        {
+            public PreCompInfo precompute(PreCompInfo existing)
+            {
+                WNafPreCompInfo existingWNaf = (existing instanceof WNafPreCompInfo) ? (WNafPreCompInfo)existing : null;
+
+                int reqPreCompLen = 1 << Math.max(0, width - 2);
+
+                if (checkExisting(existingWNaf, reqPreCompLen, includeNegated))
+                {
+                    return existingWNaf;
+                }
+
+                ECPoint[] preComp = null, preCompNeg = null;
+                ECPoint twiceP = null;
+
+                if (existingWNaf != null)
+                {
+                    preComp = existingWNaf.getPreComp();
+                    preCompNeg = existingWNaf.getPreCompNeg();
+                    twiceP = existingWNaf.getTwice();
+                }
+
+                int iniPreCompLen = 0;
+                if (preComp == null)
+                {
+                    preComp = EMPTY_POINTS;
+                }
+                else
+                {
+                    iniPreCompLen = preComp.length;
+                }
+
+                if (iniPreCompLen < reqPreCompLen)
+                {
+                    preComp = resizeTable(preComp, reqPreCompLen);
+
+                    if (reqPreCompLen == 1)
+                    {
+                        preComp[0] = p.normalize();
+                    }
+                    else
+                    {
+                        int curPreCompLen = iniPreCompLen;
+                        if (curPreCompLen == 0)
+                        {
+                            preComp[0] = p;
+                            curPreCompLen = 1;
+                        }
+
+                        ECFieldElement iso = null;
+
+                        if (reqPreCompLen == 2)
+                        {
+                            preComp[1] = p.threeTimes();
+                        }
+                        else
+                        {
+                            ECPoint isoTwiceP = twiceP, last = preComp[curPreCompLen - 1];
+                            if (isoTwiceP == null)
+                            {
+                                isoTwiceP = preComp[0].twice();
+                                twiceP = isoTwiceP;
+
+                                /*
+                                 * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism
+                                 * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This
+                                 * also requires scaling the initial point's X, Y coordinates, and reversing the
+                                 * isomorphism as part of the subsequent normalization.
+                                 * 
+                                 *  NOTE: The correctness of this optimization depends on:
+                                 *      1) additions do not use the curve's A, B coefficients.
+                                 *      2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ...
+                                 */
+                                if (!twiceP.isInfinity() && ECAlgorithms.isFpCurve(c) && c.getFieldSize() >= 64)
+                                {
+                                    switch (c.getCoordinateSystem())
+                                    {
+                                    case ECCurve.COORD_JACOBIAN:
+                                    case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+                                    case ECCurve.COORD_JACOBIAN_MODIFIED:
+                                    {
+                                        iso = twiceP.getZCoord(0);
+                                        isoTwiceP = c.createPoint(twiceP.getXCoord().toBigInteger(), twiceP.getYCoord()
+                                            .toBigInteger());
+
+                                        ECFieldElement iso2 = iso.square(), iso3 = iso2.multiply(iso);
+                                        last = last.scaleX(iso2).scaleY(iso3);
+
+                                        if (iniPreCompLen == 0)
+                                        {
+                                            preComp[0] = last;
+                                        }
+                                        break;
+                                    }
+                                    }
+                                }
+                            }
+
+                            while (curPreCompLen < reqPreCompLen)
+                            {
+                                /*
+                                 * Compute the new ECPoints for the precomputation array. The values 1, 3,
+                                 * 5, ..., 2^(width-1)-1 times p are computed
+                                 */
+                                preComp[curPreCompLen++] = last = last.add(isoTwiceP);
+                            }
+                        }
+
+                        /*
+                         * Having oft-used operands in affine form makes operations faster.
+                         */
+                        c.normalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso);
+                    }
+                }
+
+                if (includeNegated)
+                {
+                    int pos;
+                    if (preCompNeg == null)
+                    {
+                        pos = 0;
+                        preCompNeg = new ECPoint[reqPreCompLen]; 
+                    }
+                    else
+                    {
+                        pos = preCompNeg.length;
+                        if (pos < reqPreCompLen)
+                        {
+                            preCompNeg = resizeTable(preCompNeg, reqPreCompLen);
+                        }
+                    }
+
+                    while (pos < reqPreCompLen)
+                    {
+                        preCompNeg[pos] = preComp[pos].negate();
+                        ++pos;
+                    }
+                }
+
+                WNafPreCompInfo result = new WNafPreCompInfo();
+                result.setPreComp(preComp);
+                result.setPreCompNeg(preCompNeg);
+                result.setTwice(twiceP);
+                return result;
+            }
+
+            private boolean checkExisting(WNafPreCompInfo existingWNaf, int reqPreCompLen, boolean includeNegated)
+            {
+                return existingWNaf != null
+                    && checkTable(existingWNaf.getPreComp(), reqPreCompLen)
+                    && (!includeNegated || checkTable(existingWNaf.getPreCompNeg(), reqPreCompLen));
+            }
+
+            private boolean checkTable(ECPoint[] table, int reqLen)
+            {
+                return table != null && table.length >= reqLen;
+            }
+        });
+    }
+
+    private static byte[] trim(byte[] a, int length)
+    {
+        byte[] result = new byte[length];
+        System.arraycopy(a, 0, result, 0, result.length);
+        return result;
+    }
+
+    private static int[] trim(int[] a, int length)
+    {
+        int[] result = new int[length];
+        System.arraycopy(a, 0, result, 0, result.length);
+        return result;
+    }
+
+    private static ECPoint[] resizeTable(ECPoint[] a, int length)
+    {
+        ECPoint[] result = new ECPoint[length];
+        System.arraycopy(a, 0, result, 0, a.length);
+        return result;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WTauNafMultiplier.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WTauNafMultiplier.java
new file mode 100644
index 0000000..43308b1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WTauNafMultiplier.java
@@ -0,0 +1,128 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the WTNAF (Window
+ * <code>&tau;</code>-adic Non-Adjacent Form) algorithm.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class WTauNafMultiplier extends AbstractECMultiplier
+{
+    // TODO Create WTauNafUtil class and move various functionality into it
+    static final String PRECOMP_NAME = "bc_wtnaf";
+
+    /**
+     * Multiplies a {@link com.android.internal.org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m}
+     * by <code>k</code> using the reduced <code>&tau;</code>-adic NAF (RTNAF)
+     * method.
+     * @param point The ECPoint.AbstractF2m to multiply.
+     * @param k The integer by which to multiply <code>k</code>.
+     * @return <code>p</code> multiplied by <code>k</code>.
+     */
+    protected ECPoint multiplyPositive(ECPoint point, BigInteger k)
+    {
+        if (!(point instanceof ECPoint.AbstractF2m))
+        {
+            throw new IllegalArgumentException("Only ECPoint.AbstractF2m can be " +
+                    "used in WTauNafMultiplier");
+        }
+
+        ECPoint.AbstractF2m p = (ECPoint.AbstractF2m)point;
+        ECCurve.AbstractF2m curve = (ECCurve.AbstractF2m)p.getCurve();
+        int m = curve.getFieldSize();
+        byte a = curve.getA().toBigInteger().byteValue();
+        byte mu = Tnaf.getMu(a);
+        BigInteger[] s = curve.getSi();
+
+        ZTauElement rho = Tnaf.partModReduction(k, m, a, s, mu, (byte)10);
+
+        return multiplyWTnaf(p, rho, a, mu);
+    }
+
+    /**
+     * Multiplies a {@link com.android.internal.org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m}
+     * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code> using
+     * the <code>&tau;</code>-adic NAF (TNAF) method.
+     * @param p The ECPoint.AbstractF2m to multiply.
+     * @param lambda The element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code> of which to compute the
+     * <code>[&tau;]</code>-adic NAF.
+     * @return <code>p</code> multiplied by <code>&lambda;</code>.
+     */
+    private ECPoint.AbstractF2m multiplyWTnaf(ECPoint.AbstractF2m p, ZTauElement lambda, byte a, byte mu)
+    {
+        ZTauElement[] alpha = (a == 0) ? Tnaf.alpha0 : Tnaf.alpha1;
+
+        BigInteger tw = Tnaf.getTw(mu, Tnaf.WIDTH);
+
+        byte[]u = Tnaf.tauAdicWNaf(mu, lambda, Tnaf.WIDTH,
+            BigInteger.valueOf(Tnaf.POW_2_WIDTH), tw, alpha);
+
+        return multiplyFromWTnaf(p, u);
+    }
+
+    /**
+     * Multiplies a {@link com.android.internal.org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m}
+     * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>
+     * using the window <code>&tau;</code>-adic NAF (TNAF) method, given the
+     * WTNAF of <code>&lambda;</code>.
+     * @param p The ECPoint.AbstractF2m to multiply.
+     * @param u The the WTNAF of <code>&lambda;</code>..
+     * @return <code>&lambda; * p</code>
+     */
+    private static ECPoint.AbstractF2m multiplyFromWTnaf(final ECPoint.AbstractF2m p, byte[] u)
+    {
+        ECCurve.AbstractF2m curve = (ECCurve.AbstractF2m)p.getCurve();
+        final byte a = curve.getA().toBigInteger().byteValue();
+
+        WTauNafPreCompInfo preCompInfo = (WTauNafPreCompInfo)curve.precompute(p, PRECOMP_NAME, new PreCompCallback()
+        {
+            public PreCompInfo precompute(PreCompInfo existing)
+            {
+                if (existing instanceof WTauNafPreCompInfo)
+                {
+                    return existing;
+                }
+
+                WTauNafPreCompInfo result = new WTauNafPreCompInfo();
+                result.setPreComp(Tnaf.getPreComp(p, a));
+                return result;
+            }
+        });
+
+        ECPoint.AbstractF2m[] pu = preCompInfo.getPreComp();
+
+        // TODO Include negations in precomp (optionally) and use from here
+        ECPoint.AbstractF2m[] puNeg = new ECPoint.AbstractF2m[pu.length];
+        for (int i = 0; i < pu.length; ++i)
+        {
+            puNeg[i] = (ECPoint.AbstractF2m)pu[i].negate();
+        }
+
+
+        // q = infinity
+        ECPoint.AbstractF2m q = (ECPoint.AbstractF2m) p.getCurve().getInfinity();
+
+        int tauCount = 0;
+        for (int i = u.length - 1; i >= 0; i--)
+        {
+            ++tauCount;
+            int ui = u[i];
+            if (ui != 0)
+            {
+                q = q.tauPow(tauCount);
+                tauCount = 0;
+
+                ECPoint x = ui > 0 ? pu[ui >>> 1] : puNeg[(-ui) >>> 1];
+                q = (ECPoint.AbstractF2m)q.add(x);
+            }
+        }
+        if (tauCount > 0)
+        {
+            q = q.tauPow(tauCount);
+        }
+        return q;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WTauNafPreCompInfo.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WTauNafPreCompInfo.java
new file mode 100644
index 0000000..498a91b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/WTauNafPreCompInfo.java
@@ -0,0 +1,26 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+/**
+ * Class holding precomputation data for the WTNAF (Window
+ * <code>&tau;</code>-adic Non-Adjacent Form) algorithm.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class WTauNafPreCompInfo implements PreCompInfo
+{
+    /**
+     * Array holding the precomputed <code>ECPoint.AbstractF2m</code>s used for the
+     * WTNAF multiplication.
+     */
+    protected ECPoint.AbstractF2m[] preComp = null;
+
+    public ECPoint.AbstractF2m[] getPreComp()
+    {
+        return preComp;
+    }
+
+    public void setPreComp(ECPoint.AbstractF2m[] preComp)
+    {
+        this.preComp = preComp;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ZTauElement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ZTauElement.java
new file mode 100644
index 0000000..cf2e8a4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/ZTauElement.java
@@ -0,0 +1,38 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class representing an element of <code><b>Z</b>[&tau;]</code>. Let
+ * <code>&lambda;</code> be an element of <code><b>Z</b>[&tau;]</code>. Then
+ * <code>&lambda;</code> is given as <code>&lambda; = u + v&tau;</code>. The
+ * components <code>u</code> and <code>v</code> may be used directly, there
+ * are no accessor methods.
+ * Immutable class.
+ */
+class ZTauElement
+{
+    /**
+     * The &quot;real&quot; part of <code>&lambda;</code>.
+     */
+    public final BigInteger u;
+
+    /**
+     * The &quot;<code>&tau;</code>-adic&quot; part of <code>&lambda;</code>.
+     */
+    public final BigInteger v;
+
+    /**
+     * Constructor for an element <code>&lambda;</code> of
+     * <code><b>Z</b>[&tau;]</code>.
+     * @param u The &quot;real&quot; part of <code>&lambda;</code>.
+     * @param v The &quot;<code>&tau;</code>-adic&quot; part of
+     * <code>&lambda;</code>.
+     */
+    public ZTauElement(BigInteger u, BigInteger v)
+    {
+        this.u = u;
+        this.v = v;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java
new file mode 100644
index 0000000..d8f410d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java
@@ -0,0 +1,130 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECConstants;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECLookupTable;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat192;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP192K1Curve extends ECCurve.AbstractFp
+{
+    public static final BigInteger q = new BigInteger(1,
+        Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37"));
+
+    private static final int SecP192K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+    protected SecP192K1Point infinity;
+
+    public SecP192K1Curve()
+    {
+        super(q);
+
+        this.infinity = new SecP192K1Point(this, null, null);
+
+        this.a = fromBigInteger(ECConstants.ZERO);
+        this.b = fromBigInteger(BigInteger.valueOf(3));
+        this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D"));
+        this.cofactor = BigInteger.valueOf(1);
+
+        this.coord = SecP192K1_DEFAULT_COORDS;
+    }
+
+    protected ECCurve cloneCurve()
+    {
+        return new SecP192K1Curve();
+    }
+
+    public boolean supportsCoordinateSystem(int coord)
+    {
+        switch (coord)
+        {
+        case COORD_JACOBIAN:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public int getFieldSize()
+    {
+        return q.bitLength();
+    }
+
+    public ECFieldElement fromBigInteger(BigInteger x)
+    {
+        return new SecP192K1FieldElement(x);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        return new SecP192K1Point(this, x, y, withCompression);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        return new SecP192K1Point(this, x, y, zs, withCompression);
+    }
+
+    public ECPoint getInfinity()
+    {
+        return infinity;
+    }
+
+    public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len)
+    {
+        final int FE_INTS = 6;
+
+        final int[] table = new int[len * FE_INTS * 2];
+        {
+            int pos = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                ECPoint p = points[off + i];
+                Nat192.copy(((SecP192K1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS;
+                Nat192.copy(((SecP192K1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS;
+            }
+        }
+
+        return new ECLookupTable()
+        {
+            public int getSize()
+            {
+                return len;
+            }
+
+            public ECPoint lookup(int index)
+            {
+                int[] x = Nat192.create(), y = Nat192.create();
+                int pos = 0;
+
+                for (int i = 0; i < len; ++i)
+                {
+                    int MASK = ((i ^ index) - 1) >> 31;
+
+                    for (int j = 0; j < FE_INTS; ++j)
+                    {
+                        x[j] ^= table[pos + j] & MASK;
+                        y[j] ^= table[pos + FE_INTS + j] & MASK;
+                    }
+
+                    pos += (FE_INTS * 2);
+                }
+
+                return createRawPoint(new SecP192K1FieldElement(x), new SecP192K1FieldElement(y), false);
+            }
+        };
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java
new file mode 100644
index 0000000..022bdcb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java
@@ -0,0 +1,181 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat192;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP192K1Field
+{
+    // 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
+    static final int[] P = new int[]{ 0xFFFFEE37, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+    static final int[] PExt = new int[]{ 0x013C4FD1, 0x00002392, 0x00000001, 0x00000000, 0x00000000,
+        0x00000000, 0xFFFFDC6E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+    private static final int[] PExtInv = new int[]{ 0xFEC3B02F, 0xFFFFDC6D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+        0xFFFFFFFF, 0x00002391, 0x00000002 };
+    private static final int P5 = 0xFFFFFFFF;
+    private static final int PExt11 = 0xFFFFFFFF;
+    private static final int PInv33 = 0x11C9;
+
+    public static void add(int[] x, int[] y, int[] z)
+    {
+        int c = Nat192.add(x, y, z);
+        if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
+        {
+            Nat.add33To(6, PInv33, z);
+        }
+    }
+
+    public static void addExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.add(12, xx, yy, zz);
+        if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt)))
+        {
+            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.incAt(12, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void addOne(int[] x, int[] z)
+    {
+        int c = Nat.inc(6, x, z);
+        if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
+        {
+            Nat.add33To(6, PInv33, z);
+        }
+    }
+
+    public static int[] fromBigInteger(BigInteger x)
+    {
+        int[] z = Nat192.fromBigInteger(x);
+        if (z[5] == P5 && Nat192.gte(z, P))
+        {
+            Nat192.subFrom(P, z);
+        }
+        return z;
+    }
+
+    public static void half(int[] x, int[] z)
+    {
+        if ((x[0] & 1) == 0)
+        {
+            Nat.shiftDownBit(6, x, 0, z);
+        }
+        else
+        {
+            int c = Nat192.add(x, P, z);
+            Nat.shiftDownBit(6, z, c);
+        }
+    }
+
+    public static void multiply(int[] x, int[] y, int[] z)
+    {
+        int[] tt = Nat192.createExt();
+        Nat192.mul(x, y, tt);
+        reduce(tt, z);
+    }
+
+    public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+    {
+        int c = Nat192.mulAddTo(x, y, zz);
+        if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt)))
+        {
+            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.incAt(12, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void negate(int[] x, int[] z)
+    {
+        if (Nat192.isZero(x))
+        {
+            Nat192.zero(z);
+        }
+        else
+        {
+            Nat192.sub(P, x, z);
+        }
+    }
+
+    public static void reduce(int[] xx, int[] z)
+    {
+        long cc = Nat192.mul33Add(PInv33, xx, 6, xx, 0, z, 0);
+        int c = Nat192.mul33DWordAdd(PInv33, cc, z, 0);
+
+        // assert c == 0L || c == 1L;
+
+        if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
+        {
+            Nat.add33To(6, PInv33, z);
+        }
+    }
+
+    public static void reduce32(int x, int[] z)
+    {
+        if ((x != 0 && Nat192.mul33WordAdd(PInv33, x, z, 0) != 0)
+            || (z[5] == P5 && Nat192.gte(z, P)))
+        {
+            Nat.add33To(6, PInv33, z);
+        }
+    }
+
+    public static void square(int[] x, int[] z)
+    {
+        int[] tt = Nat192.createExt();
+        Nat192.square(x, tt);
+        reduce(tt, z);
+    }
+
+    public static void squareN(int[] x, int n, int[] z)
+    {
+//        assert n > 0;
+
+        int[] tt = Nat192.createExt();
+        Nat192.square(x, tt);
+        reduce(tt, z);
+
+        while (--n > 0)
+        {
+            Nat192.square(z, tt);
+            reduce(tt, z);
+        }
+    }
+
+    public static void subtract(int[] x, int[] y, int[] z)
+    {
+        int c = Nat192.sub(x, y, z);
+        if (c != 0)
+        {
+            Nat.sub33From(6, PInv33, z);
+        }
+    }
+
+    public static void subtractExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.sub(12, xx, yy, zz);
+        if (c != 0)
+        {
+            if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.decAt(12, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void twice(int[] x, int[] z)
+    {
+        int c = Nat.shiftUpBit(6, x, 0, z);
+        if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
+        {
+            Nat.add33To(6, PInv33, z);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java
new file mode 100644
index 0000000..b8d8530
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java
@@ -0,0 +1,217 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.raw.Mod;
+import com.android.internal.org.bouncycastle.math.raw.Nat192;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP192K1FieldElement extends ECFieldElement.AbstractFp
+{
+    public static final BigInteger Q = SecP192K1Curve.q;
+
+    protected int[] x;
+
+    public SecP192K1FieldElement(BigInteger x)
+    {
+        if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+        {
+            throw new IllegalArgumentException("x value invalid for SecP192K1FieldElement");
+        }
+
+        this.x = SecP192K1Field.fromBigInteger(x);
+    }
+
+    public SecP192K1FieldElement()
+    {
+        this.x = Nat192.create();
+    }
+
+    protected SecP192K1FieldElement(int[] x)
+    {
+        this.x = x;
+    }
+
+    public boolean isZero()
+    {
+        return Nat192.isZero(x);
+    }
+
+    public boolean isOne()
+    {
+        return Nat192.isOne(x);
+    }
+
+    public boolean testBitZero()
+    {
+        return Nat192.getBit(x, 0) == 1;
+    }
+
+    public BigInteger toBigInteger()
+    {
+        return Nat192.toBigInteger(x);
+    }
+
+    public String getFieldName()
+    {
+        return "SecP192K1Field";
+    }
+
+    public int getFieldSize()
+    {
+        return Q.bitLength();
+    }
+
+    public ECFieldElement add(ECFieldElement b)
+    {
+        int[] z = Nat192.create();
+        SecP192K1Field.add(x, ((SecP192K1FieldElement)b).x, z);
+        return new SecP192K1FieldElement(z);
+    }
+
+    public ECFieldElement addOne()
+    {
+        int[] z = Nat192.create();
+        SecP192K1Field.addOne(x, z);
+        return new SecP192K1FieldElement(z);
+    }
+
+    public ECFieldElement subtract(ECFieldElement b)
+    {
+        int[] z = Nat192.create();
+        SecP192K1Field.subtract(x, ((SecP192K1FieldElement)b).x, z);
+        return new SecP192K1FieldElement(z);
+    }
+
+    public ECFieldElement multiply(ECFieldElement b)
+    {
+        int[] z = Nat192.create();
+        SecP192K1Field.multiply(x, ((SecP192K1FieldElement)b).x, z);
+        return new SecP192K1FieldElement(z);
+    }
+
+    public ECFieldElement divide(ECFieldElement b)
+    {
+//        return multiply(b.invert());
+        int[] z = Nat192.create();
+        Mod.invert(SecP192K1Field.P, ((SecP192K1FieldElement)b).x, z);
+        SecP192K1Field.multiply(z, x, z);
+        return new SecP192K1FieldElement(z);
+    }
+
+    public ECFieldElement negate()
+    {
+        int[] z = Nat192.create();
+        SecP192K1Field.negate(x, z);
+        return new SecP192K1FieldElement(z);
+    }
+
+    public ECFieldElement square()
+    {
+        int[] z = Nat192.create();
+        SecP192K1Field.square(x, z);
+        return new SecP192K1FieldElement(z);
+    }
+
+    public ECFieldElement invert()
+    {
+//        return new SecP192K1FieldElement(toBigInteger().modInverse(Q));
+        int[] z = Nat192.create();
+        Mod.invert(SecP192K1Field.P, x, z);
+        return new SecP192K1FieldElement(z);
+    }
+
+    /**
+     * return a sqrt root - the routine verifies that the calculation returns the right value - if
+     * none exists it returns null.
+     */
+    public ECFieldElement sqrt()
+    {
+        /*
+         * Raise this element to the exponent 2^190 - 2^30 - 2^10 - 2^6 - 2^5 - 2^4 - 2^1
+         *
+         * Breaking up the exponent's binary representation into "repunits", we get:
+         * { 159 1s } { 1 0s } { 19 1s } { 1 0s } { 3 1s } { 3 0s} { 3 1s } { 1 0s }
+         *
+         * Therefore we need an addition chain containing 3, 19, 159 (the lengths of the repunits)
+         * We use: 1, 2, [3], 6, 8, 16, [19], 35, 70, 140, [159]
+         */
+
+        int[] x1 = this.x;
+        if (Nat192.isZero(x1) || Nat192.isOne(x1))
+        {
+            return this;
+        }
+
+        int[] x2 = Nat192.create();
+        SecP192K1Field.square(x1, x2);
+        SecP192K1Field.multiply(x2, x1, x2);
+        int[] x3 = Nat192.create();
+        SecP192K1Field.square(x2, x3);
+        SecP192K1Field.multiply(x3, x1, x3);
+        int[] x6 = Nat192.create();
+        SecP192K1Field.squareN(x3, 3, x6);
+        SecP192K1Field.multiply(x6, x3, x6);
+        int[] x8 = x6;
+        SecP192K1Field.squareN(x6, 2, x8);
+        SecP192K1Field.multiply(x8, x2, x8);
+        int[] x16 = x2;
+        SecP192K1Field.squareN(x8, 8, x16);
+        SecP192K1Field.multiply(x16, x8, x16);
+        int[] x19 = x8;
+        SecP192K1Field.squareN(x16, 3, x19);
+        SecP192K1Field.multiply(x19, x3, x19);
+        int[] x35 = Nat192.create();
+        SecP192K1Field.squareN(x19, 16, x35);
+        SecP192K1Field.multiply(x35, x16, x35);
+        int[] x70 = x16;
+        SecP192K1Field.squareN(x35, 35, x70);
+        SecP192K1Field.multiply(x70, x35, x70);
+        int[] x140 = x35;
+        SecP192K1Field.squareN(x70, 70, x140);
+        SecP192K1Field.multiply(x140, x70, x140);
+        int[] x159 = x70;
+        SecP192K1Field.squareN(x140, 19, x159);
+        SecP192K1Field.multiply(x159, x19, x159);
+
+        int[] t1 = x159;
+        SecP192K1Field.squareN(t1, 20, t1);
+        SecP192K1Field.multiply(t1, x19, t1);
+        SecP192K1Field.squareN(t1, 4, t1);
+        SecP192K1Field.multiply(t1, x3, t1);
+        SecP192K1Field.squareN(t1, 6, t1);
+        SecP192K1Field.multiply(t1, x3, t1);
+        SecP192K1Field.square(t1, t1);
+
+        int[] t2 = x3;
+        SecP192K1Field.square(t1, t2);
+
+        return Nat192.eq(x1, t2) ? new SecP192K1FieldElement(t1) : null;
+    }
+
+    public boolean equals(Object other)
+    {
+        if (other == this)
+        {
+            return true;
+        }
+
+        if (!(other instanceof SecP192K1FieldElement))
+        {
+            return false;
+        }
+
+        SecP192K1FieldElement o = (SecP192K1FieldElement)other;
+        return Nat192.eq(x, o.x);
+    }
+
+    public int hashCode()
+    {
+        return Q.hashCode() ^ Arrays.hashCode(x, 0, 6);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java
new file mode 100644
index 0000000..f06458f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java
@@ -0,0 +1,302 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat192;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP192K1Point extends ECPoint.AbstractFp
+{
+    /**
+     * Create a point which encodes with point compression.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     *
+     * @deprecated Use ECCurve.createPoint to construct points
+     */
+    public SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+    {
+        this(curve, x, y, false);
+    }
+
+    /**
+     * Create a point that encodes with or without point compresion.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     * @param withCompression
+     *            if true encode with point compression
+     *
+     * @deprecated per-point compression property will be removed, refer
+     *             {@link #getEncoded(boolean)}
+     */
+    public SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        super(curve, x, y);
+
+        if ((x == null) != (y == null))
+        {
+            throw new IllegalArgumentException("Exactly one of the field elements is null");
+        }
+
+        this.withCompression = withCompression;
+    }
+
+    SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+        boolean withCompression)
+    {
+        super(curve, x, y, zs);
+
+        this.withCompression = withCompression;
+    }
+
+    protected ECPoint detach()
+    {
+        return new SecP192K1Point(null, getAffineXCoord(), getAffineYCoord());
+    }
+
+    // B.3 pg 62
+    public ECPoint add(ECPoint b)
+    {
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return this;
+        }
+        if (this == b)
+        {
+            return twice();
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP192K1FieldElement X1 = (SecP192K1FieldElement)this.x, Y1 = (SecP192K1FieldElement)this.y;
+        SecP192K1FieldElement X2 = (SecP192K1FieldElement)b.getXCoord(), Y2 = (SecP192K1FieldElement)b.getYCoord();
+
+        SecP192K1FieldElement Z1 = (SecP192K1FieldElement)this.zs[0];
+        SecP192K1FieldElement Z2 = (SecP192K1FieldElement)b.getZCoord(0);
+
+        int c;
+        int[] tt1 = Nat192.createExt();
+        int[] t2 = Nat192.create();
+        int[] t3 = Nat192.create();
+        int[] t4 = Nat192.create();
+
+        boolean Z1IsOne = Z1.isOne();
+        int[] U2, S2;
+        if (Z1IsOne)
+        {
+            U2 = X2.x;
+            S2 = Y2.x;
+        }
+        else
+        {
+            S2 = t3;
+            SecP192K1Field.square(Z1.x, S2);
+
+            U2 = t2;
+            SecP192K1Field.multiply(S2, X2.x, U2);
+
+            SecP192K1Field.multiply(S2, Z1.x, S2);
+            SecP192K1Field.multiply(S2, Y2.x, S2);
+        }
+
+        boolean Z2IsOne = Z2.isOne();
+        int[] U1, S1;
+        if (Z2IsOne)
+        {
+            U1 = X1.x;
+            S1 = Y1.x;
+        }
+        else
+        {
+            S1 = t4;
+            SecP192K1Field.square(Z2.x, S1);
+
+            U1 = tt1;
+            SecP192K1Field.multiply(S1, X1.x, U1);
+
+            SecP192K1Field.multiply(S1, Z2.x, S1);
+            SecP192K1Field.multiply(S1, Y1.x, S1);
+        }
+
+        int[] H = Nat192.create();
+        SecP192K1Field.subtract(U1, U2, H);
+
+        int[] R = t2;
+        SecP192K1Field.subtract(S1, S2, R);
+
+        // Check if b == this or b == -this
+        if (Nat192.isZero(H))
+        {
+            if (Nat192.isZero(R))
+            {
+                // this == b, i.e. this must be doubled
+                return this.twice();
+            }
+
+            // this == -b, i.e. the result is the point at infinity
+            return curve.getInfinity();
+        }
+
+        int[] HSquared = t3;
+        SecP192K1Field.square(H, HSquared);
+
+        int[] G = Nat192.create();
+        SecP192K1Field.multiply(HSquared, H, G);
+
+        int[] V = t3;
+        SecP192K1Field.multiply(HSquared, U1, V);
+
+        SecP192K1Field.negate(G, G);
+        Nat192.mul(S1, G, tt1);
+
+        c = Nat192.addBothTo(V, V, G);
+        SecP192K1Field.reduce32(c, G);
+
+        SecP192K1FieldElement X3 = new SecP192K1FieldElement(t4);
+        SecP192K1Field.square(R, X3.x);
+        SecP192K1Field.subtract(X3.x, G, X3.x);
+
+        SecP192K1FieldElement Y3 = new SecP192K1FieldElement(G);
+        SecP192K1Field.subtract(V, X3.x, Y3.x);
+        SecP192K1Field.multiplyAddToExt(Y3.x, R, tt1);
+        SecP192K1Field.reduce(tt1, Y3.x);
+
+        SecP192K1FieldElement Z3 = new SecP192K1FieldElement(H);
+        if (!Z1IsOne)
+        {
+            SecP192K1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+        if (!Z2IsOne)
+        {
+            SecP192K1Field.multiply(Z3.x, Z2.x, Z3.x);
+        }
+
+        ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+        return new SecP192K1Point(curve, X3, Y3, zs, this.withCompression);
+    }
+
+    // B.3 pg 62
+    public ECPoint twice()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP192K1FieldElement Y1 = (SecP192K1FieldElement)this.y;
+        if (Y1.isZero())
+        {
+            return curve.getInfinity();
+        }
+
+        SecP192K1FieldElement X1 = (SecP192K1FieldElement)this.x, Z1 = (SecP192K1FieldElement)this.zs[0];
+
+        int c;
+
+        int[] Y1Squared = Nat192.create();
+        SecP192K1Field.square(Y1.x, Y1Squared);
+
+        int[] T = Nat192.create();
+        SecP192K1Field.square(Y1Squared, T);
+
+        int[] M = Nat192.create();
+        SecP192K1Field.square(X1.x, M);
+        c = Nat192.addBothTo(M, M, M);
+        SecP192K1Field.reduce32(c, M);
+
+        int[] S = Y1Squared;
+        SecP192K1Field.multiply(Y1Squared, X1.x, S);
+        c = Nat.shiftUpBits(6, S, 2, 0);
+        SecP192K1Field.reduce32(c, S);
+
+        int[] t1 = Nat192.create();
+        c = Nat.shiftUpBits(6, T, 3, 0, t1);
+        SecP192K1Field.reduce32(c, t1);
+
+        SecP192K1FieldElement X3 = new SecP192K1FieldElement(T);
+        SecP192K1Field.square(M, X3.x);
+        SecP192K1Field.subtract(X3.x, S, X3.x);
+        SecP192K1Field.subtract(X3.x, S, X3.x);
+
+        SecP192K1FieldElement Y3 = new SecP192K1FieldElement(S);
+        SecP192K1Field.subtract(S, X3.x, Y3.x);
+        SecP192K1Field.multiply(Y3.x, M, Y3.x);
+        SecP192K1Field.subtract(Y3.x, t1, Y3.x);
+
+        SecP192K1FieldElement Z3 = new SecP192K1FieldElement(M);
+        SecP192K1Field.twice(Y1.x, Z3.x);
+        if (!Z1.isOne())
+        {
+            SecP192K1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+
+        return new SecP192K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression);
+    }
+
+    public ECPoint twicePlus(ECPoint b)
+    {
+        if (this == b)
+        {
+            return threeTimes();
+        }
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return twice();
+        }
+
+        ECFieldElement Y1 = this.y;
+        if (Y1.isZero())
+        {
+            return b;
+        }
+
+        return twice().add(b);
+    }
+
+    public ECPoint threeTimes()
+    {
+        if (this.isInfinity() || this.y.isZero())
+        {
+            return this;
+        }
+
+        // NOTE: Be careful about recursions between twicePlus and threeTimes
+        return twice().add(this);
+    }
+
+    public ECPoint negate()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        return new SecP192K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java
new file mode 100644
index 0000000..ec1c9cb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java
@@ -0,0 +1,131 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECLookupTable;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat192;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP192R1Curve extends ECCurve.AbstractFp
+{
+    public static final BigInteger q = new BigInteger(1,
+        Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"));
+
+    private static final int SecP192R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+    protected SecP192R1Point infinity;
+
+    public SecP192R1Curve()
+    {
+        super(q);
+
+        this.infinity = new SecP192R1Point(this, null, null);
+
+        this.a = fromBigInteger(new BigInteger(1,
+            Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC")));
+        this.b = fromBigInteger(new BigInteger(1,
+            Hex.decode("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1")));
+        this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"));
+        this.cofactor = BigInteger.valueOf(1);
+
+        this.coord = SecP192R1_DEFAULT_COORDS;
+    }
+
+    protected ECCurve cloneCurve()
+    {
+        return new SecP192R1Curve();
+    }
+
+    public boolean supportsCoordinateSystem(int coord)
+    {
+        switch (coord)
+        {
+        case COORD_JACOBIAN:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public int getFieldSize()
+    {
+        return q.bitLength();
+    }
+
+    public ECFieldElement fromBigInteger(BigInteger x)
+    {
+        return new SecP192R1FieldElement(x);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        return new SecP192R1Point(this, x, y, withCompression);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        return new SecP192R1Point(this, x, y, zs, withCompression);
+    }
+
+    public ECPoint getInfinity()
+    {
+        return infinity;
+    }
+
+    public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len)
+    {
+        final int FE_INTS = 6;
+
+        final int[] table = new int[len * FE_INTS * 2];
+        {
+            int pos = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                ECPoint p = points[off + i];
+                Nat192.copy(((SecP192R1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS;
+                Nat192.copy(((SecP192R1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS;
+            }
+        }
+
+        return new ECLookupTable()
+        {
+            public int getSize()
+            {
+                return len;
+            }
+
+            public ECPoint lookup(int index)
+            {
+                int[] x = Nat192.create(), y = Nat192.create();
+                int pos = 0;
+
+                for (int i = 0; i < len; ++i)
+                {
+                    int MASK = ((i ^ index) - 1) >> 31;
+
+                    for (int j = 0; j < FE_INTS; ++j)
+                    {
+                        x[j] ^= table[pos + j] & MASK;
+                        y[j] ^= table[pos + FE_INTS + j] & MASK;
+                    }
+
+                    pos += (FE_INTS * 2);
+                }
+
+                return createRawPoint(new SecP192R1FieldElement(x), new SecP192R1FieldElement(y), false);
+            }
+        };
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java
new file mode 100644
index 0000000..b63e68e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java
@@ -0,0 +1,290 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat192;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP192R1Field
+{
+    private static final long M = 0xFFFFFFFFL;
+
+    // 2^192 - 2^64 - 1
+    static final int[] P = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+    static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000001,
+        0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+    private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFE,
+        0xFFFFFFFF, 0x00000001, 0x00000000, 0x00000002 };
+    private static final int P5 = 0xFFFFFFFF;
+    private static final int PExt11 = 0xFFFFFFFF;
+
+    public static void add(int[] x, int[] y, int[] z)
+    {
+        int c = Nat192.add(x, y, z);
+        if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static void addExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.add(12, xx, yy, zz);
+        if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt)))
+        {
+            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.incAt(12, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void addOne(int[] x, int[] z)
+    {
+        int c = Nat.inc(6, x, z);
+        if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static int[] fromBigInteger(BigInteger x)
+    {
+        int[] z = Nat192.fromBigInteger(x);
+        if (z[5] == P5 && Nat192.gte(z, P))
+        {
+            Nat192.subFrom(P, z);
+        }
+        return z;
+    }
+
+    public static void half(int[] x, int[] z)
+    {
+        if ((x[0] & 1) == 0)
+        {
+            Nat.shiftDownBit(6, x, 0, z);
+        }
+        else
+        {
+            int c = Nat192.add(x, P, z);
+            Nat.shiftDownBit(6, z, c);
+        }
+    }
+
+    public static void multiply(int[] x, int[] y, int[] z)
+    {
+        int[] tt = Nat192.createExt();
+        Nat192.mul(x, y, tt);
+        reduce(tt, z);
+    }
+
+    public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+    {
+        int c = Nat192.mulAddTo(x, y, zz);
+        if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt)))
+        {
+            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.incAt(12, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void negate(int[] x, int[] z)
+    {
+        if (Nat192.isZero(x))
+        {
+            Nat192.zero(z);
+        }
+        else
+        {
+            Nat192.sub(P, x, z);
+        }
+    }
+
+    public static void reduce(int[] xx, int[] z)
+    {
+        long xx06 = xx[6] & M, xx07 = xx[7] & M, xx08 = xx[8] & M;
+        long xx09 = xx[9] & M, xx10 = xx[10] & M, xx11 = xx[11] & M;
+
+        long t0 = xx06 + xx10;
+        long t1 = xx07 + xx11;
+
+        long cc = 0;
+        cc += (xx[0] & M) + t0;
+        int z0 = (int)cc;
+        cc >>= 32;
+        cc += (xx[1] & M) + t1;
+        z[1] = (int)cc;
+        cc >>= 32;
+
+        t0 += xx08;
+        t1 += xx09;
+
+        cc += (xx[2] & M) + t0;
+        long z2 = cc & M;
+        cc >>= 32;
+        cc += (xx[3] & M) + t1;
+        z[3] = (int)cc;
+        cc >>= 32;
+
+        t0 -= xx06;
+        t1 -= xx07;
+
+        cc += (xx[4] & M) + t0;
+        z[4] = (int)cc;
+        cc >>= 32;
+        cc += (xx[5] & M) + t1;
+        z[5] = (int)cc;
+        cc >>= 32;
+
+        z2 += cc;
+
+        cc += (z0 & M);
+        z[0] = (int)cc;
+        cc >>= 32;
+        if (cc != 0)
+        {
+            cc += (z[1] & M);
+            z[1] = (int)cc;
+            z2 += cc >> 32;
+        }
+        z[2] = (int)z2;
+        cc = z2 >> 32;
+
+//      assert cc == 0 || cc == 1;
+
+        if ((cc != 0 && Nat.incAt(6, z, 3) != 0)
+            || (z[5] == P5 && Nat192.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static void reduce32(int x, int[] z)
+    {
+        long cc = 0;
+
+        if (x != 0)
+        {
+            long xx06 = x & M;
+
+            cc += (z[0] & M) + xx06;
+            z[0] = (int)cc;
+            cc >>= 32;
+            if (cc != 0)
+            {
+                cc += (z[1] & M);
+                z[1] = (int)cc;
+                cc >>= 32;
+            }
+            cc += (z[2] & M) + xx06;
+            z[2] = (int)cc;
+            cc >>= 32;
+
+//            assert cc == 0 || cc == 1;
+        }
+
+        if ((cc != 0 && Nat.incAt(6, z, 3) != 0)
+            || (z[5] == P5 && Nat192.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static void square(int[] x, int[] z)
+    {
+        int[] tt = Nat192.createExt();
+        Nat192.square(x, tt);
+        reduce(tt, z);
+    }
+
+    public static void squareN(int[] x, int n, int[] z)
+    {
+//        assert n > 0;
+
+        int[] tt = Nat192.createExt();
+        Nat192.square(x, tt);
+        reduce(tt, z);
+
+        while (--n > 0)
+        {
+            Nat192.square(z, tt);
+            reduce(tt, z);
+        }
+    }
+
+    public static void subtract(int[] x, int[] y, int[] z)
+    {
+        int c = Nat192.sub(x, y, z);
+        if (c != 0)
+        {
+            subPInvFrom(z);
+        }
+    }
+
+    public static void subtractExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.sub(12, xx, yy, zz);
+        if (c != 0)
+        {
+            if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.decAt(12, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void twice(int[] x, int[] z)
+    {
+        int c = Nat.shiftUpBit(6, x, 0, z);
+        if (c != 0 || (z[5] == P5 && Nat192.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    private static void addPInvTo(int[] z)
+    {
+        long c = (z[0] & M) + 1;
+        z[0] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            c += (z[1] & M);
+            z[1] = (int)c;
+            c >>= 32;
+        }
+        c += (z[2] & M) + 1;
+        z[2] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            Nat.incAt(6, z, 3);
+        }
+    }
+
+    private static void subPInvFrom(int[] z)
+    {
+        long c = (z[0] & M) - 1;
+        z[0] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            c += (z[1] & M);
+            z[1] = (int)c;
+            c >>= 32;
+        }
+        c += (z[2] & M) - 1;
+        z[2] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            Nat.decAt(6, z, 3);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java
new file mode 100644
index 0000000..de86f91
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java
@@ -0,0 +1,194 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.raw.Mod;
+import com.android.internal.org.bouncycastle.math.raw.Nat192;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP192R1FieldElement extends ECFieldElement.AbstractFp
+{
+    public static final BigInteger Q = SecP192R1Curve.q;
+
+    protected int[] x;
+
+    public SecP192R1FieldElement(BigInteger x)
+    {
+        if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+        {
+            throw new IllegalArgumentException("x value invalid for SecP192R1FieldElement");
+        }
+
+        this.x = SecP192R1Field.fromBigInteger(x);
+    }
+
+    public SecP192R1FieldElement()
+    {
+        this.x = Nat192.create();
+    }
+
+    protected SecP192R1FieldElement(int[] x)
+    {
+        this.x = x;
+    }
+
+    public boolean isZero()
+    {
+        return Nat192.isZero(x);
+    }
+
+    public boolean isOne()
+    {
+        return Nat192.isOne(x);
+    }
+
+    public boolean testBitZero()
+    {
+        return Nat192.getBit(x, 0) == 1;
+    }
+
+    public BigInteger toBigInteger()
+    {
+        return Nat192.toBigInteger(x);
+    }
+
+    public String getFieldName()
+    {
+        return "SecP192R1Field";
+    }
+
+    public int getFieldSize()
+    {
+        return Q.bitLength();
+    }
+
+    public ECFieldElement add(ECFieldElement b)
+    {
+        int[] z = Nat192.create();
+        SecP192R1Field.add(x, ((SecP192R1FieldElement)b).x, z);
+        return new SecP192R1FieldElement(z);
+    }
+
+    public ECFieldElement addOne()
+    {
+        int[] z = Nat192.create();
+        SecP192R1Field.addOne(x, z);
+        return new SecP192R1FieldElement(z);
+    }
+
+    public ECFieldElement subtract(ECFieldElement b)
+    {
+        int[] z = Nat192.create();
+        SecP192R1Field.subtract(x, ((SecP192R1FieldElement)b).x, z);
+        return new SecP192R1FieldElement(z);
+    }
+
+    public ECFieldElement multiply(ECFieldElement b)
+    {
+        int[] z = Nat192.create();
+        SecP192R1Field.multiply(x, ((SecP192R1FieldElement)b).x, z);
+        return new SecP192R1FieldElement(z);
+    }
+
+    public ECFieldElement divide(ECFieldElement b)
+    {
+//        return multiply(b.invert());
+        int[] z = Nat192.create();
+        Mod.invert(SecP192R1Field.P, ((SecP192R1FieldElement)b).x, z);
+        SecP192R1Field.multiply(z, x, z);
+        return new SecP192R1FieldElement(z);
+    }
+
+    public ECFieldElement negate()
+    {
+        int[] z = Nat192.create();
+        SecP192R1Field.negate(x, z);
+        return new SecP192R1FieldElement(z);
+    }
+
+    public ECFieldElement square()
+    {
+        int[] z = Nat192.create();
+        SecP192R1Field.square(x, z);
+        return new SecP192R1FieldElement(z);
+    }
+
+    public ECFieldElement invert()
+    {
+//        return new SecP192R1FieldElement(toBigInteger().modInverse(Q));
+        int[] z = Nat192.create();
+        Mod.invert(SecP192R1Field.P, x, z);
+        return new SecP192R1FieldElement(z);
+    }
+
+    // D.1.4 91
+    /**
+     * return a sqrt root - the routine verifies that the calculation returns the right value - if
+     * none exists it returns null.
+     */
+    public ECFieldElement sqrt()
+    {
+        // Raise this element to the exponent 2^190 - 2^62
+
+        int[] x1 = this.x;
+        if (Nat192.isZero(x1) || Nat192.isOne(x1))
+        {
+            return this;
+        }
+
+        int[] t1 = Nat192.create();
+        int[] t2 = Nat192.create();
+
+        SecP192R1Field.square(x1, t1);
+        SecP192R1Field.multiply(t1, x1, t1);
+
+        SecP192R1Field.squareN(t1, 2, t2);
+        SecP192R1Field.multiply(t2, t1, t2);
+
+        SecP192R1Field.squareN(t2, 4, t1);
+        SecP192R1Field.multiply(t1, t2, t1);
+
+        SecP192R1Field.squareN(t1, 8, t2);
+        SecP192R1Field.multiply(t2, t1, t2);
+
+        SecP192R1Field.squareN(t2, 16, t1);
+        SecP192R1Field.multiply(t1, t2, t1);
+
+        SecP192R1Field.squareN(t1, 32, t2);
+        SecP192R1Field.multiply(t2, t1, t2);
+
+        SecP192R1Field.squareN(t2, 64, t1);
+        SecP192R1Field.multiply(t1, t2, t1);
+
+        SecP192R1Field.squareN(t1, 62, t1);
+        SecP192R1Field.square(t1, t2);
+
+        return Nat192.eq(x1, t2) ? new SecP192R1FieldElement(t1) : null;
+    }
+
+    public boolean equals(Object other)
+    {
+        if (other == this)
+        {
+            return true;
+        }
+
+        if (!(other instanceof SecP192R1FieldElement))
+        {
+            return false;
+        }
+
+        SecP192R1FieldElement o = (SecP192R1FieldElement)other;
+        return Nat192.eq(x, o.x);
+    }
+
+    public int hashCode()
+    {
+        return Q.hashCode() ^ Arrays.hashCode(x, 0, 6);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java
new file mode 100644
index 0000000..915b3b4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java
@@ -0,0 +1,314 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat192;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP192R1Point extends ECPoint.AbstractFp
+{
+    /**
+     * Create a point which encodes with point compression.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     *
+     * @deprecated Use ECCurve.createPoint to construct points
+     */
+    public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+    {
+        this(curve, x, y, false);
+    }
+
+    /**
+     * Create a point that encodes with or without point compresion.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     * @param withCompression
+     *            if true encode with point compression
+     *
+     * @deprecated per-point compression property will be removed, refer
+     *             {@link #getEncoded(boolean)}
+     */
+    public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        super(curve, x, y);
+
+        if ((x == null) != (y == null))
+        {
+            throw new IllegalArgumentException("Exactly one of the field elements is null");
+        }
+
+        this.withCompression = withCompression;
+    }
+
+    SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        super(curve, x, y, zs);
+
+        this.withCompression = withCompression;
+    }
+
+    protected ECPoint detach()
+    {
+        return new SecP192R1Point(null, getAffineXCoord(), getAffineYCoord());
+    }
+
+    // B.3 pg 62
+    public ECPoint add(ECPoint b)
+    {
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return this;
+        }
+        if (this == b)
+        {
+            return twice();
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.x, Y1 = (SecP192R1FieldElement)this.y;
+        SecP192R1FieldElement X2 = (SecP192R1FieldElement)b.getXCoord(), Y2 = (SecP192R1FieldElement)b.getYCoord();
+
+        SecP192R1FieldElement Z1 = (SecP192R1FieldElement)this.zs[0];
+        SecP192R1FieldElement Z2 = (SecP192R1FieldElement)b.getZCoord(0);
+
+        int c;
+        int[] tt1 = Nat192.createExt();
+        int[] t2 = Nat192.create();
+        int[] t3 = Nat192.create();
+        int[] t4 = Nat192.create();
+
+        boolean Z1IsOne = Z1.isOne();
+        int[] U2, S2;
+        if (Z1IsOne)
+        {
+            U2 = X2.x;
+            S2 = Y2.x;
+        }
+        else
+        {
+            S2 = t3;
+            SecP192R1Field.square(Z1.x, S2);
+
+            U2 = t2;
+            SecP192R1Field.multiply(S2, X2.x, U2);
+
+            SecP192R1Field.multiply(S2, Z1.x, S2);
+            SecP192R1Field.multiply(S2, Y2.x, S2);
+        }
+
+        boolean Z2IsOne = Z2.isOne();
+        int[] U1, S1;
+        if (Z2IsOne)
+        {
+            U1 = X1.x;
+            S1 = Y1.x;
+        }
+        else
+        {
+            S1 = t4;
+            SecP192R1Field.square(Z2.x, S1);
+
+            U1 = tt1;
+            SecP192R1Field.multiply(S1, X1.x, U1);
+
+            SecP192R1Field.multiply(S1, Z2.x, S1);
+            SecP192R1Field.multiply(S1, Y1.x, S1);
+        }
+
+        int[] H = Nat192.create();
+        SecP192R1Field.subtract(U1, U2, H);
+
+        int[] R = t2;
+        SecP192R1Field.subtract(S1, S2, R);
+
+        // Check if b == this or b == -this
+        if (Nat192.isZero(H))
+        {
+            if (Nat192.isZero(R))
+            {
+                // this == b, i.e. this must be doubled
+                return this.twice();
+            }
+
+            // this == -b, i.e. the result is the point at infinity
+            return curve.getInfinity();
+        }
+
+        int[] HSquared = t3;
+        SecP192R1Field.square(H, HSquared);
+
+        int[] G = Nat192.create();
+        SecP192R1Field.multiply(HSquared, H, G);
+
+        int[] V = t3;
+        SecP192R1Field.multiply(HSquared, U1, V);
+
+        SecP192R1Field.negate(G, G);
+        Nat192.mul(S1, G, tt1);
+
+        c = Nat192.addBothTo(V, V, G);
+        SecP192R1Field.reduce32(c, G);
+
+        SecP192R1FieldElement X3 = new SecP192R1FieldElement(t4);
+        SecP192R1Field.square(R, X3.x);
+        SecP192R1Field.subtract(X3.x, G, X3.x);
+
+        SecP192R1FieldElement Y3 = new SecP192R1FieldElement(G);
+        SecP192R1Field.subtract(V, X3.x, Y3.x);
+        SecP192R1Field.multiplyAddToExt(Y3.x, R, tt1);
+        SecP192R1Field.reduce(tt1, Y3.x);
+
+        SecP192R1FieldElement Z3 = new SecP192R1FieldElement(H);
+        if (!Z1IsOne)
+        {
+            SecP192R1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+        if (!Z2IsOne)
+        {
+            SecP192R1Field.multiply(Z3.x, Z2.x, Z3.x);
+        }
+
+        ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+        return new SecP192R1Point(curve, X3, Y3, zs, this.withCompression);
+    }
+
+    // B.3 pg 62
+    public ECPoint twice()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP192R1FieldElement Y1 = (SecP192R1FieldElement)this.y;
+        if (Y1.isZero())
+        {
+            return curve.getInfinity();
+        }
+
+        SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.x, Z1 = (SecP192R1FieldElement)this.zs[0];
+
+        int c;
+        int[] t1 = Nat192.create();
+        int[] t2 = Nat192.create();
+
+        int[] Y1Squared = Nat192.create();
+        SecP192R1Field.square(Y1.x, Y1Squared);
+
+        int[] T = Nat192.create();
+        SecP192R1Field.square(Y1Squared, T);
+
+        boolean Z1IsOne = Z1.isOne();
+
+        int[] Z1Squared = Z1.x;
+        if (!Z1IsOne)
+        {
+            Z1Squared = t2;
+            SecP192R1Field.square(Z1.x, Z1Squared);
+        }
+
+        SecP192R1Field.subtract(X1.x, Z1Squared, t1);
+
+        int[] M = t2;
+        SecP192R1Field.add(X1.x, Z1Squared, M);
+        SecP192R1Field.multiply(M, t1, M);
+        c = Nat192.addBothTo(M, M, M);
+        SecP192R1Field.reduce32(c, M);
+
+        int[] S = Y1Squared;
+        SecP192R1Field.multiply(Y1Squared, X1.x, S);
+        c = Nat.shiftUpBits(6, S, 2, 0);
+        SecP192R1Field.reduce32(c, S);
+
+        c = Nat.shiftUpBits(6, T, 3, 0, t1);
+        SecP192R1Field.reduce32(c, t1);
+
+        SecP192R1FieldElement X3 = new SecP192R1FieldElement(T);
+        SecP192R1Field.square(M, X3.x);
+        SecP192R1Field.subtract(X3.x, S, X3.x);
+        SecP192R1Field.subtract(X3.x, S, X3.x);
+
+        SecP192R1FieldElement Y3 = new SecP192R1FieldElement(S);
+        SecP192R1Field.subtract(S, X3.x, Y3.x);
+        SecP192R1Field.multiply(Y3.x, M, Y3.x);
+        SecP192R1Field.subtract(Y3.x, t1, Y3.x);
+
+        SecP192R1FieldElement Z3 = new SecP192R1FieldElement(M);
+        SecP192R1Field.twice(Y1.x, Z3.x);
+        if (!Z1IsOne)
+        {
+            SecP192R1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+
+        return new SecP192R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+    }
+
+    public ECPoint twicePlus(ECPoint b)
+    {
+        if (this == b)
+        {
+            return threeTimes();
+        }
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return twice();
+        }
+
+        ECFieldElement Y1 = this.y;
+        if (Y1.isZero())
+        {
+            return b;
+        }
+
+        return twice().add(b);
+    }
+
+    public ECPoint threeTimes()
+    {
+        if (this.isInfinity() || this.y.isZero())
+        {
+            return this;
+        }
+
+        // NOTE: Be careful about recursions between twicePlus and threeTimes
+        return twice().add(this);
+    }
+
+    public ECPoint negate()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        return new SecP192R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java
new file mode 100644
index 0000000..6347218
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java
@@ -0,0 +1,129 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECConstants;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECLookupTable;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat224;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP224K1Curve extends ECCurve.AbstractFp
+{
+    public static final BigInteger q = new BigInteger(1,
+        Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D"));
+
+    private static final int SECP224K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+    protected SecP224K1Point infinity;
+
+    public SecP224K1Curve()
+    {
+        super(q);
+
+        this.infinity = new SecP224K1Point(this, null, null);
+
+        this.a = fromBigInteger(ECConstants.ZERO);
+        this.b = fromBigInteger(BigInteger.valueOf(5));
+        this.order = new BigInteger(1, Hex.decode("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"));
+        this.cofactor = BigInteger.valueOf(1);
+        this.coord = SECP224K1_DEFAULT_COORDS;
+    }
+
+    protected ECCurve cloneCurve()
+    {
+        return new SecP224K1Curve();
+    }
+
+    public boolean supportsCoordinateSystem(int coord)
+    {
+        switch (coord)
+        {
+        case COORD_JACOBIAN:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public int getFieldSize()
+    {
+        return q.bitLength();
+    }
+
+    public ECFieldElement fromBigInteger(BigInteger x)
+    {
+        return new SecP224K1FieldElement(x);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        return new SecP224K1Point(this, x, y, withCompression);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        return new SecP224K1Point(this, x, y, zs, withCompression);
+    }
+
+    public ECPoint getInfinity()
+    {
+        return infinity;
+    }
+
+    public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len)
+    {
+        final int FE_INTS = 7;
+
+        final int[] table = new int[len * FE_INTS * 2];
+        {
+            int pos = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                ECPoint p = points[off + i];
+                Nat224.copy(((SecP224K1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS;
+                Nat224.copy(((SecP224K1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS;
+            }
+        }
+
+        return new ECLookupTable()
+        {
+            public int getSize()
+            {
+                return len;
+            }
+
+            public ECPoint lookup(int index)
+            {
+                int[] x = Nat224.create(), y = Nat224.create();
+                int pos = 0;
+
+                for (int i = 0; i < len; ++i)
+                {
+                    int MASK = ((i ^ index) - 1) >> 31;
+
+                    for (int j = 0; j < FE_INTS; ++j)
+                    {
+                        x[j] ^= table[pos + j] & MASK;
+                        y[j] ^= table[pos + FE_INTS + j] & MASK;
+                    }
+
+                    pos += (FE_INTS * 2);
+                }
+
+                return createRawPoint(new SecP224K1FieldElement(x), new SecP224K1FieldElement(y), false);
+            }
+        };
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java
new file mode 100644
index 0000000..b013511
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java
@@ -0,0 +1,182 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat224;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP224K1Field
+{
+    // 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1
+    static final int[] P = new int[]{ 0xFFFFE56D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+        0xFFFFFFFF };
+    static final int[] PExt = new int[]{ 0x02C23069, 0x00003526, 0x00000001, 0x00000000, 0x00000000,
+        0x00000000, 0x00000000, 0xFFFFCADA, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+    private static final int[] PExtInv = new int[]{ 0xFD3DCF97, 0xFFFFCAD9, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+        0xFFFFFFFF, 0xFFFFFFFF, 0x00003525, 0x00000002 };
+    private static final int P6 = 0xFFFFFFFF;
+    private static final int PExt13 = 0xFFFFFFFF;
+    private static final int PInv33 = 0x1A93;
+
+    public static void add(int[] x, int[] y, int[] z)
+    {
+        int c = Nat224.add(x, y, z);
+        if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+        {
+            Nat.add33To(7, PInv33, z);
+        }
+    }
+
+    public static void addExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.add(14, xx, yy, zz);
+        if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt)))
+        {
+            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.incAt(14, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void addOne(int[] x, int[] z)
+    {
+        int c = Nat.inc(7, x, z);
+        if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+        {
+            Nat.add33To(7, PInv33, z);
+        }
+    }
+
+    public static int[] fromBigInteger(BigInteger x)
+    {
+        int[] z = Nat224.fromBigInteger(x);
+        if (z[6] == P6 && Nat224.gte(z, P))
+        {
+            Nat.add33To(7, PInv33, z);
+        }
+        return z;
+    }
+
+    public static void half(int[] x, int[] z)
+    {
+        if ((x[0] & 1) == 0)
+        {
+            Nat.shiftDownBit(7, x, 0, z);
+        }
+        else
+        {
+            int c = Nat224.add(x, P, z);
+            Nat.shiftDownBit(7, z, c);
+        }
+    }
+
+    public static void multiply(int[] x, int[] y, int[] z)
+    {
+        int[] tt = Nat224.createExt();
+        Nat224.mul(x, y, tt);
+        reduce(tt, z);
+    }
+
+    public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+    {
+        int c = Nat224.mulAddTo(x, y, zz);
+        if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt)))
+        {
+            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.incAt(14, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void negate(int[] x, int[] z)
+    {
+        if (Nat224.isZero(x))
+        {
+            Nat224.zero(z);
+        }
+        else
+        {
+            Nat224.sub(P, x, z);
+        }
+    }
+
+    public static void reduce(int[] xx, int[] z)
+    {
+        long cc = Nat224.mul33Add(PInv33, xx, 7, xx, 0, z, 0);
+        int c = Nat224.mul33DWordAdd(PInv33, cc, z, 0);
+
+        // assert c == 0L || c == 1L;
+
+        if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+        {
+            Nat.add33To(7, PInv33, z);
+        }
+    }
+
+    public static void reduce32(int x, int[] z)
+    {
+        if ((x != 0 && Nat224.mul33WordAdd(PInv33, x, z, 0) != 0)
+            || (z[6] == P6 && Nat224.gte(z, P)))
+        {
+            Nat.add33To(7, PInv33, z);
+        }
+    }
+
+    public static void square(int[] x, int[] z)
+    {
+        int[] tt = Nat224.createExt();
+        Nat224.square(x, tt);
+        reduce(tt, z);
+    }
+
+    public static void squareN(int[] x, int n, int[] z)
+    {
+//        assert n > 0;
+
+        int[] tt = Nat224.createExt();
+        Nat224.square(x, tt);
+        reduce(tt, z);
+
+        while (--n > 0)
+        {
+            Nat224.square(z, tt);
+            reduce(tt, z);
+        }
+    }
+
+    public static void subtract(int[] x, int[] y, int[] z)
+    {
+        int c = Nat224.sub(x, y, z);
+        if (c != 0)
+        {
+            Nat.sub33From(7, PInv33, z);
+        }
+    }
+
+    public static void subtractExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.sub(14, xx, yy, zz);
+        if (c != 0)
+        {
+            if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.decAt(14, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void twice(int[] x, int[] z)
+    {
+        int c = Nat.shiftUpBit(7, x, 0, z);
+        if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+        {
+            Nat.add33To(7, PInv33, z);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java
new file mode 100644
index 0000000..4dad039
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java
@@ -0,0 +1,247 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.raw.Mod;
+import com.android.internal.org.bouncycastle.math.raw.Nat224;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP224K1FieldElement extends ECFieldElement.AbstractFp
+{
+    public static final BigInteger Q = SecP224K1Curve.q;
+
+    // Calculated as ECConstants.TWO.modPow(Q.shiftRight(2), Q)
+    private static final int[] PRECOMP_POW2 = new int[]{ 0x33bfd202, 0xdcfad133, 0x2287624a, 0xc3811ba8,
+        0xa85558fc, 0x1eaef5d7, 0x8edf154c };
+
+    protected int[] x;
+
+    public SecP224K1FieldElement(BigInteger x)
+    {
+        if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+        {
+            throw new IllegalArgumentException("x value invalid for SecP224K1FieldElement");
+        }
+
+        this.x = SecP224K1Field.fromBigInteger(x);
+    }
+
+    public SecP224K1FieldElement()
+    {
+        this.x = Nat224.create();
+    }
+
+    protected SecP224K1FieldElement(int[] x)
+    {
+        this.x = x;
+    }
+
+    public boolean isZero()
+    {
+        return Nat224.isZero(x);
+    }
+
+    public boolean isOne()
+    {
+        return Nat224.isOne(x);
+    }
+
+    public boolean testBitZero()
+    {
+        return Nat224.getBit(x, 0) == 1;
+    }
+
+    public BigInteger toBigInteger()
+    {
+        return Nat224.toBigInteger(x);
+    }
+
+    public String getFieldName()
+    {
+        return "SecP224K1Field";
+    }
+
+    public int getFieldSize()
+    {
+        return Q.bitLength();
+    }
+
+    public ECFieldElement add(ECFieldElement b)
+    {
+        int[] z = Nat224.create();
+        SecP224K1Field.add(x, ((SecP224K1FieldElement)b).x, z);
+        return new SecP224K1FieldElement(z);
+    }
+
+    public ECFieldElement addOne()
+    {
+        int[] z = Nat224.create();
+        SecP224K1Field.addOne(x, z);
+        return new SecP224K1FieldElement(z);
+    }
+
+    public ECFieldElement subtract(ECFieldElement b)
+    {
+        int[] z = Nat224.create();
+        SecP224K1Field.subtract(x, ((SecP224K1FieldElement)b).x, z);
+        return new SecP224K1FieldElement(z);
+    }
+
+    public ECFieldElement multiply(ECFieldElement b)
+    {
+        int[] z = Nat224.create();
+        SecP224K1Field.multiply(x, ((SecP224K1FieldElement)b).x, z);
+        return new SecP224K1FieldElement(z);
+    }
+
+    public ECFieldElement divide(ECFieldElement b)
+    {
+//        return multiply(b.invert());
+        int[] z = Nat224.create();
+        Mod.invert(SecP224K1Field.P, ((SecP224K1FieldElement)b).x, z);
+        SecP224K1Field.multiply(z, x, z);
+        return new SecP224K1FieldElement(z);
+    }
+
+    public ECFieldElement negate()
+    {
+        int[] z = Nat224.create();
+        SecP224K1Field.negate(x, z);
+        return new SecP224K1FieldElement(z);
+    }
+
+    public ECFieldElement square()
+    {
+        int[] z = Nat224.create();
+        SecP224K1Field.square(x, z);
+        return new SecP224K1FieldElement(z);
+    }
+
+    public ECFieldElement invert()
+    {
+//        return new SecP224K1FieldElement(toBigInteger().modInverse(Q));
+        int[] z = Nat224.create();
+        Mod.invert(SecP224K1Field.P, x, z);
+        return new SecP224K1FieldElement(z);
+    }
+
+    // D.1.4 91
+    /**
+     * return a sqrt root - the routine verifies that the calculation returns the right value - if
+     * none exists it returns null.
+     */
+    public ECFieldElement sqrt()
+    {
+        /*
+         * Q == 8m + 5, so we use Pocklington's method for this case.
+         *
+         * First, raise this element to the exponent 2^221 - 2^29 - 2^9 - 2^8 - 2^6 - 2^4 - 2^1 (i.e. m + 1)
+         *
+         * Breaking up the exponent's binary representation into "repunits", we get:
+         * { 191 1s } { 1 0s } { 19 1s } { 2 0s } { 1 1s } { 1 0s} { 1 1s } { 1 0s} { 3 1s } { 1 0s}
+         *
+         * Therefore we need an addition chain containing 1, 3, 19, 191 (the lengths of the repunits)
+         * We use: [1], 2, [3], 4, 8, 11, [19], 23, 42, 84, 107, [191]
+         */
+
+        int[] x1 = this.x;
+        if (Nat224.isZero(x1) || Nat224.isOne(x1))
+        {
+            return this;
+        }
+
+        int[] x2 = Nat224.create();
+        SecP224K1Field.square(x1, x2);
+        SecP224K1Field.multiply(x2, x1, x2);
+        int[] x3 = x2;
+        SecP224K1Field.square(x2, x3);
+        SecP224K1Field.multiply(x3, x1, x3);
+        int[] x4 = Nat224.create();
+        SecP224K1Field.square(x3, x4);
+        SecP224K1Field.multiply(x4, x1, x4);
+        int[] x8 = Nat224.create();
+        SecP224K1Field.squareN(x4, 4, x8);
+        SecP224K1Field.multiply(x8, x4, x8);
+        int[] x11 = Nat224.create();
+        SecP224K1Field.squareN(x8, 3, x11);
+        SecP224K1Field.multiply(x11, x3, x11);
+        int[] x19 = x11;
+        SecP224K1Field.squareN(x11, 8, x19);
+        SecP224K1Field.multiply(x19, x8, x19);
+        int[] x23 = x8;
+        SecP224K1Field.squareN(x19, 4, x23);
+        SecP224K1Field.multiply(x23, x4, x23);
+        int[] x42 = x4;
+        SecP224K1Field.squareN(x23, 19, x42);
+        SecP224K1Field.multiply(x42, x19, x42);
+        int[] x84 = Nat224.create();
+        SecP224K1Field.squareN(x42, 42, x84);
+        SecP224K1Field.multiply(x84, x42, x84);
+        int[] x107 = x42;
+        SecP224K1Field.squareN(x84, 23, x107);
+        SecP224K1Field.multiply(x107, x23, x107);
+        int[] x191 = x23;
+        SecP224K1Field.squareN(x107, 84, x191);
+        SecP224K1Field.multiply(x191, x84, x191);
+
+        int[] t1 = x191;
+        SecP224K1Field.squareN(t1, 20, t1);
+        SecP224K1Field.multiply(t1, x19, t1);
+        SecP224K1Field.squareN(t1, 3, t1);
+        SecP224K1Field.multiply(t1, x1, t1);
+        SecP224K1Field.squareN(t1, 2, t1);
+        SecP224K1Field.multiply(t1, x1, t1);
+        SecP224K1Field.squareN(t1, 4, t1);
+        SecP224K1Field.multiply(t1, x3, t1);
+        SecP224K1Field.square(t1, t1);
+
+        int[] t2 = x84;
+        SecP224K1Field.square(t1, t2);
+
+        if (Nat224.eq(x1, t2))
+        {
+            return new SecP224K1FieldElement(t1);
+        }
+
+        /*
+         * If the first guess is incorrect, we multiply by a precomputed power of 2 to get the second guess,
+         * which is ((4x)^(m + 1))/2 mod Q
+         */
+        SecP224K1Field.multiply(t1, PRECOMP_POW2, t1);
+
+        SecP224K1Field.square(t1, t2);
+
+        if (Nat224.eq(x1, t2))
+        {
+            return new SecP224K1FieldElement(t1);
+        }
+
+        return null;
+    }
+
+    public boolean equals(Object other)
+    {
+        if (other == this)
+        {
+            return true;
+        }
+
+        if (!(other instanceof SecP224K1FieldElement))
+        {
+            return false;
+        }
+
+        SecP224K1FieldElement o = (SecP224K1FieldElement)other;
+        return Nat224.eq(x, o.x);
+    }
+
+    public int hashCode()
+    {
+        return Q.hashCode() ^ Arrays.hashCode(x, 0, 7);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java
new file mode 100644
index 0000000..a8ef860
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java
@@ -0,0 +1,302 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat224;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP224K1Point extends ECPoint.AbstractFp
+{
+    /**
+     * Create a point which encodes with point compression.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     *
+     * @deprecated Use ECCurve.createPoint to construct points
+     */
+    public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+    {
+        this(curve, x, y, false);
+    }
+
+    /**
+     * Create a point that encodes with or without point compresion.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     * @param withCompression
+     *            if true encode with point compression
+     *
+     * @deprecated per-point compression property will be removed, refer
+     *             {@link #getEncoded(boolean)}
+     */
+    public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        super(curve, x, y);
+
+        if ((x == null) != (y == null))
+        {
+            throw new IllegalArgumentException("Exactly one of the field elements is null");
+        }
+
+        this.withCompression = withCompression;
+    }
+
+    SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+        boolean withCompression)
+    {
+        super(curve, x, y, zs);
+
+        this.withCompression = withCompression;
+    }
+
+    protected ECPoint detach()
+    {
+        return new SecP224K1Point(null, getAffineXCoord(), getAffineYCoord());
+    }
+
+    // B.3 pg 62
+    public ECPoint add(ECPoint b)
+    {
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return this;
+        }
+        if (this == b)
+        {
+            return twice();
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.x, Y1 = (SecP224K1FieldElement)this.y;
+        SecP224K1FieldElement X2 = (SecP224K1FieldElement)b.getXCoord(), Y2 = (SecP224K1FieldElement)b.getYCoord();
+
+        SecP224K1FieldElement Z1 = (SecP224K1FieldElement)this.zs[0];
+        SecP224K1FieldElement Z2 = (SecP224K1FieldElement)b.getZCoord(0);
+
+        int c;
+        int[] tt1 = Nat224.createExt();
+        int[] t2 = Nat224.create();
+        int[] t3 = Nat224.create();
+        int[] t4 = Nat224.create();
+
+        boolean Z1IsOne = Z1.isOne();
+        int[] U2, S2;
+        if (Z1IsOne)
+        {
+            U2 = X2.x;
+            S2 = Y2.x;
+        }
+        else
+        {
+            S2 = t3;
+            SecP224K1Field.square(Z1.x, S2);
+
+            U2 = t2;
+            SecP224K1Field.multiply(S2, X2.x, U2);
+
+            SecP224K1Field.multiply(S2, Z1.x, S2);
+            SecP224K1Field.multiply(S2, Y2.x, S2);
+        }
+
+        boolean Z2IsOne = Z2.isOne();
+        int[] U1, S1;
+        if (Z2IsOne)
+        {
+            U1 = X1.x;
+            S1 = Y1.x;
+        }
+        else
+        {
+            S1 = t4;
+            SecP224K1Field.square(Z2.x, S1);
+
+            U1 = tt1;
+            SecP224K1Field.multiply(S1, X1.x, U1);
+
+            SecP224K1Field.multiply(S1, Z2.x, S1);
+            SecP224K1Field.multiply(S1, Y1.x, S1);
+        }
+
+        int[] H = Nat224.create();
+        SecP224K1Field.subtract(U1, U2, H);
+
+        int[] R = t2;
+        SecP224K1Field.subtract(S1, S2, R);
+
+        // Check if b == this or b == -this
+        if (Nat224.isZero(H))
+        {
+            if (Nat224.isZero(R))
+            {
+                // this == b, i.e. this must be doubled
+                return this.twice();
+            }
+
+            // this == -b, i.e. the result is the point at infinity
+            return curve.getInfinity();
+        }
+
+        int[] HSquared = t3;
+        SecP224K1Field.square(H, HSquared);
+
+        int[] G = Nat224.create();
+        SecP224K1Field.multiply(HSquared, H, G);
+
+        int[] V = t3;
+        SecP224K1Field.multiply(HSquared, U1, V);
+
+        SecP224K1Field.negate(G, G);
+        Nat224.mul(S1, G, tt1);
+
+        c = Nat224.addBothTo(V, V, G);
+        SecP224K1Field.reduce32(c, G);
+
+        SecP224K1FieldElement X3 = new SecP224K1FieldElement(t4);
+        SecP224K1Field.square(R, X3.x);
+        SecP224K1Field.subtract(X3.x, G, X3.x);
+
+        SecP224K1FieldElement Y3 = new SecP224K1FieldElement(G);
+        SecP224K1Field.subtract(V, X3.x, Y3.x);
+        SecP224K1Field.multiplyAddToExt(Y3.x, R, tt1);
+        SecP224K1Field.reduce(tt1, Y3.x);
+
+        SecP224K1FieldElement Z3 = new SecP224K1FieldElement(H);
+        if (!Z1IsOne)
+        {
+            SecP224K1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+        if (!Z2IsOne)
+        {
+            SecP224K1Field.multiply(Z3.x, Z2.x, Z3.x);
+        }
+
+        ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+        return new SecP224K1Point(curve, X3, Y3, zs, this.withCompression);
+    }
+
+    // B.3 pg 62
+    public ECPoint twice()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP224K1FieldElement Y1 = (SecP224K1FieldElement)this.y;
+        if (Y1.isZero())
+        {
+            return curve.getInfinity();
+        }
+
+        SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.x, Z1 = (SecP224K1FieldElement)this.zs[0];
+
+        int c;
+
+        int[] Y1Squared = Nat224.create();
+        SecP224K1Field.square(Y1.x, Y1Squared);
+
+        int[] T = Nat224.create();
+        SecP224K1Field.square(Y1Squared, T);
+
+        int[] M = Nat224.create();
+        SecP224K1Field.square(X1.x, M);
+        c = Nat224.addBothTo(M, M, M);
+        SecP224K1Field.reduce32(c, M);
+
+        int[] S = Y1Squared;
+        SecP224K1Field.multiply(Y1Squared, X1.x, S);
+        c = Nat.shiftUpBits(7, S, 2, 0);
+        SecP224K1Field.reduce32(c, S);
+
+        int[] t1 = Nat224.create();
+        c = Nat.shiftUpBits(7, T, 3, 0, t1);
+        SecP224K1Field.reduce32(c, t1);
+
+        SecP224K1FieldElement X3 = new SecP224K1FieldElement(T);
+        SecP224K1Field.square(M, X3.x);
+        SecP224K1Field.subtract(X3.x, S, X3.x);
+        SecP224K1Field.subtract(X3.x, S, X3.x);
+
+        SecP224K1FieldElement Y3 = new SecP224K1FieldElement(S);
+        SecP224K1Field.subtract(S, X3.x, Y3.x);
+        SecP224K1Field.multiply(Y3.x, M, Y3.x);
+        SecP224K1Field.subtract(Y3.x, t1, Y3.x);
+
+        SecP224K1FieldElement Z3 = new SecP224K1FieldElement(M);
+        SecP224K1Field.twice(Y1.x, Z3.x);
+        if (!Z1.isOne())
+        {
+            SecP224K1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+
+        return new SecP224K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression);
+    }
+
+    public ECPoint twicePlus(ECPoint b)
+    {
+        if (this == b)
+        {
+            return threeTimes();
+        }
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return twice();
+        }
+
+        ECFieldElement Y1 = this.y;
+        if (Y1.isZero())
+        {
+            return b;
+        }
+
+        return twice().add(b);
+    }
+
+    public ECPoint threeTimes()
+    {
+        if (this.isInfinity() || this.y.isZero())
+        {
+            return this;
+        }
+
+        // NOTE: Be careful about recursions between twicePlus and threeTimes
+        return twice().add(this);
+    }
+
+    public ECPoint negate()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        return new SecP224K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java
new file mode 100644
index 0000000..16ca8bd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java
@@ -0,0 +1,131 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECLookupTable;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat224;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP224R1Curve extends ECCurve.AbstractFp
+{
+    public static final BigInteger q = new BigInteger(1,
+        Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"));
+
+    private static final int SecP224R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+    protected SecP224R1Point infinity;
+
+    public SecP224R1Curve()
+    {
+        super(q);
+
+        this.infinity = new SecP224R1Point(this, null, null);
+
+        this.a = fromBigInteger(new BigInteger(1,
+            Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE")));
+        this.b = fromBigInteger(new BigInteger(1,
+            Hex.decode("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4")));
+        this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"));
+        this.cofactor = BigInteger.valueOf(1);
+
+        this.coord = SecP224R1_DEFAULT_COORDS;
+    }
+
+    protected ECCurve cloneCurve()
+    {
+        return new SecP224R1Curve();
+    }
+
+    public boolean supportsCoordinateSystem(int coord)
+    {
+        switch (coord)
+        {
+        case COORD_JACOBIAN:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public int getFieldSize()
+    {
+        return q.bitLength();
+    }
+
+    public ECFieldElement fromBigInteger(BigInteger x)
+    {
+        return new SecP224R1FieldElement(x);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        return new SecP224R1Point(this, x, y, withCompression);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        return new SecP224R1Point(this, x, y, zs, withCompression);
+    }
+
+    public ECPoint getInfinity()
+    {
+        return infinity;
+    }
+
+    public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len)
+    {
+        final int FE_INTS = 7;
+
+        final int[] table = new int[len * FE_INTS * 2];
+        {
+            int pos = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                ECPoint p = points[off + i];
+                Nat224.copy(((SecP224R1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS;
+                Nat224.copy(((SecP224R1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS;
+            }
+        }
+
+        return new ECLookupTable()
+        {
+            public int getSize()
+            {
+                return len;
+            }
+
+            public ECPoint lookup(int index)
+            {
+                int[] x = Nat224.create(), y = Nat224.create();
+                int pos = 0;
+
+                for (int i = 0; i < len; ++i)
+                {
+                    int MASK = ((i ^ index) - 1) >> 31;
+
+                    for (int j = 0; j < FE_INTS; ++j)
+                    {
+                        x[j] ^= table[pos + j] & MASK;
+                        y[j] ^= table[pos + FE_INTS + j] & MASK;
+                    }
+
+                    pos += (FE_INTS * 2);
+                }
+
+                return createRawPoint(new SecP224R1FieldElement(x), new SecP224R1FieldElement(y), false);
+            }
+        };
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java
new file mode 100644
index 0000000..7737e9d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java
@@ -0,0 +1,302 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat224;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP224R1Field
+{
+    private static final long M = 0xFFFFFFFFL;
+
+    // 2^224 - 2^96 + 1
+    static final int[] P = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+    static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF,
+        0xFFFFFFFF, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+    private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0x00000000,
+        0x00000000, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001 };
+    private static final int P6 = 0xFFFFFFFF;
+    private static final int PExt13 = 0xFFFFFFFF;
+
+    public static void add(int[] x, int[] y, int[] z)
+    {
+        int c = Nat224.add(x, y, z);
+        if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static void addExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.add(14, xx, yy, zz);
+        if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt)))
+        {
+            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.incAt(14, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void addOne(int[] x, int[] z)
+    {
+        int c = Nat.inc(7, x, z);
+        if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static int[] fromBigInteger(BigInteger x)
+    {
+        int[] z = Nat224.fromBigInteger(x);
+        if (z[6] == P6 && Nat224.gte(z, P))
+        {
+            Nat224.subFrom(P, z);
+        }
+        return z;
+    }
+
+    public static void half(int[] x, int[] z)
+    {
+        if ((x[0] & 1) == 0)
+        {
+            Nat.shiftDownBit(7, x, 0, z);
+        }
+        else
+        {
+            int c = Nat224.add(x, P, z);
+            Nat.shiftDownBit(7, z, c);
+        }
+    }
+
+    public static void multiply(int[] x, int[] y, int[] z)
+    {
+        int[] tt = Nat224.createExt();
+        Nat224.mul(x, y, tt);
+        reduce(tt, z);
+    }
+
+    public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+    {
+        int c = Nat224.mulAddTo(x, y, zz);
+        if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt)))
+        {
+            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.incAt(14, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void negate(int[] x, int[] z)
+    {
+        if (Nat224.isZero(x))
+        {
+            Nat224.zero(z);
+        }
+        else
+        {
+            Nat224.sub(P, x, z);
+        }
+    }
+
+    public static void reduce(int[] xx, int[] z)
+    {
+        long xx10 = xx[10] & M, xx11 = xx[11] & M, xx12 = xx[12] & M, xx13 = xx[13] & M;
+
+        final long n = 1;
+
+        long t0 = (xx[7] & M) + xx11 - n;
+        long t1 = (xx[8] & M) + xx12;
+        long t2 = (xx[9] & M) + xx13;
+
+        long cc = 0;
+        cc += (xx[0] & M) - t0;
+        long z0 = cc & M;
+        cc >>= 32;
+        cc += (xx[1] & M) - t1;
+        z[1] = (int)cc;
+        cc >>= 32;
+        cc += (xx[2] & M) - t2;
+        z[2] = (int)cc;
+        cc >>= 32;
+        cc += (xx[3] & M) + t0 - xx10;
+        long z3 = cc & M;
+        cc >>= 32;
+        cc += (xx[4] & M) + t1 - xx11;
+        z[4] = (int)cc;
+        cc >>= 32;
+        cc += (xx[5] & M) + t2 - xx12;
+        z[5] = (int)cc;
+        cc >>= 32;
+        cc += (xx[6] & M) + xx10 - xx13;
+        z[6] = (int)cc;
+        cc >>= 32;
+        cc += n;
+
+//        assert cc >= 0;
+
+        z3 += cc;
+
+        z0 -= cc;
+        z[0] = (int)z0;
+        cc = z0 >> 32;
+        if (cc != 0)
+        {
+            cc += (z[1] & M);
+            z[1] = (int)cc;
+            cc >>= 32;
+            cc += (z[2] & M);
+            z[2] = (int)cc;
+            z3 += cc >> 32;
+        }
+        z[3] = (int)z3;
+        cc = z3 >> 32;
+
+//        assert cc == 0 || cc == 1;
+
+        if ((cc != 0 && Nat.incAt(7, z, 4) != 0)
+            || (z[6] == P6 && Nat224.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static void reduce32(int x, int[] z)
+    {
+        long cc = 0;
+
+        if (x != 0)
+        {
+            long xx07 = x & M;
+
+            cc += (z[0] & M) - xx07;
+            z[0] = (int)cc;
+            cc >>= 32;
+            if (cc != 0)
+            {
+                cc += (z[1] & M);
+                z[1] = (int)cc;
+                cc >>= 32;
+                cc += (z[2] & M);
+                z[2] = (int)cc;
+                cc >>= 32;
+            }
+            cc += (z[3] & M) + xx07;
+            z[3] = (int)cc;
+            cc >>= 32;
+
+//            assert cc == 0 || cc == 1;
+        }
+
+        if ((cc != 0 && Nat.incAt(7, z, 4) != 0)
+            || (z[6] == P6 && Nat224.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static void square(int[] x, int[] z)
+    {
+        int[] tt = Nat224.createExt();
+        Nat224.square(x, tt);
+        reduce(tt, z);
+    }
+
+    public static void squareN(int[] x, int n, int[] z)
+    {
+//        assert n > 0;
+
+        int[] tt = Nat224.createExt();
+        Nat224.square(x, tt);
+        reduce(tt, z);
+
+        while (--n > 0)
+        {
+            Nat224.square(z, tt);
+            reduce(tt, z);
+        }
+    }
+
+    public static void subtract(int[] x, int[] y, int[] z)
+    {
+        int c = Nat224.sub(x, y, z);
+        if (c != 0)
+        {
+            subPInvFrom(z);
+        }
+    }
+
+    public static void subtractExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.sub(14, xx, yy, zz);
+        if (c != 0)
+        {
+            if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.decAt(14, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void twice(int[] x, int[] z)
+    {
+        int c = Nat.shiftUpBit(7, x, 0, z);
+        if (c != 0 || (z[6] == P6 && Nat224.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    private static void addPInvTo(int[] z)
+    {
+        long c = (z[0] & M) - 1;
+        z[0] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            c += (z[1] & M);
+            z[1] = (int)c;
+            c >>= 32;
+            c += (z[2] & M);
+            z[2] = (int)c;
+            c >>= 32;
+        }
+        c += (z[3] & M) + 1;
+        z[3] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            Nat.incAt(7, z, 4);
+        }
+    }
+
+    private static void subPInvFrom(int[] z)
+    {
+        long c = (z[0] & M) + 1;
+        z[0] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            c += (z[1] & M);
+            z[1] = (int)c;
+            c >>= 32;
+            c += (z[2] & M);
+            z[2] = (int)c;
+            c >>= 32;
+        }
+        c += (z[3] & M) - 1;
+        z[3] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            Nat.decAt(7, z, 4);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java
new file mode 100644
index 0000000..e6a4567
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java
@@ -0,0 +1,277 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.raw.Mod;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat224;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP224R1FieldElement extends ECFieldElement.AbstractFp
+{
+    public static final BigInteger Q = SecP224R1Curve.q;
+
+    protected int[] x;
+
+    public SecP224R1FieldElement(BigInteger x)
+    {
+        if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+        {
+            throw new IllegalArgumentException("x value invalid for SecP224R1FieldElement");
+        }
+
+        this.x = SecP224R1Field.fromBigInteger(x);
+    }
+
+    public SecP224R1FieldElement()
+    {
+        this.x = Nat224.create();
+    }
+
+    protected SecP224R1FieldElement(int[] x)
+    {
+        this.x = x;
+    }
+
+    public boolean isZero()
+    {
+        return Nat224.isZero(x);
+    }
+
+    public boolean isOne()
+    {
+        return Nat224.isOne(x);
+    }
+
+    public boolean testBitZero()
+    {
+        return Nat224.getBit(x, 0) == 1;
+    }
+
+    public BigInteger toBigInteger()
+    {
+        return Nat224.toBigInteger(x);
+    }
+
+    public String getFieldName()
+    {
+        return "SecP224R1Field";
+    }
+
+    public int getFieldSize()
+    {
+        return Q.bitLength();
+    }
+
+    public ECFieldElement add(ECFieldElement b)
+    {
+        int[] z = Nat224.create();
+        SecP224R1Field.add(x, ((SecP224R1FieldElement)b).x, z);
+        return new SecP224R1FieldElement(z);
+    }
+
+    public ECFieldElement addOne()
+    {
+        int[] z = Nat224.create();
+        SecP224R1Field.addOne(x, z);
+        return new SecP224R1FieldElement(z);
+    }
+
+    public ECFieldElement subtract(ECFieldElement b)
+    {
+        int[] z = Nat224.create();
+        SecP224R1Field.subtract(x, ((SecP224R1FieldElement)b).x, z);
+        return new SecP224R1FieldElement(z);
+    }
+
+    public ECFieldElement multiply(ECFieldElement b)
+    {
+        int[] z = Nat224.create();
+        SecP224R1Field.multiply(x, ((SecP224R1FieldElement)b).x, z);
+        return new SecP224R1FieldElement(z);
+    }
+
+    public ECFieldElement divide(ECFieldElement b)
+    {
+//        return multiply(b.invert());
+        int[] z = Nat224.create();
+        Mod.invert(SecP224R1Field.P, ((SecP224R1FieldElement)b).x, z);
+        SecP224R1Field.multiply(z, x, z);
+        return new SecP224R1FieldElement(z);
+    }
+
+    public ECFieldElement negate()
+    {
+        int[] z = Nat224.create();
+        SecP224R1Field.negate(x, z);
+        return new SecP224R1FieldElement(z);
+    }
+
+    public ECFieldElement square()
+    {
+        int[] z = Nat224.create();
+        SecP224R1Field.square(x, z);
+        return new SecP224R1FieldElement(z);
+    }
+
+    public ECFieldElement invert()
+    {
+//        return new SecP224R1FieldElement(toBigInteger().modInverse(Q));
+        int[] z = Nat224.create();
+        Mod.invert(SecP224R1Field.P, x, z);
+        return new SecP224R1FieldElement(z);
+    }
+
+    /**
+     * return a sqrt root - the routine verifies that the calculation returns the right value - if
+     * none exists it returns null.
+     */
+    public ECFieldElement sqrt()
+    {
+        int[] c = this.x;
+        if (Nat224.isZero(c) || Nat224.isOne(c))
+        {
+            return this;
+        }
+
+        int[] nc = Nat224.create();
+        SecP224R1Field.negate(c, nc);
+
+        int[] r = Mod.random(SecP224R1Field.P);
+        int[] t = Nat224.create();
+
+        if (!isSquare(c))
+        {
+            return null;
+        }
+
+        while (!trySqrt(nc, r, t))
+        {
+            SecP224R1Field.addOne(r, r);
+        }
+
+        SecP224R1Field.square(t, r);
+
+        return Nat224.eq(c, r) ? new SecP224R1FieldElement(t) : null;
+    }
+
+    public boolean equals(Object other)
+    {
+        if (other == this)
+        {
+            return true;
+        }
+
+        if (!(other instanceof SecP224R1FieldElement))
+        {
+            return false;
+        }
+
+        SecP224R1FieldElement o = (SecP224R1FieldElement)other;
+        return Nat224.eq(x, o.x);
+    }
+
+    public int hashCode()
+    {
+        return Q.hashCode() ^ Arrays.hashCode(x, 0, 7);
+    }
+
+    private static boolean isSquare(int[] x)
+    {
+        int[] t1 = Nat224.create();
+        int[] t2 = Nat224.create();
+        Nat224.copy(x, t1);
+
+        for (int i = 0; i < 7; ++i)
+        {
+            Nat224.copy(t1, t2);
+            SecP224R1Field.squareN(t1, 1 << i, t1);
+            SecP224R1Field.multiply(t1, t2, t1);
+        }
+
+        SecP224R1Field.squareN(t1, 95, t1);
+        return Nat224.isOne(t1);
+    }
+
+    private static void RM(int[] nc, int[] d0, int[] e0, int[] d1, int[] e1, int[] f1, int[] t)
+    {
+        SecP224R1Field.multiply(e1, e0, t);
+        SecP224R1Field.multiply(t, nc, t);
+        SecP224R1Field.multiply(d1, d0, f1);
+        SecP224R1Field.add(f1, t, f1);
+        SecP224R1Field.multiply(d1, e0, t);
+        Nat224.copy(f1, d1);
+        SecP224R1Field.multiply(e1, d0, e1);
+        SecP224R1Field.add(e1, t, e1);
+        SecP224R1Field.square(e1, f1);
+        SecP224R1Field.multiply(f1, nc, f1);
+    }
+
+    private static void RP(int[] nc, int[] d1, int[] e1, int[] f1, int[] t)
+    {
+        Nat224.copy(nc, f1);
+
+        int[] d0 = Nat224.create();
+        int[] e0 = Nat224.create();
+
+        for (int i = 0; i < 7; ++i)
+        {
+            Nat224.copy(d1, d0);
+            Nat224.copy(e1, e0);
+
+            int j = 1 << i;
+            while (--j >= 0)
+            {
+                RS(d1, e1, f1, t);
+            }
+
+            RM(nc, d0, e0, d1, e1, f1, t);
+        }
+    }
+
+    private static void RS(int[] d, int[] e, int[] f, int[] t)
+    {
+        SecP224R1Field.multiply(e, d, e);
+        SecP224R1Field.twice(e, e);
+        SecP224R1Field.square(d, t);
+        SecP224R1Field.add(f, t, d);
+        SecP224R1Field.multiply(f, t, f);
+        int c = Nat.shiftUpBits(7, f, 2, 0);
+        SecP224R1Field.reduce32(c, f);
+    }
+
+    private static boolean trySqrt(int[] nc, int[] r, int[] t)
+    {
+        int[] d1 = Nat224.create();
+        Nat224.copy(r, d1);
+        int[] e1 = Nat224.create();
+        e1[0] = 1;
+        int[] f1 = Nat224.create();
+        RP(nc, d1, e1, f1, t);
+
+        int[] d0 = Nat224.create();
+        int[] e0 = Nat224.create();
+
+        for (int k = 1; k < 96; ++k)
+        {
+            Nat224.copy(d1, d0);
+            Nat224.copy(e1, e0);
+
+            RS(d1, e1, f1, t);
+
+            if (Nat224.isZero(d1))
+            {
+                Mod.invert(SecP224R1Field.P, e0, t);
+                SecP224R1Field.multiply(t, d0, t);
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java
new file mode 100644
index 0000000..ece3777
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java
@@ -0,0 +1,312 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat224;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP224R1Point extends ECPoint.AbstractFp
+{
+    /**
+     * Create a point which encodes with point compression.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     *
+     * @deprecated Use ECCurve.createPoint to construct points
+     */
+    public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+    {
+        this(curve, x, y, false);
+    }
+
+    /**
+     * Create a point that encodes with or without point compresion.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     * @param withCompression
+     *            if true encode with point compression
+     *
+     * @deprecated per-point compression property will be removed, refer
+     *             {@link #getEncoded(boolean)}
+     */
+    public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        super(curve, x, y);
+
+        if ((x == null) != (y == null))
+        {
+            throw new IllegalArgumentException("Exactly one of the field elements is null");
+        }
+
+        this.withCompression = withCompression;
+    }
+
+    SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        super(curve, x, y, zs);
+
+        this.withCompression = withCompression;
+    }
+
+    protected ECPoint detach()
+    {
+        return new SecP224R1Point(null, getAffineXCoord(), getAffineYCoord());
+    }
+
+    public ECPoint add(ECPoint b)
+    {
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return this;
+        }
+        if (this == b)
+        {
+            return twice();
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.x, Y1 = (SecP224R1FieldElement)this.y;
+        SecP224R1FieldElement X2 = (SecP224R1FieldElement)b.getXCoord(), Y2 = (SecP224R1FieldElement)b.getYCoord();
+
+        SecP224R1FieldElement Z1 = (SecP224R1FieldElement)this.zs[0];
+        SecP224R1FieldElement Z2 = (SecP224R1FieldElement)b.getZCoord(0);
+
+        int c;
+        int[] tt1 = Nat224.createExt();
+        int[] t2 = Nat224.create();
+        int[] t3 = Nat224.create();
+        int[] t4 = Nat224.create();
+
+        boolean Z1IsOne = Z1.isOne();
+        int[] U2, S2;
+        if (Z1IsOne)
+        {
+            U2 = X2.x;
+            S2 = Y2.x;
+        }
+        else
+        {
+            S2 = t3;
+            SecP224R1Field.square(Z1.x, S2);
+
+            U2 = t2;
+            SecP224R1Field.multiply(S2, X2.x, U2);
+
+            SecP224R1Field.multiply(S2, Z1.x, S2);
+            SecP224R1Field.multiply(S2, Y2.x, S2);
+        }
+
+        boolean Z2IsOne = Z2.isOne();
+        int[] U1, S1;
+        if (Z2IsOne)
+        {
+            U1 = X1.x;
+            S1 = Y1.x;
+        }
+        else
+        {
+            S1 = t4;
+            SecP224R1Field.square(Z2.x, S1);
+
+            U1 = tt1;
+            SecP224R1Field.multiply(S1, X1.x, U1);
+
+            SecP224R1Field.multiply(S1, Z2.x, S1);
+            SecP224R1Field.multiply(S1, Y1.x, S1);
+        }
+
+        int[] H = Nat224.create();
+        SecP224R1Field.subtract(U1, U2, H);
+
+        int[] R = t2;
+        SecP224R1Field.subtract(S1, S2, R);
+
+        // Check if b == this or b == -this
+        if (Nat224.isZero(H))
+        {
+            if (Nat224.isZero(R))
+            {
+                // this == b, i.e. this must be doubled
+                return this.twice();
+            }
+
+            // this == -b, i.e. the result is the point at infinity
+            return curve.getInfinity();
+        }
+
+        int[] HSquared = t3;
+        SecP224R1Field.square(H, HSquared);
+
+        int[] G = Nat224.create();
+        SecP224R1Field.multiply(HSquared, H, G);
+
+        int[] V = t3;
+        SecP224R1Field.multiply(HSquared, U1, V);
+
+        SecP224R1Field.negate(G, G);
+        Nat224.mul(S1, G, tt1);
+
+        c = Nat224.addBothTo(V, V, G);
+        SecP224R1Field.reduce32(c, G);
+
+        SecP224R1FieldElement X3 = new SecP224R1FieldElement(t4);
+        SecP224R1Field.square(R, X3.x);
+        SecP224R1Field.subtract(X3.x, G, X3.x);
+
+        SecP224R1FieldElement Y3 = new SecP224R1FieldElement(G);
+        SecP224R1Field.subtract(V, X3.x, Y3.x);
+        SecP224R1Field.multiplyAddToExt(Y3.x, R, tt1);
+        SecP224R1Field.reduce(tt1, Y3.x);
+
+        SecP224R1FieldElement Z3 = new SecP224R1FieldElement(H);
+        if (!Z1IsOne)
+        {
+            SecP224R1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+        if (!Z2IsOne)
+        {
+            SecP224R1Field.multiply(Z3.x, Z2.x, Z3.x);
+        }
+
+        ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+        return new SecP224R1Point(curve, X3, Y3, zs, this.withCompression);
+    }
+
+    public ECPoint twice()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP224R1FieldElement Y1 = (SecP224R1FieldElement)this.y;
+        if (Y1.isZero())
+        {
+            return curve.getInfinity();
+        }
+
+        SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.x, Z1 = (SecP224R1FieldElement)this.zs[0];
+
+        int c;
+        int[] t1 = Nat224.create();
+        int[] t2 = Nat224.create();
+
+        int[] Y1Squared = Nat224.create();
+        SecP224R1Field.square(Y1.x, Y1Squared);
+
+        int[] T = Nat224.create();
+        SecP224R1Field.square(Y1Squared, T);
+
+        boolean Z1IsOne = Z1.isOne();
+
+        int[] Z1Squared = Z1.x;
+        if (!Z1IsOne)
+        {
+            Z1Squared = t2;
+            SecP224R1Field.square(Z1.x, Z1Squared);
+        }
+
+        SecP224R1Field.subtract(X1.x, Z1Squared, t1);
+
+        int[] M = t2;
+        SecP224R1Field.add(X1.x, Z1Squared, M);
+        SecP224R1Field.multiply(M, t1, M);
+        c = Nat224.addBothTo(M, M, M);
+        SecP224R1Field.reduce32(c, M);
+
+        int[] S = Y1Squared;
+        SecP224R1Field.multiply(Y1Squared, X1.x, S);
+        c = Nat.shiftUpBits(7, S, 2, 0);
+        SecP224R1Field.reduce32(c, S);
+
+        c = Nat.shiftUpBits(7, T, 3, 0, t1);
+        SecP224R1Field.reduce32(c, t1);
+
+        SecP224R1FieldElement X3 = new SecP224R1FieldElement(T);
+        SecP224R1Field.square(M, X3.x);
+        SecP224R1Field.subtract(X3.x, S, X3.x);
+        SecP224R1Field.subtract(X3.x, S, X3.x);
+
+        SecP224R1FieldElement Y3 = new SecP224R1FieldElement(S);
+        SecP224R1Field.subtract(S, X3.x, Y3.x);
+        SecP224R1Field.multiply(Y3.x, M, Y3.x);
+        SecP224R1Field.subtract(Y3.x, t1, Y3.x);
+
+        SecP224R1FieldElement Z3 = new SecP224R1FieldElement(M);
+        SecP224R1Field.twice(Y1.x, Z3.x);
+        if (!Z1IsOne)
+        {
+            SecP224R1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+
+        return new SecP224R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+    }
+
+    public ECPoint twicePlus(ECPoint b)
+    {
+        if (this == b)
+        {
+            return threeTimes();
+        }
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return twice();
+        }
+
+        ECFieldElement Y1 = this.y;
+        if (Y1.isZero())
+        {
+            return b;
+        }
+
+        return twice().add(b);
+    }
+
+    public ECPoint threeTimes()
+    {
+        if (this.isInfinity() || this.y.isZero())
+        {
+            return this;
+        }
+
+        // NOTE: Be careful about recursions between twicePlus and threeTimes
+        return twice().add(this);
+    }
+
+    public ECPoint negate()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        return new SecP224R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java
new file mode 100644
index 0000000..31d5b4c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java
@@ -0,0 +1,129 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECConstants;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECLookupTable;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat256;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP256K1Curve extends ECCurve.AbstractFp
+{
+    public static final BigInteger q = new BigInteger(1,
+        Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"));
+
+    private static final int SECP256K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+    protected SecP256K1Point infinity;
+
+    public SecP256K1Curve()
+    {
+        super(q);
+
+        this.infinity = new SecP256K1Point(this, null, null);
+
+        this.a = fromBigInteger(ECConstants.ZERO);
+        this.b = fromBigInteger(BigInteger.valueOf(7));
+        this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"));
+        this.cofactor = BigInteger.valueOf(1);
+        this.coord = SECP256K1_DEFAULT_COORDS;
+    }
+
+    protected ECCurve cloneCurve()
+    {
+        return new SecP256K1Curve();
+    }
+
+    public boolean supportsCoordinateSystem(int coord)
+    {
+        switch (coord)
+        {
+        case COORD_JACOBIAN:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public int getFieldSize()
+    {
+        return q.bitLength();
+    }
+
+    public ECFieldElement fromBigInteger(BigInteger x)
+    {
+        return new SecP256K1FieldElement(x);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        return new SecP256K1Point(this, x, y, withCompression);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        return new SecP256K1Point(this, x, y, zs, withCompression);
+    }
+
+    public ECPoint getInfinity()
+    {
+        return infinity;
+    }
+
+    public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len)
+    {
+        final int FE_INTS = 8;
+
+        final int[] table = new int[len * FE_INTS * 2];
+        {
+            int pos = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                ECPoint p = points[off + i];
+                Nat256.copy(((SecP256K1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS;
+                Nat256.copy(((SecP256K1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS;
+            }
+        }
+
+        return new ECLookupTable()
+        {
+            public int getSize()
+            {
+                return len;
+            }
+
+            public ECPoint lookup(int index)
+            {
+                int[] x = Nat256.create(), y = Nat256.create();
+                int pos = 0;
+
+                for (int i = 0; i < len; ++i)
+                {
+                    int MASK = ((i ^ index) - 1) >> 31;
+
+                    for (int j = 0; j < FE_INTS; ++j)
+                    {
+                        x[j] ^= table[pos + j] & MASK;
+                        y[j] ^= table[pos + FE_INTS + j] & MASK;
+                    }
+
+                    pos += (FE_INTS * 2);
+                }
+
+                return createRawPoint(new SecP256K1FieldElement(x), new SecP256K1FieldElement(y), false);
+            }
+        };
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java
new file mode 100644
index 0000000..f8cdada
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java
@@ -0,0 +1,183 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat256;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP256K1Field
+{
+    // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
+    static final int[] P = new int[]{ 0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+        0xFFFFFFFF, 0xFFFFFFFF };
+    static final int[] PExt = new int[]{ 0x000E90A1, 0x000007A2, 0x00000001, 0x00000000, 0x00000000,
+        0x00000000, 0x00000000, 0x00000000, 0xFFFFF85E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+        0xFFFFFFFF, 0xFFFFFFFF };
+    private static final int[] PExtInv = new int[]{ 0xFFF16F5F, 0xFFFFF85D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000007A1, 0x00000002 };
+    private static final int P7 = 0xFFFFFFFF;
+    private static final int PExt15 = 0xFFFFFFFF;
+    private static final int PInv33 = 0x3D1;
+
+    public static void add(int[] x, int[] y, int[] z)
+    {
+        int c = Nat256.add(x, y, z);
+        if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
+        {
+            Nat.add33To(8, PInv33, z);
+        }
+    }
+
+    public static void addExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.add(16, xx, yy, zz);
+        if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt)))
+        {
+            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.incAt(16, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void addOne(int[] x, int[] z)
+    {
+        int c = Nat.inc(8, x, z);
+        if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
+        {
+            Nat.add33To(8, PInv33, z);
+        }
+    }
+
+    public static int[] fromBigInteger(BigInteger x)
+    {
+        int[] z = Nat256.fromBigInteger(x);
+        if (z[7] == P7 && Nat256.gte(z, P))
+        {
+            Nat256.subFrom(P, z);
+        }
+        return z;
+    }
+
+    public static void half(int[] x, int[] z)
+    {
+        if ((x[0] & 1) == 0)
+        {
+            Nat.shiftDownBit(8, x, 0, z);
+        }
+        else
+        {
+            int c = Nat256.add(x, P, z);
+            Nat.shiftDownBit(8, z, c);
+        }
+    }
+
+    public static void multiply(int[] x, int[] y, int[] z)
+    {
+        int[] tt = Nat256.createExt();
+        Nat256.mul(x, y, tt);
+        reduce(tt, z);
+    }
+
+    public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+    {
+        int c = Nat256.mulAddTo(x, y, zz);
+        if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt)))
+        {
+            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.incAt(16, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void negate(int[] x, int[] z)
+    {
+        if (Nat256.isZero(x))
+        {
+            Nat256.zero(z);
+        }
+        else
+        {
+            Nat256.sub(P, x, z);
+        }
+    }
+
+    public static void reduce(int[] xx, int[] z)
+    {
+        long cc = Nat256.mul33Add(PInv33, xx, 8, xx, 0, z, 0);
+        int c = Nat256.mul33DWordAdd(PInv33, cc, z, 0);
+
+        // assert c == 0L || c == 1L;
+
+        if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
+        {
+            Nat.add33To(8, PInv33, z);
+        }
+    }
+
+    public static void reduce32(int x, int[] z)
+    {
+        if ((x != 0 && Nat256.mul33WordAdd(PInv33, x, z, 0) != 0)
+            || (z[7] == P7 && Nat256.gte(z, P)))
+        {
+            Nat.add33To(8, PInv33, z);
+        }
+    }
+
+    public static void square(int[] x, int[] z)
+    {
+        int[] tt = Nat256.createExt();
+        Nat256.square(x, tt);
+        reduce(tt, z);
+    }
+
+    public static void squareN(int[] x, int n, int[] z)
+    {
+//        assert n > 0;
+
+        int[] tt = Nat256.createExt();
+        Nat256.square(x, tt);
+        reduce(tt, z);
+
+        while (--n > 0)
+        {
+            Nat256.square(z, tt);
+            reduce(tt, z);
+        }
+    }
+
+    public static void subtract(int[] x, int[] y, int[] z)
+    {
+        int c = Nat256.sub(x, y, z);
+        if (c != 0)
+        {
+            Nat.sub33From(8, PInv33, z);
+        }
+    }
+
+    public static void subtractExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.sub(16, xx, yy, zz);
+        if (c != 0)
+        {
+            if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.decAt(16, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void twice(int[] x, int[] z)
+    {
+        int c = Nat.shiftUpBit(8, x, 0, z);
+        if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
+        {
+            Nat.add33To(8, PInv33, z);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java
new file mode 100644
index 0000000..eb6c123
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java
@@ -0,0 +1,219 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.raw.Mod;
+import com.android.internal.org.bouncycastle.math.raw.Nat256;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP256K1FieldElement extends ECFieldElement.AbstractFp
+{
+    public static final BigInteger Q = SecP256K1Curve.q;
+
+    protected int[] x;
+
+    public SecP256K1FieldElement(BigInteger x)
+    {
+        if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+        {
+            throw new IllegalArgumentException("x value invalid for SecP256K1FieldElement");
+        }
+
+        this.x = SecP256K1Field.fromBigInteger(x);
+    }
+
+    public SecP256K1FieldElement()
+    {
+        this.x = Nat256.create();
+    }
+
+    protected SecP256K1FieldElement(int[] x)
+    {
+        this.x = x;
+    }
+
+    public boolean isZero()
+    {
+        return Nat256.isZero(x);
+    }
+
+    public boolean isOne()
+    {
+        return Nat256.isOne(x);
+    }
+
+    public boolean testBitZero()
+    {
+        return Nat256.getBit(x, 0) == 1;
+    }
+
+    public BigInteger toBigInteger()
+    {
+        return Nat256.toBigInteger(x);
+    }
+
+    public String getFieldName()
+    {
+        return "SecP256K1Field";
+    }
+
+    public int getFieldSize()
+    {
+        return Q.bitLength();
+    }
+
+    public ECFieldElement add(ECFieldElement b)
+    {
+        int[] z = Nat256.create();
+        SecP256K1Field.add(x, ((SecP256K1FieldElement)b).x, z);
+        return new SecP256K1FieldElement(z);
+    }
+
+    public ECFieldElement addOne()
+    {
+        int[] z = Nat256.create();
+        SecP256K1Field.addOne(x, z);
+        return new SecP256K1FieldElement(z);
+    }
+
+    public ECFieldElement subtract(ECFieldElement b)
+    {
+        int[] z = Nat256.create();
+        SecP256K1Field.subtract(x, ((SecP256K1FieldElement)b).x, z);
+        return new SecP256K1FieldElement(z);
+    }
+
+    public ECFieldElement multiply(ECFieldElement b)
+    {
+        int[] z = Nat256.create();
+        SecP256K1Field.multiply(x, ((SecP256K1FieldElement)b).x, z);
+        return new SecP256K1FieldElement(z);
+    }
+
+    public ECFieldElement divide(ECFieldElement b)
+    {
+//        return multiply(b.invert());
+        int[] z = Nat256.create();
+        Mod.invert(SecP256K1Field.P, ((SecP256K1FieldElement)b).x, z);
+        SecP256K1Field.multiply(z, x, z);
+        return new SecP256K1FieldElement(z);
+    }
+
+    public ECFieldElement negate()
+    {
+        int[] z = Nat256.create();
+        SecP256K1Field.negate(x, z);
+        return new SecP256K1FieldElement(z);
+    }
+
+    public ECFieldElement square()
+    {
+        int[] z = Nat256.create();
+        SecP256K1Field.square(x, z);
+        return new SecP256K1FieldElement(z);
+    }
+
+    public ECFieldElement invert()
+    {
+//        return new SecP256K1FieldElement(toBigInteger().modInverse(Q));
+        int[] z = Nat256.create();
+        Mod.invert(SecP256K1Field.P, x, z);
+        return new SecP256K1FieldElement(z);
+    }
+
+    // D.1.4 91
+    /**
+     * return a sqrt root - the routine verifies that the calculation returns the right value - if
+     * none exists it returns null.
+     */
+    public ECFieldElement sqrt()
+    {
+        /*
+         * Raise this element to the exponent 2^254 - 2^30 - 2^7 - 2^6 - 2^5 - 2^4 - 2^2
+         *
+         * Breaking up the exponent's binary representation into "repunits", we get:
+         * { 223 1s } { 1 0s } { 22 1s } { 4 0s } { 2 1s } { 2 0s}
+         *
+         * Therefore we need an addition chain containing 2, 22, 223 (the lengths of the repunits)
+         * We use: 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
+         */
+
+        int[] x1 = this.x;
+        if (Nat256.isZero(x1) || Nat256.isOne(x1))
+        {
+            return this;
+        }
+
+        int[] x2 = Nat256.create();
+        SecP256K1Field.square(x1, x2);
+        SecP256K1Field.multiply(x2, x1, x2);
+        int[] x3 = Nat256.create();
+        SecP256K1Field.square(x2, x3);
+        SecP256K1Field.multiply(x3, x1, x3);
+        int[] x6 = Nat256.create();
+        SecP256K1Field.squareN(x3, 3, x6);
+        SecP256K1Field.multiply(x6, x3, x6);
+        int[] x9 = x6;
+        SecP256K1Field.squareN(x6, 3, x9);
+        SecP256K1Field.multiply(x9, x3, x9);
+        int[] x11 = x9;
+        SecP256K1Field.squareN(x9, 2, x11);
+        SecP256K1Field.multiply(x11, x2, x11);
+        int[] x22 = Nat256.create();
+        SecP256K1Field.squareN(x11, 11, x22);
+        SecP256K1Field.multiply(x22, x11, x22);
+        int[] x44 = x11;
+        SecP256K1Field.squareN(x22, 22, x44);
+        SecP256K1Field.multiply(x44, x22, x44);
+        int[] x88 = Nat256.create();
+        SecP256K1Field.squareN(x44, 44, x88);
+        SecP256K1Field.multiply(x88, x44, x88);
+        int[] x176 = Nat256.create();
+        SecP256K1Field.squareN(x88, 88, x176);
+        SecP256K1Field.multiply(x176, x88, x176);
+        int[] x220 = x88;
+        SecP256K1Field.squareN(x176, 44, x220);
+        SecP256K1Field.multiply(x220, x44, x220);
+        int[] x223 = x44;
+        SecP256K1Field.squareN(x220, 3, x223);
+        SecP256K1Field.multiply(x223, x3, x223);
+
+        int[] t1 = x223;
+        SecP256K1Field.squareN(t1, 23, t1);
+        SecP256K1Field.multiply(t1, x22, t1);
+        SecP256K1Field.squareN(t1, 6, t1);
+        SecP256K1Field.multiply(t1, x2, t1);
+        SecP256K1Field.squareN(t1, 2, t1);
+
+        int[] t2 = x2;
+        SecP256K1Field.square(t1, t2);
+
+        return Nat256.eq(x1, t2) ? new SecP256K1FieldElement(t1) : null;
+    }
+
+    public boolean equals(Object other)
+    {
+        if (other == this)
+        {
+            return true;
+        }
+
+        if (!(other instanceof SecP256K1FieldElement))
+        {
+            return false;
+        }
+
+        SecP256K1FieldElement o = (SecP256K1FieldElement)other;
+        return Nat256.eq(x, o.x);
+    }
+
+    public int hashCode()
+    {
+        return Q.hashCode() ^ Arrays.hashCode(x, 0, 8);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java
new file mode 100644
index 0000000..b3d17da
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java
@@ -0,0 +1,302 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat256;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP256K1Point extends ECPoint.AbstractFp
+{
+    /**
+     * Create a point which encodes with point compression.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     *
+     * @deprecated Use ECCurve.createPoint to construct points
+     */
+    public SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+    {
+        this(curve, x, y, false);
+    }
+
+    /**
+     * Create a point that encodes with or without point compresion.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     * @param withCompression
+     *            if true encode with point compression
+     *
+     * @deprecated per-point compression property will be removed, refer
+     *             {@link #getEncoded(boolean)}
+     */
+    public SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        super(curve, x, y);
+
+        if ((x == null) != (y == null))
+        {
+            throw new IllegalArgumentException("Exactly one of the field elements is null");
+        }
+
+        this.withCompression = withCompression;
+    }
+
+    SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+        boolean withCompression)
+    {
+        super(curve, x, y, zs);
+
+        this.withCompression = withCompression;
+    }
+
+    protected ECPoint detach()
+    {
+        return new SecP256K1Point(null, getAffineXCoord(), getAffineYCoord());
+    }
+
+    // B.3 pg 62
+    public ECPoint add(ECPoint b)
+    {
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return this;
+        }
+        if (this == b)
+        {
+            return twice();
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP256K1FieldElement X1 = (SecP256K1FieldElement)this.x, Y1 = (SecP256K1FieldElement)this.y;
+        SecP256K1FieldElement X2 = (SecP256K1FieldElement)b.getXCoord(), Y2 = (SecP256K1FieldElement)b.getYCoord();
+
+        SecP256K1FieldElement Z1 = (SecP256K1FieldElement)this.zs[0];
+        SecP256K1FieldElement Z2 = (SecP256K1FieldElement)b.getZCoord(0);
+
+        int c;
+        int[] tt1 = Nat256.createExt();
+        int[] t2 = Nat256.create();
+        int[] t3 = Nat256.create();
+        int[] t4 = Nat256.create();
+
+        boolean Z1IsOne = Z1.isOne();
+        int[] U2, S2;
+        if (Z1IsOne)
+        {
+            U2 = X2.x;
+            S2 = Y2.x;
+        }
+        else
+        {
+            S2 = t3;
+            SecP256K1Field.square(Z1.x, S2);
+
+            U2 = t2;
+            SecP256K1Field.multiply(S2, X2.x, U2);
+
+            SecP256K1Field.multiply(S2, Z1.x, S2);
+            SecP256K1Field.multiply(S2, Y2.x, S2);
+        }
+
+        boolean Z2IsOne = Z2.isOne();
+        int[] U1, S1;
+        if (Z2IsOne)
+        {
+            U1 = X1.x;
+            S1 = Y1.x;
+        }
+        else
+        {
+            S1 = t4;
+            SecP256K1Field.square(Z2.x, S1);
+
+            U1 = tt1;
+            SecP256K1Field.multiply(S1, X1.x, U1);
+
+            SecP256K1Field.multiply(S1, Z2.x, S1);
+            SecP256K1Field.multiply(S1, Y1.x, S1);
+        }
+
+        int[] H = Nat256.create();
+        SecP256K1Field.subtract(U1, U2, H);
+
+        int[] R = t2;
+        SecP256K1Field.subtract(S1, S2, R);
+
+        // Check if b == this or b == -this
+        if (Nat256.isZero(H))
+        {
+            if (Nat256.isZero(R))
+            {
+                // this == b, i.e. this must be doubled
+                return this.twice();
+            }
+
+            // this == -b, i.e. the result is the point at infinity
+            return curve.getInfinity();
+        }
+
+        int[] HSquared = t3;
+        SecP256K1Field.square(H, HSquared);
+
+        int[] G = Nat256.create();
+        SecP256K1Field.multiply(HSquared, H, G);
+
+        int[] V = t3;
+        SecP256K1Field.multiply(HSquared, U1, V);
+
+        SecP256K1Field.negate(G, G);
+        Nat256.mul(S1, G, tt1);
+
+        c = Nat256.addBothTo(V, V, G);
+        SecP256K1Field.reduce32(c, G);
+
+        SecP256K1FieldElement X3 = new SecP256K1FieldElement(t4);
+        SecP256K1Field.square(R, X3.x);
+        SecP256K1Field.subtract(X3.x, G, X3.x);
+
+        SecP256K1FieldElement Y3 = new SecP256K1FieldElement(G);
+        SecP256K1Field.subtract(V, X3.x, Y3.x);
+        SecP256K1Field.multiplyAddToExt(Y3.x, R, tt1);
+        SecP256K1Field.reduce(tt1, Y3.x);
+
+        SecP256K1FieldElement Z3 = new SecP256K1FieldElement(H);
+        if (!Z1IsOne)
+        {
+            SecP256K1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+        if (!Z2IsOne)
+        {
+            SecP256K1Field.multiply(Z3.x, Z2.x, Z3.x);
+        }
+
+        ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+        return new SecP256K1Point(curve, X3, Y3, zs, this.withCompression);
+    }
+
+    // B.3 pg 62
+    public ECPoint twice()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP256K1FieldElement Y1 = (SecP256K1FieldElement)this.y;
+        if (Y1.isZero())
+        {
+            return curve.getInfinity();
+        }
+
+        SecP256K1FieldElement X1 = (SecP256K1FieldElement)this.x, Z1 = (SecP256K1FieldElement)this.zs[0];
+
+        int c;
+
+        int[] Y1Squared = Nat256.create();
+        SecP256K1Field.square(Y1.x, Y1Squared);
+
+        int[] T = Nat256.create();
+        SecP256K1Field.square(Y1Squared, T);
+
+        int[] M = Nat256.create();
+        SecP256K1Field.square(X1.x, M);
+        c = Nat256.addBothTo(M, M, M);
+        SecP256K1Field.reduce32(c, M);
+
+        int[] S = Y1Squared;
+        SecP256K1Field.multiply(Y1Squared, X1.x, S);
+        c = Nat.shiftUpBits(8, S, 2, 0);
+        SecP256K1Field.reduce32(c, S);
+
+        int[] t1 = Nat256.create();
+        c = Nat.shiftUpBits(8, T, 3, 0, t1);
+        SecP256K1Field.reduce32(c, t1);
+
+        SecP256K1FieldElement X3 = new SecP256K1FieldElement(T);
+        SecP256K1Field.square(M, X3.x);
+        SecP256K1Field.subtract(X3.x, S, X3.x);
+        SecP256K1Field.subtract(X3.x, S, X3.x);
+
+        SecP256K1FieldElement Y3 = new SecP256K1FieldElement(S);
+        SecP256K1Field.subtract(S, X3.x, Y3.x);
+        SecP256K1Field.multiply(Y3.x, M, Y3.x);
+        SecP256K1Field.subtract(Y3.x, t1, Y3.x);
+
+        SecP256K1FieldElement Z3 = new SecP256K1FieldElement(M);
+        SecP256K1Field.twice(Y1.x, Z3.x);
+        if (!Z1.isOne())
+        {
+            SecP256K1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+
+        return new SecP256K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression);
+    }
+
+    public ECPoint twicePlus(ECPoint b)
+    {
+        if (this == b)
+        {
+            return threeTimes();
+        }
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return twice();
+        }
+
+        ECFieldElement Y1 = this.y;
+        if (Y1.isZero())
+        {
+            return b;
+        }
+
+        return twice().add(b);
+    }
+
+    public ECPoint threeTimes()
+    {
+        if (this.isInfinity() || this.y.isZero())
+        {
+            return this;
+        }
+
+        // NOTE: Be careful about recursions between twicePlus and threeTimes
+        return twice().add(this);
+    }
+
+    public ECPoint negate()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        return new SecP256K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java
new file mode 100644
index 0000000..54477c1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java
@@ -0,0 +1,131 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECLookupTable;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat256;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP256R1Curve extends ECCurve.AbstractFp
+{
+    public static final BigInteger q = new BigInteger(1,
+        Hex.decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"));
+
+    private static final int SecP256R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+    protected SecP256R1Point infinity;
+
+    public SecP256R1Curve()
+    {
+        super(q);
+
+        this.infinity = new SecP256R1Point(this, null, null);
+
+        this.a = fromBigInteger(new BigInteger(1,
+            Hex.decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC")));
+        this.b = fromBigInteger(new BigInteger(1,
+            Hex.decode("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B")));
+        this.order = new BigInteger(1, Hex.decode("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"));
+        this.cofactor = BigInteger.valueOf(1);
+
+        this.coord = SecP256R1_DEFAULT_COORDS;
+    }
+
+    protected ECCurve cloneCurve()
+    {
+        return new SecP256R1Curve();
+    }
+
+    public boolean supportsCoordinateSystem(int coord)
+    {
+        switch (coord)
+        {
+        case COORD_JACOBIAN:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public int getFieldSize()
+    {
+        return q.bitLength();
+    }
+
+    public ECFieldElement fromBigInteger(BigInteger x)
+    {
+        return new SecP256R1FieldElement(x);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        return new SecP256R1Point(this, x, y, withCompression);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        return new SecP256R1Point(this, x, y, zs, withCompression);
+    }
+
+    public ECPoint getInfinity()
+    {
+        return infinity;
+    }
+
+    public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len)
+    {
+        final int FE_INTS = 8;
+
+        final int[] table = new int[len * FE_INTS * 2];
+        {
+            int pos = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                ECPoint p = points[off + i];
+                Nat256.copy(((SecP256R1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS;
+                Nat256.copy(((SecP256R1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS;
+            }
+        }
+
+        return new ECLookupTable()
+        {
+            public int getSize()
+            {
+                return len;
+            }
+
+            public ECPoint lookup(int index)
+            {
+                int[] x = Nat256.create(), y = Nat256.create();
+                int pos = 0;
+
+                for (int i = 0; i < len; ++i)
+                {
+                    int MASK = ((i ^ index) - 1) >> 31;
+
+                    for (int j = 0; j < FE_INTS; ++j)
+                    {
+                        x[j] ^= table[pos + j] & MASK;
+                        y[j] ^= table[pos + FE_INTS + j] & MASK;
+                    }
+
+                    pos += (FE_INTS * 2);
+                }
+
+                return createRawPoint(new SecP256R1FieldElement(x), new SecP256R1FieldElement(y), false);
+            }
+        };
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java
new file mode 100644
index 0000000..bbec4bc
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java
@@ -0,0 +1,317 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat256;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP256R1Field
+{
+    private static final long M = 0xFFFFFFFFL;
+
+    // 2^256 - 2^224 + 2^192 + 2^96 - 1
+    static final int[] P = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,
+        0x00000001, 0xFFFFFFFF };
+    static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF,
+        0xFFFFFFFF, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0x00000001, 0xFFFFFFFE,
+        0x00000002, 0xFFFFFFFE };
+    private static final int P7 = 0xFFFFFFFF;
+    private static final int PExt15s1 = 0xFFFFFFFE >>> 1;
+
+    public static void add(int[] x, int[] y, int[] z)
+    {
+        int c = Nat256.add(x, y, z);
+        if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static void addExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.add(16, xx, yy, zz);
+        if (c != 0 || ((zz[15] >>> 1) >= PExt15s1 && Nat.gte(16, zz, PExt)))
+        {
+            Nat.subFrom(16, PExt, zz);
+        }
+    }
+
+    public static void addOne(int[] x, int[] z)
+    {
+        int c = Nat.inc(8, x, z);
+        if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static int[] fromBigInteger(BigInteger x)
+    {
+        int[] z = Nat256.fromBigInteger(x);
+        if (z[7] == P7 && Nat256.gte(z, P))
+        {
+            Nat256.subFrom(P, z);
+        }
+        return z;
+    }
+
+    public static void half(int[] x, int[] z)
+    {
+        if ((x[0] & 1) == 0)
+        {
+            Nat.shiftDownBit(8, x, 0, z);
+        }
+        else
+        {
+            int c = Nat256.add(x, P, z);
+            Nat.shiftDownBit(8, z, c);
+        }
+    }
+
+    public static void multiply(int[] x, int[] y, int[] z)
+    {
+        int[] tt = Nat256.createExt();
+        Nat256.mul(x, y, tt);
+        reduce(tt, z);
+    }
+
+    public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
+    {
+        int c = Nat256.mulAddTo(x, y, zz);
+        if (c != 0 || ((zz[15] >>> 1) >= PExt15s1 && Nat.gte(16, zz, PExt)))
+        {
+            Nat.subFrom(16, PExt, zz);
+        }
+    }
+
+    public static void negate(int[] x, int[] z)
+    {
+        if (Nat256.isZero(x))
+        {
+            Nat256.zero(z);
+        }
+        else
+        {
+            Nat256.sub(P, x, z);
+        }
+    }
+
+    public static void reduce(int[] xx, int[] z)
+    {
+        long xx08 = xx[8] & M, xx09 = xx[9] & M, xx10 = xx[10] & M, xx11 = xx[11] & M;
+        long xx12 = xx[12] & M, xx13 = xx[13] & M, xx14 = xx[14] & M, xx15 = xx[15] & M;
+
+        final long n = 6;
+
+        xx08 -= n;
+
+        long t0 = xx08 + xx09;
+        long t1 = xx09 + xx10;
+        long t2 = xx10 + xx11 - xx15;
+        long t3 = xx11 + xx12;
+        long t4 = xx12 + xx13;
+        long t5 = xx13 + xx14;
+        long t6 = xx14 + xx15;
+        long t7 = t5 - t0;
+
+        long cc = 0;
+        cc += (xx[0] & M) - t3 - t7;
+        z[0] = (int)cc;
+        cc >>= 32;
+        cc += (xx[1] & M) + t1 - t4 - t6;
+        z[1] = (int)cc;
+        cc >>= 32;
+        cc += (xx[2] & M) + t2 - t5;
+        z[2] = (int)cc;
+        cc >>= 32;
+        cc += (xx[3] & M) + (t3 << 1) + t7 - t6;
+        z[3] = (int)cc;
+        cc >>= 32;
+        cc += (xx[4] & M) + (t4 << 1) + xx14 - t1;
+        z[4] = (int)cc;
+        cc >>= 32;
+        cc += (xx[5] & M) + (t5 << 1) - t2;
+        z[5] = (int)cc;
+        cc >>= 32;
+        cc += (xx[6] & M) + (t6 << 1) + t7;
+        z[6] = (int)cc;
+        cc >>= 32;
+        cc += (xx[7] & M) + (xx15 << 1) + xx08 - t2 - t4;
+        z[7] = (int)cc;
+        cc >>= 32;
+        cc += n;
+
+//        assert cc >= 0;
+
+        reduce32((int)cc, z);
+    }
+
+    public static void reduce32(int x, int[] z)
+    {
+        long cc = 0;
+
+        if (x != 0)
+        {
+            long xx08 = x & M;
+
+            cc += (z[0] & M) + xx08;
+            z[0] = (int)cc;
+            cc >>= 32;
+            if (cc != 0)
+            {
+                cc += (z[1] & M);
+                z[1] = (int)cc;
+                cc >>= 32;
+                cc += (z[2] & M);
+                z[2] = (int)cc;
+                cc >>= 32;
+            }
+            cc += (z[3] & M) - xx08;
+            z[3] = (int)cc;
+            cc >>= 32;
+            if (cc != 0)
+            {
+                cc += (z[4] & M);
+                z[4] = (int)cc;
+                cc >>= 32;
+                cc += (z[5] & M);
+                z[5] = (int)cc;
+                cc >>= 32;
+            }
+            cc += (z[6] & M) - xx08;
+            z[6] = (int)cc;
+            cc >>= 32;
+            cc += (z[7] & M) + xx08;
+            z[7] = (int)cc;
+            cc >>= 32;
+
+//          assert cc == 0 || cc == 1;
+        }
+
+        if (cc != 0 || (z[7] == P7 && Nat256.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static void square(int[] x, int[] z)
+    {
+        int[] tt = Nat256.createExt();
+        Nat256.square(x, tt);
+        reduce(tt, z);
+    }
+
+    public static void squareN(int[] x, int n, int[] z)
+    {
+//        assert n > 0;
+
+        int[] tt = Nat256.createExt();
+        Nat256.square(x, tt);
+        reduce(tt, z);
+
+        while (--n > 0)
+        {
+            Nat256.square(z, tt);
+            reduce(tt, z);
+        }
+    }
+
+    public static void subtract(int[] x, int[] y, int[] z)
+    {
+        int c = Nat256.sub(x, y, z);
+        if (c != 0)
+        {
+            subPInvFrom(z);
+        }
+    }
+
+    public static void subtractExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.sub(16, xx, yy, zz);
+        if (c != 0)
+        {
+            Nat.addTo(16, PExt, zz);
+        }
+    }
+
+    public static void twice(int[] x, int[] z)
+    {
+        int c = Nat.shiftUpBit(8, x, 0, z);
+        if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    private static void addPInvTo(int[] z)
+    {
+        long c = (z[0] & M) + 1;
+        z[0] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            c += (z[1] & M);
+            z[1] = (int)c;
+            c >>= 32;
+            c += (z[2] & M);
+            z[2] = (int)c;
+            c >>= 32;
+        }
+        c += (z[3] & M) - 1;
+        z[3] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            c += (z[4] & M);
+            z[4] = (int)c;
+            c >>= 32;
+            c += (z[5] & M);
+            z[5] = (int)c;
+            c >>= 32;
+        }
+        c += (z[6] & M) - 1;
+        z[6] = (int)c;
+        c >>= 32;
+        c += (z[7] & M) + 1;
+        z[7] = (int)c;
+//        c >>= 32;
+    }
+
+    private static void subPInvFrom(int[] z)
+    {
+        long c = (z[0] & M) - 1;
+        z[0] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            c += (z[1] & M);
+            z[1] = (int)c;
+            c >>= 32;
+            c += (z[2] & M);
+            z[2] = (int)c;
+            c >>= 32;
+        }
+        c += (z[3] & M) + 1;
+        z[3] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            c += (z[4] & M);
+            z[4] = (int)c;
+            c >>= 32;
+            c += (z[5] & M);
+            z[5] = (int)c;
+            c >>= 32;
+        }
+        c += (z[6] & M) + 1;
+        z[6] = (int)c;
+        c >>= 32;
+        c += (z[7] & M) - 1;
+        z[7] = (int)c;
+//        c >>= 32;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java
new file mode 100644
index 0000000..e373c76
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java
@@ -0,0 +1,193 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.raw.Mod;
+import com.android.internal.org.bouncycastle.math.raw.Nat256;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP256R1FieldElement extends ECFieldElement.AbstractFp
+{
+    public static final BigInteger Q = SecP256R1Curve.q;
+
+    protected int[] x;
+
+    public SecP256R1FieldElement(BigInteger x)
+    {
+        if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+        {
+            throw new IllegalArgumentException("x value invalid for SecP256R1FieldElement");
+        }
+
+        this.x = SecP256R1Field.fromBigInteger(x);
+    }
+
+    public SecP256R1FieldElement()
+    {
+        this.x = Nat256.create();
+    }
+
+    protected SecP256R1FieldElement(int[] x)
+    {
+        this.x = x;
+    }
+
+    public boolean isZero()
+    {
+        return Nat256.isZero(x);
+    }
+
+    public boolean isOne()
+    {
+        return Nat256.isOne(x);
+    }
+
+    public boolean testBitZero()
+    {
+        return Nat256.getBit(x, 0) == 1;
+    }
+
+    public BigInteger toBigInteger()
+    {
+        return Nat256.toBigInteger(x);
+    }
+
+    public String getFieldName()
+    {
+        return "SecP256R1Field";
+    }
+
+    public int getFieldSize()
+    {
+        return Q.bitLength();
+    }
+
+    public ECFieldElement add(ECFieldElement b)
+    {
+        int[] z = Nat256.create();
+        SecP256R1Field.add(x, ((SecP256R1FieldElement)b).x, z);
+        return new SecP256R1FieldElement(z);
+    }
+
+    public ECFieldElement addOne()
+    {
+        int[] z = Nat256.create();
+        SecP256R1Field.addOne(x, z);
+        return new SecP256R1FieldElement(z);
+    }
+
+    public ECFieldElement subtract(ECFieldElement b)
+    {
+        int[] z = Nat256.create();
+        SecP256R1Field.subtract(x, ((SecP256R1FieldElement)b).x, z);
+        return new SecP256R1FieldElement(z);
+    }
+
+    public ECFieldElement multiply(ECFieldElement b)
+    {
+        int[] z = Nat256.create();
+        SecP256R1Field.multiply(x, ((SecP256R1FieldElement)b).x, z);
+        return new SecP256R1FieldElement(z);
+    }
+
+    public ECFieldElement divide(ECFieldElement b)
+    {
+//        return multiply(b.invert());
+        int[] z = Nat256.create();
+        Mod.invert(SecP256R1Field.P, ((SecP256R1FieldElement)b).x, z);
+        SecP256R1Field.multiply(z, x, z);
+        return new SecP256R1FieldElement(z);
+    }
+
+    public ECFieldElement negate()
+    {
+        int[] z = Nat256.create();
+        SecP256R1Field.negate(x, z);
+        return new SecP256R1FieldElement(z);
+    }
+
+    public ECFieldElement square()
+    {
+        int[] z = Nat256.create();
+        SecP256R1Field.square(x, z);
+        return new SecP256R1FieldElement(z);
+    }
+
+    public ECFieldElement invert()
+    {
+//        return new SecP256R1FieldElement(toBigInteger().modInverse(Q));
+        int[] z = Nat256.create();
+        Mod.invert(SecP256R1Field.P, x, z);
+        return new SecP256R1FieldElement(z);
+    }
+
+    /**
+     * return a sqrt root - the routine verifies that the calculation returns the right value - if
+     * none exists it returns null.
+     */
+    public ECFieldElement sqrt()
+    {
+        // Raise this element to the exponent 2^254 - 2^222 + 2^190 + 2^94
+
+        int[] x1 = this.x;
+        if (Nat256.isZero(x1) || Nat256.isOne(x1))
+        {
+            return this;
+        }
+
+        int[] t1 = Nat256.create();
+        int[] t2 = Nat256.create();
+
+        SecP256R1Field.square(x1, t1);
+        SecP256R1Field.multiply(t1, x1, t1);
+
+        SecP256R1Field.squareN(t1, 2, t2);
+        SecP256R1Field.multiply(t2, t1, t2);
+
+        SecP256R1Field.squareN(t2, 4, t1);
+        SecP256R1Field.multiply(t1, t2, t1);
+
+        SecP256R1Field.squareN(t1, 8, t2);
+        SecP256R1Field.multiply(t2, t1, t2);
+
+        SecP256R1Field.squareN(t2, 16, t1);
+        SecP256R1Field.multiply(t1, t2, t1);
+
+        SecP256R1Field.squareN(t1, 32, t1);
+        SecP256R1Field.multiply(t1, x1, t1);
+
+        SecP256R1Field.squareN(t1, 96, t1);
+        SecP256R1Field.multiply(t1, x1, t1);
+
+        SecP256R1Field.squareN(t1, 94, t1);
+        SecP256R1Field.square(t1, t2);
+
+        return Nat256.eq(x1, t2) ? new SecP256R1FieldElement(t1) : null;
+    }
+
+    public boolean equals(Object other)
+    {
+        if (other == this)
+        {
+            return true;
+        }
+
+        if (!(other instanceof SecP256R1FieldElement))
+        {
+            return false;
+        }
+
+        SecP256R1FieldElement o = (SecP256R1FieldElement)other;
+        return Nat256.eq(x, o.x);
+    }
+
+    public int hashCode()
+    {
+        return Q.hashCode() ^ Arrays.hashCode(x, 0, 8);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java
new file mode 100644
index 0000000..a7abfbd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java
@@ -0,0 +1,312 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat256;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP256R1Point extends ECPoint.AbstractFp
+{
+    /**
+     * Create a point which encodes with point compression.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     *
+     * @deprecated Use ECCurve.createPoint to construct points
+     */
+    public SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+    {
+        this(curve, x, y, false);
+    }
+
+    /**
+     * Create a point that encodes with or without point compresion.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     * @param withCompression
+     *            if true encode with point compression
+     *
+     * @deprecated per-point compression property will be removed, refer
+     *             {@link #getEncoded(boolean)}
+     */
+    public SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        super(curve, x, y);
+
+        if ((x == null) != (y == null))
+        {
+            throw new IllegalArgumentException("Exactly one of the field elements is null");
+        }
+
+        this.withCompression = withCompression;
+    }
+
+    SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        super(curve, x, y, zs);
+
+        this.withCompression = withCompression;
+    }
+
+    protected ECPoint detach()
+    {
+        return new SecP256R1Point(null, getAffineXCoord(), getAffineYCoord());
+    }
+
+    public ECPoint add(ECPoint b)
+    {
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return this;
+        }
+        if (this == b)
+        {
+            return twice();
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP256R1FieldElement X1 = (SecP256R1FieldElement)this.x, Y1 = (SecP256R1FieldElement)this.y;
+        SecP256R1FieldElement X2 = (SecP256R1FieldElement)b.getXCoord(), Y2 = (SecP256R1FieldElement)b.getYCoord();
+
+        SecP256R1FieldElement Z1 = (SecP256R1FieldElement)this.zs[0];
+        SecP256R1FieldElement Z2 = (SecP256R1FieldElement)b.getZCoord(0);
+
+        int c;
+        int[] tt1 = Nat256.createExt();
+        int[] t2 = Nat256.create();
+        int[] t3 = Nat256.create();
+        int[] t4 = Nat256.create();
+
+        boolean Z1IsOne = Z1.isOne();
+        int[] U2, S2;
+        if (Z1IsOne)
+        {
+            U2 = X2.x;
+            S2 = Y2.x;
+        }
+        else
+        {
+            S2 = t3;
+            SecP256R1Field.square(Z1.x, S2);
+
+            U2 = t2;
+            SecP256R1Field.multiply(S2, X2.x, U2);
+
+            SecP256R1Field.multiply(S2, Z1.x, S2);
+            SecP256R1Field.multiply(S2, Y2.x, S2);
+        }
+
+        boolean Z2IsOne = Z2.isOne();
+        int[] U1, S1;
+        if (Z2IsOne)
+        {
+            U1 = X1.x;
+            S1 = Y1.x;
+        }
+        else
+        {
+            S1 = t4;
+            SecP256R1Field.square(Z2.x, S1);
+
+            U1 = tt1;
+            SecP256R1Field.multiply(S1, X1.x, U1);
+
+            SecP256R1Field.multiply(S1, Z2.x, S1);
+            SecP256R1Field.multiply(S1, Y1.x, S1);
+        }
+
+        int[] H = Nat256.create();
+        SecP256R1Field.subtract(U1, U2, H);
+
+        int[] R = t2;
+        SecP256R1Field.subtract(S1, S2, R);
+
+        // Check if b == this or b == -this
+        if (Nat256.isZero(H))
+        {
+            if (Nat256.isZero(R))
+            {
+                // this == b, i.e. this must be doubled
+                return this.twice();
+            }
+
+            // this == -b, i.e. the result is the point at infinity
+            return curve.getInfinity();
+        }
+
+        int[] HSquared = t3;
+        SecP256R1Field.square(H, HSquared);
+
+        int[] G = Nat256.create();
+        SecP256R1Field.multiply(HSquared, H, G);
+
+        int[] V = t3;
+        SecP256R1Field.multiply(HSquared, U1, V);
+
+        SecP256R1Field.negate(G, G);
+        Nat256.mul(S1, G, tt1);
+
+        c = Nat256.addBothTo(V, V, G);
+        SecP256R1Field.reduce32(c, G);
+
+        SecP256R1FieldElement X3 = new SecP256R1FieldElement(t4);
+        SecP256R1Field.square(R, X3.x);
+        SecP256R1Field.subtract(X3.x, G, X3.x);
+
+        SecP256R1FieldElement Y3 = new SecP256R1FieldElement(G);
+        SecP256R1Field.subtract(V, X3.x, Y3.x);
+        SecP256R1Field.multiplyAddToExt(Y3.x, R, tt1);
+        SecP256R1Field.reduce(tt1, Y3.x);
+
+        SecP256R1FieldElement Z3 = new SecP256R1FieldElement(H);
+        if (!Z1IsOne)
+        {
+            SecP256R1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+        if (!Z2IsOne)
+        {
+            SecP256R1Field.multiply(Z3.x, Z2.x, Z3.x);
+        }
+
+        ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+        return new SecP256R1Point(curve, X3, Y3, zs, this.withCompression);
+    }
+
+    public ECPoint twice()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP256R1FieldElement Y1 = (SecP256R1FieldElement)this.y;
+        if (Y1.isZero())
+        {
+            return curve.getInfinity();
+        }
+
+        SecP256R1FieldElement X1 = (SecP256R1FieldElement)this.x, Z1 = (SecP256R1FieldElement)this.zs[0];
+
+        int c;
+        int[] t1 = Nat256.create();
+        int[] t2 = Nat256.create();
+
+        int[] Y1Squared = Nat256.create();
+        SecP256R1Field.square(Y1.x, Y1Squared);
+
+        int[] T = Nat256.create();
+        SecP256R1Field.square(Y1Squared, T);
+
+        boolean Z1IsOne = Z1.isOne();
+
+        int[] Z1Squared = Z1.x;
+        if (!Z1IsOne)
+        {
+            Z1Squared = t2;
+            SecP256R1Field.square(Z1.x, Z1Squared);
+        }
+
+        SecP256R1Field.subtract(X1.x, Z1Squared, t1);
+
+        int[] M = t2;
+        SecP256R1Field.add(X1.x, Z1Squared, M);
+        SecP256R1Field.multiply(M, t1, M);
+        c = Nat256.addBothTo(M, M, M);
+        SecP256R1Field.reduce32(c, M);
+
+        int[] S = Y1Squared;
+        SecP256R1Field.multiply(Y1Squared, X1.x, S);
+        c = Nat.shiftUpBits(8, S, 2, 0);
+        SecP256R1Field.reduce32(c, S);
+
+        c = Nat.shiftUpBits(8, T, 3, 0, t1);
+        SecP256R1Field.reduce32(c, t1);
+
+        SecP256R1FieldElement X3 = new SecP256R1FieldElement(T);
+        SecP256R1Field.square(M, X3.x);
+        SecP256R1Field.subtract(X3.x, S, X3.x);
+        SecP256R1Field.subtract(X3.x, S, X3.x);
+
+        SecP256R1FieldElement Y3 = new SecP256R1FieldElement(S);
+        SecP256R1Field.subtract(S, X3.x, Y3.x);
+        SecP256R1Field.multiply(Y3.x, M, Y3.x);
+        SecP256R1Field.subtract(Y3.x, t1, Y3.x);
+
+        SecP256R1FieldElement Z3 = new SecP256R1FieldElement(M);
+        SecP256R1Field.twice(Y1.x, Z3.x);
+        if (!Z1IsOne)
+        {
+            SecP256R1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+
+        return new SecP256R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+    }
+
+    public ECPoint twicePlus(ECPoint b)
+    {
+        if (this == b)
+        {
+            return threeTimes();
+        }
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return twice();
+        }
+
+        ECFieldElement Y1 = this.y;
+        if (Y1.isZero())
+        {
+            return b;
+        }
+
+        return twice().add(b);
+    }
+
+    public ECPoint threeTimes()
+    {
+        if (this.isInfinity() || this.y.isZero())
+        {
+            return this;
+        }
+
+        // NOTE: Be careful about recursions between twicePlus and threeTimes
+        return twice().add(this);
+    }
+
+    public ECPoint negate()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        return new SecP256R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java
new file mode 100644
index 0000000..bf63167
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java
@@ -0,0 +1,131 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECLookupTable;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP384R1Curve extends ECCurve.AbstractFp
+{
+    public static final BigInteger q = new BigInteger(1,
+        Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"));
+
+    private static final int SecP384R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+    protected SecP384R1Point infinity;
+
+    public SecP384R1Curve()
+    {
+        super(q);
+
+        this.infinity = new SecP384R1Point(this, null, null);
+
+        this.a = fromBigInteger(new BigInteger(1,
+            Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC")));
+        this.b = fromBigInteger(new BigInteger(1,
+            Hex.decode("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF")));
+        this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"));
+        this.cofactor = BigInteger.valueOf(1);
+
+        this.coord = SecP384R1_DEFAULT_COORDS;
+    }
+
+    protected ECCurve cloneCurve()
+    {
+        return new SecP384R1Curve();
+    }
+
+    public boolean supportsCoordinateSystem(int coord)
+    {
+        switch (coord)
+        {
+        case COORD_JACOBIAN:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public int getFieldSize()
+    {
+        return q.bitLength();
+    }
+
+    public ECFieldElement fromBigInteger(BigInteger x)
+    {
+        return new SecP384R1FieldElement(x);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        return new SecP384R1Point(this, x, y, withCompression);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        return new SecP384R1Point(this, x, y, zs, withCompression);
+    }
+
+    public ECPoint getInfinity()
+    {
+        return infinity;
+    }
+
+    public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len)
+    {
+        final int FE_INTS = 12;
+
+        final int[] table = new int[len * FE_INTS * 2];
+        {
+            int pos = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                ECPoint p = points[off + i];
+                Nat.copy(FE_INTS, ((SecP384R1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS;
+                Nat.copy(FE_INTS, ((SecP384R1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS;
+            }
+        }
+
+        return new ECLookupTable()
+        {
+            public int getSize()
+            {
+                return len;
+            }
+
+            public ECPoint lookup(int index)
+            {
+                int[] x = Nat.create(FE_INTS), y = Nat.create(FE_INTS);
+                int pos = 0;
+
+                for (int i = 0; i < len; ++i)
+                {
+                    int MASK = ((i ^ index) - 1) >> 31;
+
+                    for (int j = 0; j < FE_INTS; ++j)
+                    {
+                        x[j] ^= table[pos + j] & MASK;
+                        y[j] ^= table[pos + FE_INTS + j] & MASK;
+                    }
+
+                    pos += (FE_INTS * 2);
+                }
+
+                return createRawPoint(new SecP384R1FieldElement(x), new SecP384R1FieldElement(y), false);
+            }
+        };
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java
new file mode 100644
index 0000000..524a78d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java
@@ -0,0 +1,300 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat384;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP384R1Field
+{
+    private static final long M = 0xFFFFFFFFL;
+
+    // 2^384 - 2^128 - 2^96 + 2^32 - 1
+    static final int[] P = new int[]{ 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF,
+        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+    static final int[] PExt = new int[]{ 0x00000001, 0xFFFFFFFE, 0x00000000, 0x00000002, 0x00000000, 0xFFFFFFFE,
+        0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFE, 0x00000001, 0x00000000,
+        0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+    private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0x00000001,
+        0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFE, 0xFFFFFFFF,
+        0x00000001, 0x00000002 };
+    private static final int P11 = 0xFFFFFFFF;
+    private static final int PExt23 = 0xFFFFFFFF;
+
+    public static void add(int[] x, int[] y, int[] z)
+    {
+        int c = Nat.add(12, x, y, z);
+        if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static void addExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.add(24, xx, yy, zz);
+        if (c != 0 || (zz[23] == PExt23 && Nat.gte(24, zz, PExt)))
+        {
+            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.incAt(24, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void addOne(int[] x, int[] z)
+    {
+        int c = Nat.inc(12, x, z);
+        if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static int[] fromBigInteger(BigInteger x)
+    {
+        int[] z = Nat.fromBigInteger(384, x);
+        if (z[11] == P11 && Nat.gte(12, z, P))
+        {
+            Nat.subFrom(12, P, z);
+        }
+        return z;
+    }
+
+    public static void half(int[] x, int[] z)
+    {
+        if ((x[0] & 1) == 0)
+        {
+            Nat.shiftDownBit(12, x, 0, z);
+        }
+        else
+        {
+            int c = Nat.add(12, x, P, z);
+            Nat.shiftDownBit(12, z, c);
+        }
+    }
+
+    public static void multiply(int[] x, int[] y, int[] z)
+    {
+        int[] tt = Nat.create(24);
+        Nat384.mul(x, y, tt);
+        reduce(tt, z);
+    }
+
+    public static void negate(int[] x, int[] z)
+    {
+        if (Nat.isZero(12, x))
+        {
+            Nat.zero(12, z);
+        }
+        else
+        {
+            Nat.sub(12, P, x, z);
+        }
+    }
+
+    public static void reduce(int[] xx, int[] z)
+    {
+        long xx16 = xx[16] & M, xx17 = xx[17] & M, xx18 = xx[18] & M, xx19 = xx[19] & M;
+        long xx20 = xx[20] & M, xx21 = xx[21] & M, xx22 = xx[22] & M, xx23 = xx[23] & M;
+
+        final long n = 1;
+
+        long t0 = (xx[12] & M) + xx20 - n;
+        long t1 = (xx[13] & M) + xx22;
+        long t2 = (xx[14] & M) + xx22 + xx23;
+        long t3 = (xx[15] & M) + xx23;
+        long t4 = xx17 + xx21;
+        long t5 = xx21 - xx23;
+        long t6 = xx22 - xx23;
+        long t7 = t0 + t5;
+
+        long cc = 0;
+        cc += (xx[0] & M) + t7;
+        z[0] = (int)cc;
+        cc >>= 32;
+        cc += (xx[1] & M) + xx23 - t0 + t1;
+        z[1] = (int)cc;
+        cc >>= 32;
+        cc += (xx[2] & M) - xx21 - t1 + t2;
+        z[2] = (int)cc;
+        cc >>= 32;
+        cc += (xx[3] & M) - t2 + t3 + t7;
+        z[3] = (int)cc;
+        cc >>= 32;
+        cc += (xx[4] & M) + xx16 + xx21 + t1 - t3 + t7;
+        z[4] = (int)cc;
+        cc >>= 32;
+        cc += (xx[5] & M) - xx16 + t1 + t2 + t4;
+        z[5] = (int)cc;
+        cc >>= 32;
+        cc += (xx[6] & M) + xx18 - xx17 + t2 + t3;
+        z[6] = (int)cc;
+        cc >>= 32;
+        cc += (xx[7] & M) + xx16 + xx19 - xx18 + t3;
+        z[7] = (int)cc;
+        cc >>= 32;
+        cc += (xx[8] & M) + xx16 + xx17 + xx20 - xx19;
+        z[8] = (int)cc;
+        cc >>= 32;
+        cc += (xx[9] & M) + xx18 - xx20 + t4;
+        z[9] = (int)cc;
+        cc >>= 32;
+        cc += (xx[10] & M) + xx18 + xx19 - t5 + t6;
+        z[10] = (int)cc;
+        cc >>= 32;
+        cc += (xx[11] & M) + xx19 + xx20 - t6;
+        z[11] = (int)cc;
+        cc >>= 32;
+        cc += n;
+
+//        assert cc >= 0;
+
+        reduce32((int)cc, z);
+    }
+
+    public static void reduce32(int x, int[] z)
+    {
+        long cc = 0;
+
+        if (x != 0)
+        {
+            long xx12 = x & M;
+
+            cc += (z[0] & M) + xx12;
+            z[0] = (int)cc;
+            cc >>= 32;
+            cc += (z[1] & M) - xx12;
+            z[1] = (int)cc;
+            cc >>= 32;
+            if (cc != 0)
+            {
+                cc += (z[2] & M);
+                z[2] = (int)cc;
+                cc >>= 32;
+            }
+            cc += (z[3] & M) + xx12;
+            z[3] = (int)cc;
+            cc >>= 32;
+            cc += (z[4] & M) + xx12;
+            z[4] = (int)cc;
+            cc >>= 32;
+
+//            assert cc == 0 || cc == 1;
+        }
+
+        if ((cc != 0 && Nat.incAt(12, z, 5) != 0)
+            || (z[11] == P11 && Nat.gte(12, z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    public static void square(int[] x, int[] z)
+    {
+        int[] tt = Nat.create(24);
+        Nat384.square(x, tt);
+        reduce(tt, z);
+    }
+
+    public static void squareN(int[] x, int n, int[] z)
+    {
+//        assert n > 0;
+
+        int[] tt = Nat.create(24);
+        Nat384.square(x, tt);
+        reduce(tt, z);
+
+        while (--n > 0)
+        {
+            Nat384.square(z, tt);
+            reduce(tt, z);
+        }
+    }
+
+    public static void subtract(int[] x, int[] y, int[] z)
+    {
+        int c = Nat.sub(12, x, y, z);
+        if (c != 0)
+        {
+            subPInvFrom(z);
+        }
+    }
+
+    public static void subtractExt(int[] xx, int[] yy, int[] zz)
+    {
+        int c = Nat.sub(24, xx, yy, zz);
+        if (c != 0)
+        {
+            if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
+            {
+                Nat.decAt(24, zz, PExtInv.length);
+            }
+        }
+    }
+
+    public static void twice(int[] x, int[] z)
+    {
+        int c = Nat.shiftUpBit(12, x, 0, z);
+        if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P)))
+        {
+            addPInvTo(z);
+        }
+    }
+
+    private static void addPInvTo(int[] z)
+    {
+        long c = (z[0] & M) + 1;
+        z[0] = (int)c;
+        c >>= 32;
+        c += (z[1] & M) - 1;
+        z[1] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            c += (z[2] & M);
+            z[2] = (int)c;
+            c >>= 32;
+        }
+        c += (z[3] & M) + 1;
+        z[3] = (int)c;
+        c >>= 32;
+        c += (z[4] & M) + 1;
+        z[4] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            Nat.incAt(12, z, 5);
+        }
+    }
+
+    private static void subPInvFrom(int[] z)
+    {
+        long c = (z[0] & M) - 1;
+        z[0] = (int)c;
+        c >>= 32;
+        c += (z[1] & M) + 1;
+        z[1] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            c += (z[2] & M);
+            z[2] = (int)c;
+            c >>= 32;
+        }
+        c += (z[3] & M) - 1;
+        z[3] = (int)c;
+        c >>= 32;
+        c += (z[4] & M) - 1;
+        z[4] = (int)c;
+        c >>= 32;
+        if (c != 0)
+        {
+            Nat.decAt(12, z, 5);
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java
new file mode 100644
index 0000000..e58dea8
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java
@@ -0,0 +1,215 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.raw.Mod;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP384R1FieldElement extends ECFieldElement.AbstractFp
+{
+    public static final BigInteger Q = SecP384R1Curve.q;
+
+    protected int[] x;
+
+    public SecP384R1FieldElement(BigInteger x)
+    {
+        if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+        {
+            throw new IllegalArgumentException("x value invalid for SecP384R1FieldElement");
+        }
+
+        this.x = SecP384R1Field.fromBigInteger(x);
+    }
+
+    public SecP384R1FieldElement()
+    {
+        this.x = Nat.create(12);
+    }
+
+    protected SecP384R1FieldElement(int[] x)
+    {
+        this.x = x;
+    }
+
+    public boolean isZero()
+    {
+        return Nat.isZero(12, x);
+    }
+
+    public boolean isOne()
+    {
+        return Nat.isOne(12, x);
+    }
+
+    public boolean testBitZero()
+    {
+        return Nat.getBit(x, 0) == 1;
+    }
+
+    public BigInteger toBigInteger()
+    {
+        return Nat.toBigInteger(12, x);
+    }
+
+    public String getFieldName()
+    {
+        return "SecP384R1Field";
+    }
+
+    public int getFieldSize()
+    {
+        return Q.bitLength();
+    }
+
+    public ECFieldElement add(ECFieldElement b)
+    {
+        int[] z = Nat.create(12);
+        SecP384R1Field.add(x, ((SecP384R1FieldElement)b).x, z);
+        return new SecP384R1FieldElement(z);
+    }
+
+    public ECFieldElement addOne()
+    {
+        int[] z = Nat.create(12);
+        SecP384R1Field.addOne(x, z);
+        return new SecP384R1FieldElement(z);
+    }
+
+    public ECFieldElement subtract(ECFieldElement b)
+    {
+        int[] z = Nat.create(12);
+        SecP384R1Field.subtract(x, ((SecP384R1FieldElement)b).x, z);
+        return new SecP384R1FieldElement(z);
+    }
+
+    public ECFieldElement multiply(ECFieldElement b)
+    {
+        int[] z = Nat.create(12);
+        SecP384R1Field.multiply(x, ((SecP384R1FieldElement)b).x, z);
+        return new SecP384R1FieldElement(z);
+    }
+
+    public ECFieldElement divide(ECFieldElement b)
+    {
+//        return multiply(b.invert());
+        int[] z = Nat.create(12);
+        Mod.invert(SecP384R1Field.P, ((SecP384R1FieldElement)b).x, z);
+        SecP384R1Field.multiply(z, x, z);
+        return new SecP384R1FieldElement(z);
+    }
+
+    public ECFieldElement negate()
+    {
+        int[] z = Nat.create(12);
+        SecP384R1Field.negate(x, z);
+        return new SecP384R1FieldElement(z);
+    }
+
+    public ECFieldElement square()
+    {
+        int[] z = Nat.create(12);
+        SecP384R1Field.square(x, z);
+        return new SecP384R1FieldElement(z);
+    }
+
+    public ECFieldElement invert()
+    {
+//        return new SecP384R1FieldElement(toBigInteger().modInverse(Q));
+        int[] z = Nat.create(12);
+        Mod.invert(SecP384R1Field.P, x, z);
+        return new SecP384R1FieldElement(z);
+    }
+
+    /**
+     * return a sqrt root - the routine verifies that the calculation returns the right value - if
+     * none exists it returns null.
+     */
+    public ECFieldElement sqrt()
+    {
+        // Raise this element to the exponent 2^382 - 2^126 - 2^94 + 2^30
+
+        int[] x1 = this.x;
+        if (Nat.isZero(12, x1) || Nat.isOne(12, x1))
+        {
+            return this;
+        }
+
+        int[] t1 = Nat.create(12);
+        int[] t2 = Nat.create(12);
+        int[] t3 = Nat.create(12);
+        int[] t4 = Nat.create(12);
+
+        SecP384R1Field.square(x1, t1);
+        SecP384R1Field.multiply(t1, x1, t1);
+
+        SecP384R1Field.squareN(t1, 2, t2);
+        SecP384R1Field.multiply(t2, t1, t2);
+
+        SecP384R1Field.square(t2, t2);
+        SecP384R1Field.multiply(t2, x1, t2);
+
+        SecP384R1Field.squareN(t2, 5, t3);
+        SecP384R1Field.multiply(t3, t2, t3);
+
+        SecP384R1Field.squareN(t3, 5, t4);
+        SecP384R1Field.multiply(t4, t2, t4);
+
+        SecP384R1Field.squareN(t4, 15, t2);
+        SecP384R1Field.multiply(t2, t4, t2);
+
+        SecP384R1Field.squareN(t2, 2, t3);
+        SecP384R1Field.multiply(t1, t3, t1);
+
+        SecP384R1Field.squareN(t3, 28, t3);
+        SecP384R1Field.multiply(t2, t3, t2);
+
+        SecP384R1Field.squareN(t2, 60, t3);
+        SecP384R1Field.multiply(t3, t2, t3);
+
+        int[] r = t2;
+
+        SecP384R1Field.squareN(t3, 120, r);
+        SecP384R1Field.multiply(r, t3, r);
+
+        SecP384R1Field.squareN(r, 15, r);
+        SecP384R1Field.multiply(r, t4, r);
+
+        SecP384R1Field.squareN(r, 33, r);
+        SecP384R1Field.multiply(r, t1, r);
+
+        SecP384R1Field.squareN(r, 64, r);
+        SecP384R1Field.multiply(r, x1, r);
+
+        SecP384R1Field.squareN(r, 30, t1);
+        SecP384R1Field.square(t1, t2);
+
+        return Nat.eq(12, x1, t2) ? new SecP384R1FieldElement(t1) : null;
+    }
+
+    public boolean equals(Object other)
+    {
+        if (other == this)
+        {
+            return true;
+        }
+
+        if (!(other instanceof SecP384R1FieldElement))
+        {
+            return false;
+        }
+
+        SecP384R1FieldElement o = (SecP384R1FieldElement)other;
+        return Nat.eq(12, x, o.x);
+    }
+
+    public int hashCode()
+    {
+        return Q.hashCode() ^ Arrays.hashCode(x, 0, 12);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java
new file mode 100644
index 0000000..63b381e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java
@@ -0,0 +1,313 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat384;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP384R1Point extends ECPoint.AbstractFp
+{
+    /**
+     * Create a point which encodes with point compression.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     *
+     * @deprecated Use ECCurve.createPoint to construct points
+     */
+    public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+    {
+        this(curve, x, y, false);
+    }
+
+    /**
+     * Create a point that encodes with or without point compresion.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     * @param withCompression
+     *            if true encode with point compression
+     *
+     * @deprecated per-point compression property will be removed, refer
+     *             {@link #getEncoded(boolean)}
+     */
+    public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        super(curve, x, y);
+
+        if ((x == null) != (y == null))
+        {
+            throw new IllegalArgumentException("Exactly one of the field elements is null");
+        }
+
+        this.withCompression = withCompression;
+    }
+
+    SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        super(curve, x, y, zs);
+
+        this.withCompression = withCompression;
+    }
+
+    protected ECPoint detach()
+    {
+        return new SecP384R1Point(null, getAffineXCoord(), getAffineYCoord());
+    }
+
+    public ECPoint add(ECPoint b)
+    {
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return this;
+        }
+        if (this == b)
+        {
+            return twice();
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.x, Y1 = (SecP384R1FieldElement)this.y;
+        SecP384R1FieldElement X2 = (SecP384R1FieldElement)b.getXCoord(), Y2 = (SecP384R1FieldElement)b.getYCoord();
+
+        SecP384R1FieldElement Z1 = (SecP384R1FieldElement)this.zs[0];
+        SecP384R1FieldElement Z2 = (SecP384R1FieldElement)b.getZCoord(0);
+
+        int c;
+        int[] tt1 = Nat.create(24);
+        int[] tt2 = Nat.create(24);
+        int[] t3 = Nat.create(12);
+        int[] t4 = Nat.create(12);
+
+        boolean Z1IsOne = Z1.isOne();
+        int[] U2, S2;
+        if (Z1IsOne)
+        {
+            U2 = X2.x;
+            S2 = Y2.x;
+        }
+        else
+        {
+            S2 = t3;
+            SecP384R1Field.square(Z1.x, S2);
+
+            U2 = tt2;
+            SecP384R1Field.multiply(S2, X2.x, U2);
+
+            SecP384R1Field.multiply(S2, Z1.x, S2);
+            SecP384R1Field.multiply(S2, Y2.x, S2);
+        }
+
+        boolean Z2IsOne = Z2.isOne();
+        int[] U1, S1;
+        if (Z2IsOne)
+        {
+            U1 = X1.x;
+            S1 = Y1.x;
+        }
+        else
+        {
+            S1 = t4;
+            SecP384R1Field.square(Z2.x, S1);
+
+            U1 = tt1;
+            SecP384R1Field.multiply(S1, X1.x, U1);
+
+            SecP384R1Field.multiply(S1, Z2.x, S1);
+            SecP384R1Field.multiply(S1, Y1.x, S1);
+        }
+
+        int[] H = Nat.create(12);
+        SecP384R1Field.subtract(U1, U2, H);
+
+        int[] R = Nat.create(12);
+        SecP384R1Field.subtract(S1, S2, R);
+
+        // Check if b == this or b == -this
+        if (Nat.isZero(12, H))
+        {
+            if (Nat.isZero(12, R))
+            {
+                // this == b, i.e. this must be doubled
+                return this.twice();
+            }
+
+            // this == -b, i.e. the result is the point at infinity
+            return curve.getInfinity();
+        }
+
+        int[] HSquared = t3;
+        SecP384R1Field.square(H, HSquared);
+
+        int[] G = Nat.create(12);
+        SecP384R1Field.multiply(HSquared, H, G);
+
+        int[] V = t3;
+        SecP384R1Field.multiply(HSquared, U1, V);
+
+        SecP384R1Field.negate(G, G);
+        Nat384.mul(S1, G, tt1);
+
+        c = Nat.addBothTo(12, V, V, G);
+        SecP384R1Field.reduce32(c, G);
+
+        SecP384R1FieldElement X3 = new SecP384R1FieldElement(t4);
+        SecP384R1Field.square(R, X3.x);
+        SecP384R1Field.subtract(X3.x, G, X3.x);
+
+        SecP384R1FieldElement Y3 = new SecP384R1FieldElement(G);
+        SecP384R1Field.subtract(V, X3.x, Y3.x);
+        Nat384.mul(Y3.x, R, tt2);
+        SecP384R1Field.addExt(tt1, tt2, tt1);
+        SecP384R1Field.reduce(tt1, Y3.x);
+
+        SecP384R1FieldElement Z3 = new SecP384R1FieldElement(H);
+        if (!Z1IsOne)
+        {
+            SecP384R1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+        if (!Z2IsOne)
+        {
+            SecP384R1Field.multiply(Z3.x, Z2.x, Z3.x);
+        }
+
+        ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+        return new SecP384R1Point(curve, X3, Y3, zs, this.withCompression);
+    }
+
+    public ECPoint twice()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP384R1FieldElement Y1 = (SecP384R1FieldElement)this.y;
+        if (Y1.isZero())
+        {
+            return curve.getInfinity();
+        }
+
+        SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.x, Z1 = (SecP384R1FieldElement)this.zs[0];
+
+        int c;
+        int[] t1 = Nat.create(12);
+        int[] t2 = Nat.create(12);
+
+        int[] Y1Squared = Nat.create(12);
+        SecP384R1Field.square(Y1.x, Y1Squared);
+
+        int[] T = Nat.create(12);
+        SecP384R1Field.square(Y1Squared, T);
+
+        boolean Z1IsOne = Z1.isOne();
+
+        int[] Z1Squared = Z1.x;
+        if (!Z1IsOne)
+        {
+            Z1Squared = t2;
+            SecP384R1Field.square(Z1.x, Z1Squared);
+        }
+
+        SecP384R1Field.subtract(X1.x, Z1Squared, t1);
+
+        int[] M = t2;
+        SecP384R1Field.add(X1.x, Z1Squared, M);
+        SecP384R1Field.multiply(M, t1, M);
+        c = Nat.addBothTo(12, M, M, M);
+        SecP384R1Field.reduce32(c, M);
+
+        int[] S = Y1Squared;
+        SecP384R1Field.multiply(Y1Squared, X1.x, S);
+        c = Nat.shiftUpBits(12, S, 2, 0);
+        SecP384R1Field.reduce32(c, S);
+
+        c = Nat.shiftUpBits(12, T, 3, 0, t1);
+        SecP384R1Field.reduce32(c, t1);
+
+        SecP384R1FieldElement X3 = new SecP384R1FieldElement(T);
+        SecP384R1Field.square(M, X3.x);
+        SecP384R1Field.subtract(X3.x, S, X3.x);
+        SecP384R1Field.subtract(X3.x, S, X3.x);
+
+        SecP384R1FieldElement Y3 = new SecP384R1FieldElement(S);
+        SecP384R1Field.subtract(S, X3.x, Y3.x);
+        SecP384R1Field.multiply(Y3.x, M, Y3.x);
+        SecP384R1Field.subtract(Y3.x, t1, Y3.x);
+
+        SecP384R1FieldElement Z3 = new SecP384R1FieldElement(M);
+        SecP384R1Field.twice(Y1.x, Z3.x);
+        if (!Z1IsOne)
+        {
+            SecP384R1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+
+        return new SecP384R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+    }
+
+    public ECPoint twicePlus(ECPoint b)
+    {
+        if (this == b)
+        {
+            return threeTimes();
+        }
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return twice();
+        }
+
+        ECFieldElement Y1 = this.y;
+        if (Y1.isZero())
+        {
+            return b;
+        }
+
+        return twice().add(b);
+    }
+
+    public ECPoint threeTimes()
+    {
+        if (this.isInfinity() || this.y.isZero())
+        {
+            return this;
+        }
+
+        // NOTE: Be careful about recursions between twicePlus and threeTimes
+        return twice().add(this);
+    }
+
+    public ECPoint negate()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        return new SecP384R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java
new file mode 100644
index 0000000..5a170b7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java
@@ -0,0 +1,131 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECLookupTable;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.util.encoders.Hex;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP521R1Curve extends ECCurve.AbstractFp
+{
+    public static final BigInteger q = new BigInteger(1,
+        Hex.decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
+
+    private static final int SecP521R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+    protected SecP521R1Point infinity;
+
+    public SecP521R1Curve()
+    {
+        super(q);
+
+        this.infinity = new SecP521R1Point(this, null, null);
+
+        this.a = fromBigInteger(new BigInteger(1,
+            Hex.decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC")));
+        this.b = fromBigInteger(new BigInteger(1,
+            Hex.decode("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00")));
+        this.order = new BigInteger(1, Hex.decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"));
+        this.cofactor = BigInteger.valueOf(1);
+
+        this.coord = SecP521R1_DEFAULT_COORDS;
+    }
+
+    protected ECCurve cloneCurve()
+    {
+        return new SecP521R1Curve();
+    }
+
+    public boolean supportsCoordinateSystem(int coord)
+    {
+        switch (coord)
+        {
+        case COORD_JACOBIAN:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public int getFieldSize()
+    {
+        return q.bitLength();
+    }
+
+    public ECFieldElement fromBigInteger(BigInteger x)
+    {
+        return new SecP521R1FieldElement(x);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        return new SecP521R1Point(this, x, y, withCompression);
+    }
+
+    protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        return new SecP521R1Point(this, x, y, zs, withCompression);
+    }
+
+    public ECPoint getInfinity()
+    {
+        return infinity;
+    }
+
+    public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len)
+    {
+        final int FE_INTS = 17;
+
+        final int[] table = new int[len * FE_INTS * 2];
+        {
+            int pos = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                ECPoint p = points[off + i];
+                Nat.copy(FE_INTS, ((SecP521R1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS;
+                Nat.copy(FE_INTS, ((SecP521R1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS;
+            }
+        }
+
+        return new ECLookupTable()
+        {
+            public int getSize()
+            {
+                return len;
+            }
+
+            public ECPoint lookup(int index)
+            {
+                int[] x = Nat.create(FE_INTS), y = Nat.create(FE_INTS);
+                int pos = 0;
+
+                for (int i = 0; i < len; ++i)
+                {
+                    int MASK = ((i ^ index) - 1) >> 31;
+
+                    for (int j = 0; j < FE_INTS; ++j)
+                    {
+                        x[j] ^= table[pos + j] & MASK;
+                        y[j] ^= table[pos + FE_INTS + j] & MASK;
+                    }
+
+                    pos += (FE_INTS * 2);
+                }
+
+                return createRawPoint(new SecP521R1FieldElement(x), new SecP521R1FieldElement(y), false);
+            }
+        };
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java
new file mode 100644
index 0000000..d29f820
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java
@@ -0,0 +1,160 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.math.raw.Nat512;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP521R1Field
+{
+    // 2^521 - 1
+    static final int[] P = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x1FF };
+    private static final int P16 = 0x1FF;
+
+    public static void add(int[] x, int[] y, int[] z)
+    {
+        int c = Nat.add(16, x, y, z) + x[16] + y[16];
+        if (c > P16 || (c == P16 && Nat.eq(16, z, P)))
+        {
+            c += Nat.inc(16, z);
+            c &= P16;
+        }
+        z[16] = c;
+    }
+
+    public static void addOne(int[] x, int[] z)
+    {
+        int c = Nat.inc(16, x, z) + x[16];
+        if (c > P16 || (c == P16 && Nat.eq(16, z, P)))
+        {
+            c += Nat.inc(16, z);
+            c &= P16;
+        }
+        z[16] = c;
+    }
+
+    public static int[] fromBigInteger(BigInteger x)
+    {
+        int[] z = Nat.fromBigInteger(521, x);
+        if (Nat.eq(17, z, P))
+        {
+            Nat.zero(17, z);
+        }
+        return z;
+    }
+
+    public static void half(int[] x, int[] z)
+    {
+        int x16 = x[16];
+        int c = Nat.shiftDownBit(16, x, x16, z);
+        z[16] = (x16 >>> 1) | (c >>> 23);
+    }
+
+    public static void multiply(int[] x, int[] y, int[] z)
+    {
+        int[] tt = Nat.create(33);
+        implMultiply(x, y, tt);
+        reduce(tt, z);
+    }
+
+    public static void negate(int[] x, int[] z)
+    {
+        if (Nat.isZero(17, x))
+        {
+            Nat.zero(17, z);
+        }
+        else
+        {
+            Nat.sub(17, P, x, z);
+        }
+    }
+
+    public static void reduce(int[] xx, int[] z)
+    {
+//        assert xx[32] >>> 18 == 0;
+
+        int xx32 = xx[32];
+        int c = Nat.shiftDownBits(16, xx, 16, 9, xx32, z, 0) >>> 23;
+        c += xx32 >>> 9;
+        c += Nat.addTo(16, xx, z);
+        if (c > P16 || (c == P16 && Nat.eq(16, z, P)))
+        {
+            c += Nat.inc(16, z);
+            c &= P16;
+        }
+        z[16] = c;
+    }
+
+    public static void reduce23(int[] z)
+    {
+        int z16 = z[16];
+        int c = Nat.addWordTo(16, z16 >>> 9, z) + (z16 & P16);
+        if (c > P16 || (c == P16 && Nat.eq(16, z, P)))
+        {
+            c += Nat.inc(16, z);
+            c &= P16;
+        }
+        z[16] = c;
+    }
+
+    public static void square(int[] x, int[] z)
+    {
+        int[] tt = Nat.create(33);
+        implSquare(x, tt);
+        reduce(tt, z);
+    }
+
+    public static void squareN(int[] x, int n, int[] z)
+    {
+//        assert n > 0;
+
+        int[] tt = Nat.create(33);
+        implSquare(x, tt);
+        reduce(tt, z);
+
+        while (--n > 0)
+        {
+            implSquare(z, tt);
+            reduce(tt, z);
+        }
+    }
+
+    public static void subtract(int[] x, int[] y, int[] z)
+    {
+        int c = Nat.sub(16, x, y, z) + x[16] - y[16];
+        if (c < 0)
+        {
+            c += Nat.dec(16, z);
+            c &= P16;
+        }
+        z[16] = c;
+    }
+
+    public static void twice(int[] x, int[] z)
+    {
+        int x16 = x[16];
+        int c = Nat.shiftUpBit(16, x, x16 << 23, z) | (x16 << 1);
+        z[16] = c & P16;
+    }
+
+    protected static void implMultiply(int[] x, int[] y, int[] zz)
+    {
+        Nat512.mul(x, y, zz);
+
+        int x16 = x[16], y16 = y[16];
+        zz[32] = Nat.mul31BothAdd(16, x16, y, y16, x, zz, 16) + (x16 * y16);
+    }
+
+    protected static void implSquare(int[] x, int[] zz)
+    {
+        Nat512.square(x, zz);
+
+        int x16 = x[16];
+        zz[32] = Nat.mulWordAddTo(16, x16 << 1, x, 0, zz, 16) + (x16 * x16);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java
new file mode 100644
index 0000000..f06233a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java
@@ -0,0 +1,173 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.raw.Mod;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP521R1FieldElement extends ECFieldElement.AbstractFp
+{
+    public static final BigInteger Q = SecP521R1Curve.q;
+
+    protected int[] x;
+
+    public SecP521R1FieldElement(BigInteger x)
+    {
+        if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0)
+        {
+            throw new IllegalArgumentException("x value invalid for SecP521R1FieldElement");
+        }
+
+        this.x = SecP521R1Field.fromBigInteger(x);
+    }
+
+    public SecP521R1FieldElement()
+    {
+        this.x = Nat.create(17);
+    }
+
+    protected SecP521R1FieldElement(int[] x)
+    {
+        this.x = x;
+    }
+
+    public boolean isZero()
+    {
+        return Nat.isZero(17, x);
+    }
+
+    public boolean isOne()
+    {
+        return Nat.isOne(17, x);
+    }
+
+    public boolean testBitZero()
+    {
+        return Nat.getBit(x, 0) == 1;
+    }
+
+    public BigInteger toBigInteger()
+    {
+        return Nat.toBigInteger(17, x);
+    }
+
+    public String getFieldName()
+    {
+        return "SecP521R1Field";
+    }
+
+    public int getFieldSize()
+    {
+        return Q.bitLength();
+    }
+
+    public ECFieldElement add(ECFieldElement b)
+    {
+        int[] z = Nat.create(17);
+        SecP521R1Field.add(x, ((SecP521R1FieldElement)b).x, z);
+        return new SecP521R1FieldElement(z);
+    }
+
+    public ECFieldElement addOne()
+    {
+        int[] z = Nat.create(17);
+        SecP521R1Field.addOne(x, z);
+        return new SecP521R1FieldElement(z);
+    }
+
+    public ECFieldElement subtract(ECFieldElement b)
+    {
+        int[] z = Nat.create(17);
+        SecP521R1Field.subtract(x, ((SecP521R1FieldElement)b).x, z);
+        return new SecP521R1FieldElement(z);
+    }
+
+    public ECFieldElement multiply(ECFieldElement b)
+    {
+        int[] z = Nat.create(17);
+        SecP521R1Field.multiply(x, ((SecP521R1FieldElement)b).x, z);
+        return new SecP521R1FieldElement(z);
+    }
+
+    public ECFieldElement divide(ECFieldElement b)
+    {
+//        return multiply(b.invert());
+        int[] z = Nat.create(17);
+        Mod.invert(SecP521R1Field.P, ((SecP521R1FieldElement)b).x, z);
+        SecP521R1Field.multiply(z, x, z);
+        return new SecP521R1FieldElement(z);
+    }
+
+    public ECFieldElement negate()
+    {
+        int[] z = Nat.create(17);
+        SecP521R1Field.negate(x, z);
+        return new SecP521R1FieldElement(z);
+    }
+
+    public ECFieldElement square()
+    {
+        int[] z = Nat.create(17);
+        SecP521R1Field.square(x, z);
+        return new SecP521R1FieldElement(z);
+    }
+
+    public ECFieldElement invert()
+    {
+//        return new SecP521R1FieldElement(toBigInteger().modInverse(Q));
+        int[] z = Nat.create(17);
+        Mod.invert(SecP521R1Field.P, x, z);
+        return new SecP521R1FieldElement(z);
+    }
+
+    // D.1.4 91
+    /**
+     * return a sqrt root - the routine verifies that the calculation returns the right value - if
+     * none exists it returns null.
+     */
+    public ECFieldElement sqrt()
+    {
+        // Raise this element to the exponent 2^519
+
+        int[] x1 = this.x;
+        if (Nat.isZero(17, x1) || Nat.isOne(17, x1))
+        {
+            return this;
+        }
+
+        int[] t1 = Nat.create(17);
+        int[] t2 = Nat.create(17);
+
+        SecP521R1Field.squareN(x1, 519, t1);
+        SecP521R1Field.square(t1, t2);
+
+        return Nat.eq(17, x1, t2) ? new SecP521R1FieldElement(t1) : null;
+    }
+
+    public boolean equals(Object other)
+    {
+        if (other == this)
+        {
+            return true;
+        }
+
+        if (!(other instanceof SecP521R1FieldElement))
+        {
+            return false;
+        }
+
+        SecP521R1FieldElement o = (SecP521R1FieldElement)other;
+        return Nat.eq(17, x, o.x);
+    }
+
+    public int hashCode()
+    {
+        return Q.hashCode() ^ Arrays.hashCode(x, 0, 17);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java
new file mode 100644
index 0000000..2eef8e2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java
@@ -0,0 +1,337 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.custom.sec;
+
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECFieldElement;
+import com.android.internal.org.bouncycastle.math.ec.ECPoint;
+import com.android.internal.org.bouncycastle.math.raw.Nat;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class SecP521R1Point extends ECPoint.AbstractFp
+{
+    /**
+     * Create a point which encodes with point compression.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     *
+     * @deprecated Use ECCurve.createPoint to construct points
+     */
+    public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+    {
+        this(curve, x, y, false);
+    }
+
+    /**
+     * Create a point that encodes with or without point compresion.
+     *
+     * @param curve
+     *            the curve to use
+     * @param x
+     *            affine x co-ordinate
+     * @param y
+     *            affine y co-ordinate
+     * @param withCompression
+     *            if true encode with point compression
+     *
+     * @deprecated per-point compression property will be removed, refer
+     *             {@link #getEncoded(boolean)}
+     */
+    public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+    {
+        super(curve, x, y);
+
+        if ((x == null) != (y == null))
+        {
+            throw new IllegalArgumentException("Exactly one of the field elements is null");
+        }
+
+        this.withCompression = withCompression;
+    }
+
+    SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
+    {
+        super(curve, x, y, zs);
+
+        this.withCompression = withCompression;
+    }
+
+    protected ECPoint detach()
+    {
+        return new SecP521R1Point(null, getAffineXCoord(), getAffineYCoord());
+    }
+
+    public ECPoint add(ECPoint b)
+    {
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return this;
+        }
+        if (this == b)
+        {
+            return twice();
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP521R1FieldElement X1 = (SecP521R1FieldElement)this.x, Y1 = (SecP521R1FieldElement)this.y;
+        SecP521R1FieldElement X2 = (SecP521R1FieldElement)b.getXCoord(), Y2 = (SecP521R1FieldElement)b.getYCoord();
+
+        SecP521R1FieldElement Z1 = (SecP521R1FieldElement)this.zs[0];
+        SecP521R1FieldElement Z2 = (SecP521R1FieldElement)b.getZCoord(0);
+
+        int[] t1 = Nat.create(17);
+        int[] t2 = Nat.create(17);
+        int[] t3 = Nat.create(17);
+        int[] t4 = Nat.create(17);
+
+        boolean Z1IsOne = Z1.isOne();
+        int[] U2, S2;
+        if (Z1IsOne)
+        {
+            U2 = X2.x;
+            S2 = Y2.x;
+        }
+        else
+        {
+            S2 = t3;
+            SecP521R1Field.square(Z1.x, S2);
+
+            U2 = t2;
+            SecP521R1Field.multiply(S2, X2.x, U2);
+
+            SecP521R1Field.multiply(S2, Z1.x, S2);
+            SecP521R1Field.multiply(S2, Y2.x, S2);
+        }
+
+        boolean Z2IsOne = Z2.isOne();
+        int[] U1, S1;
+        if (Z2IsOne)
+        {
+            U1 = X1.x;
+            S1 = Y1.x;
+        }
+        else
+        {
+            S1 = t4;
+            SecP521R1Field.square(Z2.x, S1);
+
+            U1 = t1;
+            SecP521R1Field.multiply(S1, X1.x, U1);
+
+            SecP521R1Field.multiply(S1, Z2.x, S1);
+            SecP521R1Field.multiply(S1, Y1.x, S1);
+        }
+
+        int[] H = Nat.create(17);
+        SecP521R1Field.subtract(U1, U2, H);
+
+        int[] R = t2;
+        SecP521R1Field.subtract(S1, S2, R);
+
+        // Check if b == this or b == -this
+        if (Nat.isZero(17, H))
+        {
+            if (Nat.isZero(17, R))
+            {
+                // this == b, i.e. this must be doubled
+                return this.twice();
+            }
+
+            // this == -b, i.e. the result is the point at infinity
+            return curve.getInfinity();
+        }
+
+        int[] HSquared = t3;
+        SecP521R1Field.square(H, HSquared);
+
+        int[] G = Nat.create(17);
+        SecP521R1Field.multiply(HSquared, H, G);
+
+        int[] V = t3;
+        SecP521R1Field.multiply(HSquared, U1, V);
+
+        SecP521R1Field.multiply(S1, G, t1);
+
+        SecP521R1FieldElement X3 = new SecP521R1FieldElement(t4);
+        SecP521R1Field.square(R, X3.x);
+        SecP521R1Field.add(X3.x, G, X3.x);
+        SecP521R1Field.subtract(X3.x, V, X3.x);
+        SecP521R1Field.subtract(X3.x, V, X3.x);
+
+        SecP521R1FieldElement Y3 = new SecP521R1FieldElement(G);
+        SecP521R1Field.subtract(V, X3.x, Y3.x);
+        SecP521R1Field.multiply(Y3.x, R, t2);
+        SecP521R1Field.subtract(t2, t1, Y3.x);
+
+        SecP521R1FieldElement Z3 = new SecP521R1FieldElement(H);
+        if (!Z1IsOne)
+        {
+            SecP521R1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+        if (!Z2IsOne)
+        {
+            SecP521R1Field.multiply(Z3.x, Z2.x, Z3.x);
+        }
+
+        ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+        return new SecP521R1Point(curve, X3, Y3, zs, this.withCompression);
+    }
+
+    public ECPoint twice()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        ECCurve curve = this.getCurve();
+
+        SecP521R1FieldElement Y1 = (SecP521R1FieldElement)this.y;
+        if (Y1.isZero())
+        {
+            return curve.getInfinity();
+        }
+
+        SecP521R1FieldElement X1 = (SecP521R1FieldElement)this.x, Z1 = (SecP521R1FieldElement)this.zs[0];
+
+        int[] t1 = Nat.create(17);
+        int[] t2 = Nat.create(17);
+
+        int[] Y1Squared = Nat.create(17);
+        SecP521R1Field.square(Y1.x, Y1Squared);
+
+        int[] T = Nat.create(17);
+        SecP521R1Field.square(Y1Squared, T);
+
+        boolean Z1IsOne = Z1.isOne();
+
+        int[] Z1Squared = Z1.x;
+        if (!Z1IsOne)
+        {
+            Z1Squared = t2;
+            SecP521R1Field.square(Z1.x, Z1Squared);
+        }
+
+        SecP521R1Field.subtract(X1.x, Z1Squared, t1);
+
+        int[] M = t2;
+        SecP521R1Field.add(X1.x, Z1Squared, M);
+        SecP521R1Field.multiply(M, t1, M);
+        Nat.addBothTo(17, M, M, M);
+        SecP521R1Field.reduce23(M);
+
+        int[] S = Y1Squared;
+        SecP521R1Field.multiply(Y1Squared, X1.x, S);
+        Nat.shiftUpBits(17, S, 2, 0);
+        SecP521R1Field.reduce23(S);
+
+        Nat.shiftUpBits(17, T, 3, 0, t1);
+        SecP521R1Field.reduce23(t1);
+
+        SecP521R1FieldElement X3 = new SecP521R1FieldElement(T);
+        SecP521R1Field.square(M, X3.x);
+        SecP521R1Field.subtract(X3.x, S, X3.x);
+        SecP521R1Field.subtract(X3.x, S, X3.x);
+
+        SecP521R1FieldElement Y3 = new SecP521R1FieldElement(S);
+        SecP521R1Field.subtract(S, X3.x, Y3.x);
+        SecP521R1Field.multiply(Y3.x, M, Y3.x);
+        SecP521R1Field.subtract(Y3.x, t1, Y3.x);
+
+        SecP521R1FieldElement Z3 = new SecP521R1FieldElement(M);
+        SecP521R1Field.twice(Y1.x, Z3.x);
+        if (!Z1IsOne)
+        {
+            SecP521R1Field.multiply(Z3.x, Z1.x, Z3.x);
+        }
+
+        return new SecP521R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+    }
+
+    public ECPoint twicePlus(ECPoint b)
+    {
+        if (this == b)
+        {
+            return threeTimes();
+        }
+        if (this.isInfinity())
+        {
+            return b;
+        }
+        if (b.isInfinity())
+        {
+            return twice();
+        }
+
+        ECFieldElement Y1 = this.y;
+        if (Y1.isZero())
+        {
+            return b;
+        }
+
+        return twice().add(b);
+    }
+
+    public ECPoint threeTimes()
+    {
+        if (this.isInfinity() || this.y.isZero())
+        {
+            return this;
+        }
+
+        // NOTE: Be careful about recursions between twicePlus and threeTimes
+        return twice().add(this);
+    }
+
+    protected ECFieldElement two(ECFieldElement x)
+    {
+        return x.add(x);
+    }
+
+    protected ECFieldElement three(ECFieldElement x)
+    {
+        return two(x).add(x);
+    }
+
+    protected ECFieldElement four(ECFieldElement x)
+    {
+        return two(two(x));
+    }
+
+    protected ECFieldElement eight(ECFieldElement x)
+    {
+        return four(two(x));
+    }
+
+    protected ECFieldElement doubleProductFromSquares(ECFieldElement a, ECFieldElement b,
+        ECFieldElement aSquared, ECFieldElement bSquared)
+    {
+        /*
+         * NOTE: If squaring in the field is faster than multiplication, then this is a quicker
+         * way to calculate 2.A.B, if A^2 and B^2 are already known.
+         */
+        return a.add(b).square().subtract(aSquared).subtract(bSquared);
+    }
+
+    public ECPoint negate()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        return new SecP521R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/ECEndomorphism.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/ECEndomorphism.java
new file mode 100644
index 0000000..33cbf99
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/ECEndomorphism.java
@@ -0,0 +1,14 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.endo;
+
+import com.android.internal.org.bouncycastle.math.ec.ECPointMap;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ECEndomorphism
+{
+    ECPointMap getPointMap();
+
+    boolean hasEfficientPointMap();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/GLVEndomorphism.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/GLVEndomorphism.java
new file mode 100644
index 0000000..fe1e939
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/GLVEndomorphism.java
@@ -0,0 +1,12 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.endo;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface GLVEndomorphism extends ECEndomorphism
+{
+    BigInteger[] decomposeScalar(BigInteger k);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java
new file mode 100644
index 0000000..cdec544
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java
@@ -0,0 +1,62 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.endo;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.math.ec.ECConstants;
+import com.android.internal.org.bouncycastle.math.ec.ECCurve;
+import com.android.internal.org.bouncycastle.math.ec.ECPointMap;
+import com.android.internal.org.bouncycastle.math.ec.ScaleXPointMap;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class GLVTypeBEndomorphism implements GLVEndomorphism
+{
+    protected final ECCurve curve;
+    protected final GLVTypeBParameters parameters;
+    protected final ECPointMap pointMap;
+
+    public GLVTypeBEndomorphism(ECCurve curve, GLVTypeBParameters parameters)
+    {
+        this.curve = curve;
+        this.parameters = parameters;
+        this.pointMap = new ScaleXPointMap(curve.fromBigInteger(parameters.getBeta()));
+    }
+
+    public BigInteger[] decomposeScalar(BigInteger k)
+    {
+        int bits = parameters.getBits();
+        BigInteger b1 = calculateB(k, parameters.getG1(), bits);
+        BigInteger b2 = calculateB(k, parameters.getG2(), bits);
+
+        GLVTypeBParameters p = parameters;
+        BigInteger a = k.subtract((b1.multiply(p.getV1A())).add(b2.multiply(p.getV2A())));
+        BigInteger b = (b1.multiply(p.getV1B())).add(b2.multiply(p.getV2B())).negate();
+
+        return new BigInteger[]{ a, b };
+    }
+
+    public ECPointMap getPointMap()
+    {
+        return pointMap;
+    }
+
+    public boolean hasEfficientPointMap()
+    {
+        return true;
+    }
+
+    protected BigInteger calculateB(BigInteger k, BigInteger g, int t)
+    {
+        boolean negative = (g.signum() < 0);
+        BigInteger b = k.multiply(g.abs());
+        boolean extra = b.testBit(t - 1);
+        b = b.shiftRight(t);
+        if (extra)
+        {
+            b = b.add(ECConstants.ONE);
+        }
+        return negative ? b.negate() : b;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java
new file mode 100644
index 0000000..ab49e0a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java
@@ -0,0 +1,102 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.ec.endo;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class GLVTypeBParameters
+{
+    private static void checkVector(BigInteger[] v, String name)
+    {
+        if (v == null || v.length != 2 || v[0] == null || v[1] == null)
+        {
+            throw new IllegalArgumentException("'" + name + "' must consist of exactly 2 (non-null) values");
+        }
+    }
+
+    protected final BigInteger beta;
+    protected final BigInteger lambda;
+    protected final BigInteger v1A, v1B, v2A, v2B;
+    protected final BigInteger g1, g2;
+    protected final int bits;
+
+    public GLVTypeBParameters(BigInteger beta, BigInteger lambda, BigInteger[] v1, BigInteger[] v2, BigInteger g1,
+        BigInteger g2, int bits)
+    {
+        checkVector(v1, "v1");
+        checkVector(v2, "v2");
+
+        this.beta = beta;
+        this.lambda = lambda;
+        this.v1A = v1[0];
+        this.v1B = v1[1];
+        this.v2A = v2[0];
+        this.v2B = v2[1];
+        this.g1 = g1;
+        this.g2 = g2;
+        this.bits = bits;
+    }
+
+    public BigInteger getBeta()
+    {
+        return beta;
+    }
+
+    public BigInteger getLambda()
+    {
+        return lambda;
+    }
+
+    /**
+     * @deprecated Use {@link #getV1A()} and {@link #getV1B()} instead.
+     */
+    public BigInteger[] getV1()
+    {
+        return new BigInteger[]{ v1A, v1B };
+    }
+
+    public BigInteger getV1A()
+    {
+        return v1A;
+    }
+
+    public BigInteger getV1B()
+    {
+        return v1B;
+    }
+
+    /**
+     * @deprecated Use {@link #getV2A()} and {@link #getV2B()} instead.
+     */
+    public BigInteger[] getV2()
+    {
+        return new BigInteger[]{ v2A, v2B };
+    }
+
+    public BigInteger getV2A()
+    {
+        return v2A;
+    }
+
+    public BigInteger getV2B()
+    {
+        return v2B;
+    }
+
+    public BigInteger getG1()
+    {
+        return g1;
+    }
+
+    public BigInteger getG2()
+    {
+        return g2;
+    }
+    
+    public int getBits()
+    {
+        return bits;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/ExtensionField.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/ExtensionField.java
new file mode 100644
index 0000000..9f12727
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/ExtensionField.java
@@ -0,0 +1,12 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.field;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface ExtensionField extends FiniteField
+{
+    FiniteField getSubfield();
+
+    int getDegree();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/FiniteField.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/FiniteField.java
new file mode 100644
index 0000000..32c64bf
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/FiniteField.java
@@ -0,0 +1,14 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.field;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface FiniteField
+{
+    BigInteger getCharacteristic();
+
+    int getDimension();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/FiniteFields.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/FiniteFields.java
new file mode 100644
index 0000000..f318076
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/FiniteFields.java
@@ -0,0 +1,57 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.field;
+
+import java.math.BigInteger;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class FiniteFields
+{
+    static final FiniteField GF_2 = new PrimeField(BigInteger.valueOf(2));
+    static final FiniteField GF_3 = new PrimeField(BigInteger.valueOf(3));
+
+    public static PolynomialExtensionField getBinaryExtensionField(int[] exponents)
+    {
+        if (exponents[0] != 0)
+        {
+            throw new IllegalArgumentException("Irreducible polynomials in GF(2) must have constant term");
+        }
+        for (int i = 1; i < exponents.length; ++i)
+        {
+            if (exponents[i] <= exponents[i - 1])
+            {
+                throw new IllegalArgumentException("Polynomial exponents must be montonically increasing");
+            }
+        }
+
+        return new GenericPolynomialExtensionField(GF_2, new GF2Polynomial(exponents));
+    }
+
+//    public static PolynomialExtensionField getTernaryExtensionField(Term[] terms)
+//    {
+//        return new GenericPolynomialExtensionField(GF_3, new GF3Polynomial(terms));
+//    }
+
+    public static FiniteField getPrimeField(BigInteger characteristic)
+    {
+        int bitLength = characteristic.bitLength();
+        if (characteristic.signum() <= 0 || bitLength < 2)
+        {
+            throw new IllegalArgumentException("'characteristic' must be >= 2");
+        }
+
+        if (bitLength < 3)
+        {
+            switch (characteristic.intValue())
+            {
+            case 2:
+                return GF_2;
+            case 3:
+                return GF_3;
+            }
+        }
+
+        return new PrimeField(characteristic);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/GF2Polynomial.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/GF2Polynomial.java
new file mode 100644
index 0000000..181e0a9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/GF2Polynomial.java
@@ -0,0 +1,43 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.field;
+
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+class GF2Polynomial implements Polynomial
+{
+    protected final int[] exponents;
+
+    GF2Polynomial(int[] exponents)
+    {
+        this.exponents = Arrays.clone(exponents);
+    }
+
+    public int getDegree()
+    {
+        return exponents[exponents.length - 1];
+    }
+
+    public int[] getExponentsPresent()
+    {
+        return Arrays.clone(exponents);
+    }
+
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (!(obj instanceof GF2Polynomial))
+        {
+            return false;
+        }
+        GF2Polynomial other = (GF2Polynomial)obj;
+        return Arrays.areEqual(exponents, other.exponents);
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(exponents);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/GenericPolynomialExtensionField.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/GenericPolynomialExtensionField.java
new file mode 100644
index 0000000..a3523eb
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/GenericPolynomialExtensionField.java
@@ -0,0 +1,63 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.field;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.util.Integers;
+
+class GenericPolynomialExtensionField implements PolynomialExtensionField
+{
+    protected final FiniteField subfield;
+    protected final Polynomial minimalPolynomial;
+
+    GenericPolynomialExtensionField(FiniteField subfield, Polynomial polynomial)
+    {
+        this.subfield = subfield;
+        this.minimalPolynomial = polynomial;
+    }
+
+    public BigInteger getCharacteristic()
+    {
+        return subfield.getCharacteristic();
+    }
+
+    public int getDimension()
+    {
+        return subfield.getDimension() * minimalPolynomial.getDegree();
+    }
+
+    public FiniteField getSubfield()
+    {
+        return subfield;
+    }
+
+    public int getDegree()
+    {
+        return minimalPolynomial.getDegree();
+    }
+
+    public Polynomial getMinimalPolynomial()
+    {
+        return minimalPolynomial;
+    }
+
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (!(obj instanceof GenericPolynomialExtensionField))
+        {
+            return false;
+        }
+        GenericPolynomialExtensionField other = (GenericPolynomialExtensionField)obj;
+        return subfield.equals(other.subfield) && minimalPolynomial.equals(other.minimalPolynomial);
+    }
+
+    public int hashCode()
+    {
+        return subfield.hashCode()
+            ^ Integers.rotateLeft(minimalPolynomial.hashCode(), 16);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/Polynomial.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/Polynomial.java
new file mode 100644
index 0000000..c4d9322
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/Polynomial.java
@@ -0,0 +1,16 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.field;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Polynomial
+{
+    int getDegree();
+
+//    BigInteger[] getCoefficients();
+
+    int[] getExponentsPresent();
+
+//    Term[] getNonZeroTerms();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/PolynomialExtensionField.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/PolynomialExtensionField.java
new file mode 100644
index 0000000..4d08745
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/PolynomialExtensionField.java
@@ -0,0 +1,10 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.field;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface PolynomialExtensionField extends ExtensionField
+{
+    Polynomial getMinimalPolynomial();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/PrimeField.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/PrimeField.java
new file mode 100644
index 0000000..ebfe73f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/field/PrimeField.java
@@ -0,0 +1,43 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.field;
+
+import java.math.BigInteger;
+
+class PrimeField implements FiniteField
+{
+    protected final BigInteger characteristic;
+
+    PrimeField(BigInteger characteristic)
+    {
+        this.characteristic = characteristic;
+    }
+
+    public BigInteger getCharacteristic()
+    {
+        return characteristic;
+    }
+
+    public int getDimension()
+    {
+        return 1;
+    }
+
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (!(obj instanceof PrimeField))
+        {
+            return false;
+        }
+        PrimeField other = (PrimeField)obj;
+        return characteristic.equals(other.characteristic);
+    }
+
+    public int hashCode()
+    {
+        return characteristic.hashCode();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Interleave.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Interleave.java
new file mode 100644
index 0000000..31e7553
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Interleave.java
@@ -0,0 +1,181 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.raw;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Interleave
+{
+    private static final long M32 = 0x55555555L;
+    private static final long M64 = 0x5555555555555555L;
+    private static final long M64R = 0xAAAAAAAAAAAAAAAAL;
+
+    /*
+     * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
+     * In a binary field, this operation is the same as squaring an 8 bit number.
+     * 
+     * NOTE: All entries are positive so sign-extension is not an issue.
+     */
+//    private static final short[] INTERLEAVE2_TABLE = new short[]
+//    {
+//        0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+//        0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+//        0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+//        0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+//        0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+//        0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+//        0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+//        0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+//        0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+//        0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+//        0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+//        0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+//        0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+//        0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+//        0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+//        0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+//        0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+//        0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+//        0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+//        0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+//        0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+//        0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+//        0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+//        0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+//        0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+//        0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+//        0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+//        0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+//        0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+//        0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+//        0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+//        0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+//    };
+
+    public static int expand8to16(int x)
+    {
+        x &= 0xFF;
+        x  = (x | (x << 4)) & 0x0F0F;
+        x  = (x | (x << 2)) & 0x3333;
+        x  = (x | (x << 1)) & 0x5555;
+        return x;
+    }
+
+    public static int expand16to32(int x)
+    {
+        x &= 0xFFFF;
+        x  = (x | (x << 8)) & 0x00FF00FF;
+        x  = (x | (x << 4)) & 0x0F0F0F0F;
+        x  = (x | (x << 2)) & 0x33333333;
+        x  = (x | (x << 1)) & 0x55555555;
+        return x;
+    }
+
+    public static long expand32to64(int x)
+    {
+        // "shuffle" low half to even bits and high half to odd bits
+        int t;
+        t = (x ^ (x >>>  8)) & 0x0000FF00; x ^= (t ^ (t <<  8));
+        t = (x ^ (x >>>  4)) & 0x00F000F0; x ^= (t ^ (t <<  4));
+        t = (x ^ (x >>>  2)) & 0x0C0C0C0C; x ^= (t ^ (t <<  2));
+        t = (x ^ (x >>>  1)) & 0x22222222; x ^= (t ^ (t <<  1));
+
+        return ((x >>> 1) & M32) << 32 | (x & M32);
+    }
+
+    public static void expand64To128(long x, long[] z, int zOff)
+    {
+        // "shuffle" low half to even bits and high half to odd bits
+        long t;
+        t = (x ^ (x >>> 16)) & 0x00000000FFFF0000L; x ^= (t ^ (t << 16));
+        t = (x ^ (x >>>  8)) & 0x0000FF000000FF00L; x ^= (t ^ (t <<  8));
+        t = (x ^ (x >>>  4)) & 0x00F000F000F000F0L; x ^= (t ^ (t <<  4));
+        t = (x ^ (x >>>  2)) & 0x0C0C0C0C0C0C0C0CL; x ^= (t ^ (t <<  2));
+        t = (x ^ (x >>>  1)) & 0x2222222222222222L; x ^= (t ^ (t <<  1));
+
+        z[zOff    ] = (x      ) & M64;
+        z[zOff + 1] = (x >>> 1) & M64;
+    }
+
+    public static void expand64To128Rev(long x, long[] z, int zOff)
+    {
+        // "shuffle" low half to even bits and high half to odd bits
+        long t;
+        t = (x ^ (x >>> 16)) & 0x00000000FFFF0000L; x ^= (t ^ (t << 16));
+        t = (x ^ (x >>>  8)) & 0x0000FF000000FF00L; x ^= (t ^ (t <<  8));
+        t = (x ^ (x >>>  4)) & 0x00F000F000F000F0L; x ^= (t ^ (t <<  4));
+        t = (x ^ (x >>>  2)) & 0x0C0C0C0C0C0C0C0CL; x ^= (t ^ (t <<  2));
+        t = (x ^ (x >>>  1)) & 0x2222222222222222L; x ^= (t ^ (t <<  1));
+
+        z[zOff    ] = (x     ) & M64R;
+        z[zOff + 1] = (x << 1) & M64R;
+    }
+
+    public static int shuffle(int x)
+    {
+        // "shuffle" low half to even bits and high half to odd bits
+        int t;
+        t = (x ^ (x >>>  8)) & 0x0000FF00; x ^= (t ^ (t <<  8));
+        t = (x ^ (x >>>  4)) & 0x00F000F0; x ^= (t ^ (t <<  4));
+        t = (x ^ (x >>>  2)) & 0x0C0C0C0C; x ^= (t ^ (t <<  2));
+        t = (x ^ (x >>>  1)) & 0x22222222; x ^= (t ^ (t <<  1));
+        return x;
+    }
+
+    public static long shuffle(long x)
+    {
+        // "shuffle" low half to even bits and high half to odd bits
+        long t;
+        t = (x ^ (x >>> 16)) & 0x00000000FFFF0000L; x ^= (t ^ (t << 16));
+        t = (x ^ (x >>>  8)) & 0x0000FF000000FF00L; x ^= (t ^ (t <<  8));
+        t = (x ^ (x >>>  4)) & 0x00F000F000F000F0L; x ^= (t ^ (t <<  4));
+        t = (x ^ (x >>>  2)) & 0x0C0C0C0C0C0C0C0CL; x ^= (t ^ (t <<  2));
+        t = (x ^ (x >>>  1)) & 0x2222222222222222L; x ^= (t ^ (t <<  1));
+        return x;
+    }
+
+    public static int shuffle2(int x)
+    {
+        // "shuffle" (twice) low half to even bits and high half to odd bits
+        int t;
+        t = (x ^ (x >>>  7)) & 0x00AA00AA; x ^= (t ^ (t <<  7));
+        t = (x ^ (x >>> 14)) & 0x0000CCCC; x ^= (t ^ (t << 14));
+        t = (x ^ (x >>>  4)) & 0x00F000F0; x ^= (t ^ (t <<  4));
+        t = (x ^ (x >>>  8)) & 0x0000FF00; x ^= (t ^ (t <<  8));
+        return x;
+    }
+
+    public static int unshuffle(int x)
+    {
+        // "unshuffle" even bits to low half and odd bits to high half
+        int t;
+        t = (x ^ (x >>>  1)) & 0x22222222; x ^= (t ^ (t <<  1));
+        t = (x ^ (x >>>  2)) & 0x0C0C0C0C; x ^= (t ^ (t <<  2));
+        t = (x ^ (x >>>  4)) & 0x00F000F0; x ^= (t ^ (t <<  4));
+        t = (x ^ (x >>>  8)) & 0x0000FF00; x ^= (t ^ (t <<  8));
+        return x;
+    }
+
+    public static long unshuffle(long x)
+    {
+        // "unshuffle" even bits to low half and odd bits to high half
+        long t;
+        t = (x ^ (x >>>  1)) & 0x2222222222222222L; x ^= (t ^ (t <<  1));
+        t = (x ^ (x >>>  2)) & 0x0C0C0C0C0C0C0C0CL; x ^= (t ^ (t <<  2));
+        t = (x ^ (x >>>  4)) & 0x00F000F000F000F0L; x ^= (t ^ (t <<  4));
+        t = (x ^ (x >>>  8)) & 0x0000FF000000FF00L; x ^= (t ^ (t <<  8));
+        t = (x ^ (x >>> 16)) & 0x00000000FFFF0000L; x ^= (t ^ (t << 16));
+        return x;
+    }
+
+    public static int unshuffle2(int x)
+    {
+        // "unshuffle" (twice) even bits to low half and odd bits to high half
+        int t;
+        t = (x ^ (x >>>  8)) & 0x0000FF00; x ^= (t ^ (t <<  8));
+        t = (x ^ (x >>>  4)) & 0x00F000F0; x ^= (t ^ (t <<  4));
+        t = (x ^ (x >>> 14)) & 0x0000CCCC; x ^= (t ^ (t << 14));
+        t = (x ^ (x >>>  7)) & 0x00AA00AA; x ^= (t ^ (t <<  7));
+        return x;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Mod.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Mod.java
new file mode 100644
index 0000000..dd821ff
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Mod.java
@@ -0,0 +1,203 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.raw;
+
+import java.util.Random;
+
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class Mod
+{
+    public static int inverse32(int d)
+    {
+//        int x = d + (((d + 1) & 4) << 1);   // d.x == 1 mod 2**4
+        int x = d;                          // d.x == 1 mod 2**3
+        x *= 2 - d * x;                     // d.x == 1 mod 2**6
+        x *= 2 - d * x;                     // d.x == 1 mod 2**12
+        x *= 2 - d * x;                     // d.x == 1 mod 2**24
+        x *= 2 - d * x;                     // d.x == 1 mod 2**48
+//        assert d * x == 1;
+        return  x;
+    }
+
+    public static void invert(int[] p, int[] x, int[] z)
+    {
+        int len = p.length;
+        if (Nat.isZero(len, x))
+        {
+            throw new IllegalArgumentException("'x' cannot be 0");
+        }
+        if (Nat.isOne(len, x))
+        {
+            System.arraycopy(x, 0, z, 0, len);
+            return;
+        }
+
+        int[] u = Nat.copy(len, x);
+        int[] a = Nat.create(len);
+        a[0] = 1;
+        int ac = 0;
+
+        if ((u[0] & 1) == 0)
+        {
+            ac = inversionStep(p, u, len, a, ac);
+        }
+        if (Nat.isOne(len, u))
+        {
+            inversionResult(p, ac, a, z);
+            return;
+        }
+
+        int[] v = Nat.copy(len, p);
+        int[] b = Nat.create(len);
+        int bc = 0;
+
+        int uvLen = len;
+
+        for (;;)
+        {
+            while (u[uvLen - 1] == 0 && v[uvLen - 1] == 0)
+            {
+                --uvLen;
+            }
+
+            if (Nat.gte(uvLen, u, v))
+            {
+                Nat.subFrom(uvLen, v, u);
+//              assert (u[0] & 1) == 0;
+                ac += Nat.subFrom(len, b, a) - bc;
+                ac = inversionStep(p, u, uvLen, a, ac);
+                if (Nat.isOne(uvLen, u))
+                {
+                    inversionResult(p, ac, a, z);
+                    return;
+                }
+            }
+            else
+            {
+                Nat.subFrom(uvLen, u, v);
+//              assert (v[0] & 1) == 0;
+                bc += Nat.subFrom(len, a, b) - ac;
+                bc = inversionStep(p, v, uvLen, b, bc);
+                if (Nat.isOne(uvLen, v))
+                {
+                    inversionResult(p, bc, b, z);
+                    return;
+                }
+            }
+        }
+    }
+
+    public static int[] random(int[] p)
+    {
+        int len = p.length;
+        Random rand = new Random();
+        int[] s = Nat.create(len);
+
+        int m = p[len - 1];
+        m |= m >>> 1;
+        m |= m >>> 2;
+        m |= m >>> 4;
+        m |= m >>> 8;
+        m |= m >>> 16;
+
+        do
+        {
+            for (int i = 0; i != len; i++)
+            {
+                s[i] = rand.nextInt();
+            }
+            s[len - 1] &= m;
+        }
+        while (Nat.gte(len, s, p));
+
+        return s;
+    }
+
+    public static void add(int[] p, int[] x, int[] y, int[] z)
+    {
+        int len = p.length;
+        int c = Nat.add(len, x, y, z);
+        if (c != 0)
+        {
+            Nat.subFrom(len, p, z);
+        }
+    }
+
+    public static void subtract(int[] p, int[] x, int[] y, int[] z)
+    {
+        int len = p.length;
+        int c = Nat.sub(len, x, y, z);
+        if (c != 0)
+        {
+            Nat.addTo(len, p, z);
+        }
+    }
+
+    private static void inversionResult(int[] p, int ac, int[] a, int[] z)
+    {
+        if (ac < 0)
+        {
+            Nat.add(p.length, a, p, z);
+        }
+        else
+        {
+            System.arraycopy(a, 0, z, 0, p.length);
+        }
+    }
+
+    private static int inversionStep(int[] p, int[] u, int uLen, int[] x, int xc)
+    {
+        int len = p.length;
+        int count = 0;
+        while (u[0] == 0)
+        {
+            Nat.shiftDownWord(uLen, u, 0);
+            count += 32;
+        }
+
+        {
+            int zeroes = getTrailingZeroes(u[0]);
+            if (zeroes > 0)
+            {
+                Nat.shiftDownBits(uLen, u, zeroes, 0);
+                count += zeroes;
+            }
+        }
+
+        for (int i = 0; i < count; ++i)
+        {
+            if ((x[0] & 1) != 0)
+            {
+                if (xc < 0)
+                {
+                    xc += Nat.addTo(len, p, x);
+                }
+                else
+                {
+                    xc += Nat.subFrom(len, p, x);
+                }
+            }
+
+//            assert xc == 0 || xc == 1;
+            Nat.shiftDownBit(len, x, xc);
+        }
+        
+        return xc;
+    }
+
+    private static int getTrailingZeroes(int x)
+    {
+//        assert x != 0;
+
+        int count = 0;
+        while ((x & 1) == 0)
+        {
+            x >>>= 1;
+            ++count;
+        }
+        return count;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat.java
new file mode 100644
index 0000000..ed2d05e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat.java
@@ -0,0 +1,1153 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.raw;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class Nat
+{
+    private static final long M = 0xFFFFFFFFL;
+
+    public static int add(int len, int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (x[i] & M) + (y[i] & M);
+            z[i] = (int)c;
+            c >>>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int add33At(int len, int x, int[] z, int zPos)
+    {
+        // assert zPos <= (len - 2);
+        long c = (z[zPos + 0] & M) + (x & M);
+        z[zPos + 0] = (int)c;
+        c >>>= 32;
+        c += (z[zPos + 1] & M) + 1L;
+        z[zPos + 1] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, zPos + 2);
+    }
+
+    public static int add33At(int len, int x, int[] z, int zOff, int zPos)
+    {
+        // assert zPos <= (len - 2);
+        long c = (z[zOff + zPos] & M) + (x & M);
+        z[zOff + zPos] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + zPos + 1] & M) + 1L;
+        z[zOff + zPos + 1] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, zOff, zPos + 2);
+    }
+
+    public static int add33To(int len, int x, int[] z)
+    {
+        long c = (z[0] & M) + (x & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += (z[1] & M) + 1L;
+        z[1] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, 2);
+    }
+
+    public static int add33To(int len, int x, int[] z, int zOff)
+    {
+        long c = (z[zOff + 0] & M) + (x & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + 1] & M) + 1L;
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, zOff, 2);
+    }
+
+    public static int addBothTo(int len, int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (x[i] & M) + (y[i] & M) + (z[i] & M);
+            z[i] = (int)c;
+            c >>>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int addBothTo(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (x[xOff + i] & M) + (y[yOff + i] & M) + (z[zOff + i] & M);
+            z[zOff + i] = (int)c;
+            c >>>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int addDWordAt(int len, long x, int[] z, int zPos)
+    {
+        // assert zPos <= (len - 2);
+        long c = (z[zPos + 0] & M) + (x & M);
+        z[zPos + 0] = (int)c;
+        c >>>= 32;
+        c += (z[zPos + 1] & M) + (x >>> 32);
+        z[zPos + 1] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, zPos + 2);
+    }
+
+    public static int addDWordAt(int len, long x, int[] z, int zOff, int zPos)
+    {
+        // assert zPos <= (len - 2);
+        long c = (z[zOff + zPos] & M) + (x & M);
+        z[zOff + zPos] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + zPos + 1] & M) + (x >>> 32);
+        z[zOff + zPos + 1] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, zOff, zPos + 2);
+    }
+
+    public static int addDWordTo(int len, long x, int[] z)
+    {
+        long c = (z[0] & M) + (x & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += (z[1] & M) + (x >>> 32);
+        z[1] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, 2);
+    }
+
+    public static int addDWordTo(int len, long x, int[] z, int zOff)
+    {
+        long c = (z[zOff + 0] & M) + (x & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + 1] & M) + (x >>> 32);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, zOff, 2);
+    }
+
+    public static int addTo(int len, int[] x, int[] z)
+    {
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (x[i] & M) + (z[i] & M);
+            z[i] = (int)c;
+            c >>>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int addTo(int len, int[] x, int xOff, int[] z, int zOff)
+    {
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (x[xOff + i] & M) + (z[zOff + i] & M);
+            z[zOff + i] = (int)c;
+            c >>>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int addWordAt(int len, int x, int[] z, int zPos)
+    {
+        // assert zPos <= (len - 1);
+        long c = (x & M) + (z[zPos] & M);
+        z[zPos] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, zPos + 1);
+    }
+
+    public static int addWordAt(int len, int x, int[] z, int zOff, int zPos)
+    {
+        // assert zPos <= (len - 1);
+        long c = (x & M) + (z[zOff + zPos] & M);
+        z[zOff + zPos] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, zOff, zPos + 1);
+    }
+
+    public static int addWordTo(int len, int x, int[] z)
+    {
+        long c = (x & M) + (z[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, 1);
+    }
+
+    public static int addWordTo(int len, int x, int[] z, int zOff)
+    {
+        long c = (x & M) + (z[zOff] & M);
+        z[zOff] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, zOff, 1);
+    }
+
+    public static int cadd(int len, int mask, int[] x, int[] y, int[] z)
+    {
+        long MASK = -(mask & 1) & M;
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (x[i] & M) + (y[i] & MASK);
+            z[i] = (int)c;
+            c >>>= 32;
+        }
+        return (int)c;
+    }
+
+    public static void cmov(int len, int mask, int[] x, int xOff, int[] z, int zOff)
+    {
+        mask = -(mask & 1);
+
+        for (int i = 0; i < len; ++i)
+        {
+            int z_i = z[zOff + i], diff = z_i ^ x[xOff + i];
+            z_i ^= (diff & mask);
+            z[zOff + i] = z_i;
+        }
+
+//        final int half = 0x55555555, rest = half << (-mask);
+//
+//        for (int i = 0; i < len; ++i)
+//        {
+//            int z_i = z[zOff + i], diff = z_i ^ x[xOff + i];
+//            z_i ^= (diff & half);
+//            z_i ^= (diff & rest);
+//            z[zOff + i] = z_i;
+//        }
+    }
+
+    public static int[] copy(int len, int[] x)
+    {
+        int[] z = new int[len];
+        System.arraycopy(x, 0, z, 0, len);
+        return z;
+    }
+
+    public static void copy(int len, int[] x, int[] z)
+    {
+        System.arraycopy(x, 0, z, 0, len);
+    }
+
+    public static void copy(int len, int[] x, int xOff, int[] z, int zOff)
+    {
+        System.arraycopy(x, xOff, z, zOff, len);
+    }
+
+    public static int[] create(int len)
+    {
+        return new int[len];
+    }
+
+    public static long[] create64(int len)
+    {
+        return new long[len];
+    }
+
+    public static int csub(int len, int mask, int[] x, int[] y, int[] z)
+    {
+        long MASK = -(mask & 1) & M;
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (x[i] & M) - (y[i] & MASK);
+            z[i] = (int)c;
+            c >>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int dec(int len, int[] z)
+    {
+        for (int i = 0; i < len; ++i)
+        {
+            if (--z[i] != -1)
+            {
+                return 0;
+            }
+        }
+        return -1;
+    }
+
+    public static int dec(int len, int[] x, int[] z)
+    {
+        int i = 0;
+        while (i < len)
+        {
+            int c = x[i] - 1;
+            z[i] = c;
+            ++i;
+            if (c != -1)
+            {
+                while (i < len)
+                {
+                    z[i] = x[i];
+                    ++i;
+                }
+                return 0;
+            }
+        }
+        return -1;
+    }
+
+    public static int decAt(int len, int[] z, int zPos)
+    {
+        // assert zPos <= len;
+        for (int i = zPos; i < len; ++i)
+        {
+            if (--z[i] != -1)
+            {
+                return 0;
+            }
+        }
+        return -1;
+    }
+
+    public static int decAt(int len, int[] z, int zOff, int zPos)
+    {
+        // assert zPos <= len;
+        for (int i = zPos; i < len; ++i)
+        {
+            if (--z[zOff + i] != -1)
+            {
+                return 0;
+            }
+        }
+        return -1;
+    }
+
+    public static boolean eq(int len, int[] x, int[] y)
+    {
+        for (int i = len - 1; i >= 0; --i)
+        {
+            if (x[i] != y[i])
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static int[] fromBigInteger(int bits, BigInteger x)
+    {
+        if (x.signum() < 0 || x.bitLength() > bits)
+        {
+            throw new IllegalArgumentException();
+        }
+
+        int len = (bits + 31) >> 5;
+        int[] z = create(len);
+        int i = 0;
+        while (x.signum() != 0)
+        {
+            z[i++] = x.intValue();
+            x = x.shiftRight(32);
+        }
+        return z;
+    }
+
+    public static int getBit(int[] x, int bit)
+    {
+        if (bit == 0)
+        {
+            return x[0] & 1;
+        }
+        int w = bit >> 5;
+        if (w < 0 || w >= x.length)
+        {
+            return 0;
+        }
+        int b = bit & 31;
+        return (x[w] >>> b) & 1;
+    }
+
+    public static boolean gte(int len, int[] x, int[] y)
+    {
+        for (int i = len - 1; i >= 0; --i)
+        {
+            int x_i = x[i] ^ Integer.MIN_VALUE;
+            int y_i = y[i] ^ Integer.MIN_VALUE;
+            if (x_i < y_i)
+                return false;
+            if (x_i > y_i)
+                return true;
+        }
+        return true;
+    }
+
+    public static int inc(int len, int[] z)
+    {
+        for (int i = 0; i < len; ++i)
+        {
+            if (++z[i] != 0)
+            {
+                return 0;
+            }
+        }
+        return 1;
+    }
+
+    public static int inc(int len, int[] x, int[] z)
+    {
+        int i = 0;
+        while (i < len)
+        {
+            int c = x[i] + 1;
+            z[i] = c;
+            ++i;
+            if (c != 0)
+            {
+                while (i < len)
+                {
+                    z[i] = x[i];
+                    ++i;
+                }
+                return 0;
+            }
+        }
+        return 1;
+    }
+
+    public static int incAt(int len, int[] z, int zPos)
+    {
+        // assert zPos <= len;
+        for (int i = zPos; i < len; ++i)
+        {
+            if (++z[i] != 0)
+            {
+                return 0;
+            }
+        }
+        return 1;
+    }
+
+    public static int incAt(int len, int[] z, int zOff, int zPos)
+    {
+        // assert zPos <= len;
+        for (int i = zPos; i < len; ++i)
+        {
+            if (++z[zOff + i] != 0)
+            {
+                return 0;
+            }
+        }
+        return 1;
+    }
+
+    public static boolean isOne(int len, int[] x)
+    {
+        if (x[0] != 1)
+        {
+            return false;
+        }
+        for (int i = 1; i < len; ++i)
+        {
+            if (x[i] != 0)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isZero(int len, int[] x)
+    {
+        for (int i = 0; i < len; ++i)
+        {
+            if (x[i] != 0)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static void mul(int len, int[] x, int[] y, int[] zz)
+    {
+        zz[len] = mulWord(len, x[0], y, zz);
+
+        for (int i = 1; i < len; ++i)
+        {
+            zz[i + len] = mulWordAddTo(len, x[i], y, 0, zz, i);
+        }
+    }
+
+    public static void mul(int len, int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+    {
+        zz[zzOff + len] = mulWord(len, x[xOff], y, yOff, zz, zzOff);
+
+        for (int i = 1; i < len; ++i)
+        {
+            zz[zzOff + i + len] = mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff + i);
+        }
+    }
+
+    public static void mul(int[] x, int xOff, int xLen, int[] y, int yOff, int yLen, int[] zz, int zzOff)
+    {
+        zz[zzOff + yLen] = mulWord(yLen, x[xOff], y, yOff, zz, zzOff);
+
+        for (int i = 1; i < xLen; ++i)
+        {
+            zz[zzOff + i + yLen] = mulWordAddTo(yLen, x[xOff + i], y, yOff, zz, zzOff + i);
+        }
+    }
+
+    public static int mulAddTo(int len, int[] x, int[] y, int[] zz)
+    {
+        long zc = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            long c = mulWordAddTo(len, x[i], y, 0, zz, i) & M;
+            c += zc + (zz[i + len] & M);
+            zz[i + len] = (int)c;
+            zc = c >>> 32;
+        }
+        return (int)zc;
+    }
+
+    public static int mulAddTo(int len, int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+    {
+        long zc = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            long c = mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff) & M;
+            c += zc + (zz[zzOff + len] & M);
+            zz[zzOff + len] = (int)c;
+            zc = c >>> 32;
+            ++zzOff;
+        }
+        return (int)zc;
+    }
+
+    public static int mul31BothAdd(int len, int a, int[] x, int b, int[] y, int[] z, int zOff)
+    {
+        long c = 0, aVal = a & M, bVal = b & M;
+        int i = 0;
+        do
+        {
+            c += aVal * (x[i] & M) + bVal * (y[i] & M) + (z[zOff + i] & M);
+            z[zOff + i] = (int)c;
+            c >>>= 32;
+        }
+        while (++i < len);
+        return (int)c;
+    }
+
+    public static int mulWord(int len, int x, int[] y, int[] z)
+    {
+        long c = 0, xVal = x & M;
+        int i = 0;
+        do
+        {
+            c += xVal * (y[i] & M);
+            z[i] = (int)c;
+            c >>>= 32;
+        }
+        while (++i < len);
+        return (int)c;
+    }
+
+    public static int mulWord(int len, int x, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0, xVal = x & M;
+        int i = 0;
+        do
+        {
+            c += xVal * (y[yOff + i] & M);
+            z[zOff + i] = (int)c;
+            c >>>= 32;
+        }
+        while (++i < len);
+        return (int)c;
+    }
+
+    public static int mulWordAddTo(int len, int x, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0, xVal = x & M;
+        int i = 0;
+        do
+        {
+            c += xVal * (y[yOff + i] & M) + (z[zOff + i] & M);
+            z[zOff + i] = (int)c;
+            c >>>= 32;
+        }
+        while (++i < len);
+        return (int)c;
+    }
+
+    public static int mulWordDwordAddAt(int len, int x, long y, int[] z, int zPos)
+    {
+        // assert zPos <= (len - 3);
+        long c = 0, xVal = x & M;
+        c += xVal * (y & M) + (z[zPos + 0] & M);
+        z[zPos + 0] = (int)c;
+        c >>>= 32;
+        c += xVal * (y >>> 32) + (z[zPos + 1] & M);
+        z[zPos + 1] = (int)c;
+        c >>>= 32;
+        c += (z[zPos + 2] & M);
+        z[zPos + 2] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : incAt(len, z, zPos + 3);
+    }
+
+    public static int shiftDownBit(int len, int[] z, int c)
+    {
+        int i = len;
+        while (--i >= 0)
+        {
+            int next = z[i];
+            z[i] = (next >>> 1) | (c << 31);
+            c = next;
+        }
+        return c << 31;
+    }
+
+    public static int shiftDownBit(int len, int[] z, int zOff, int c)
+    {
+        int i = len;
+        while (--i >= 0)
+        {
+            int next = z[zOff + i];
+            z[zOff + i] = (next >>> 1) | (c << 31);
+            c = next;
+        }
+        return c << 31;
+    }
+
+    public static int shiftDownBit(int len, int[] x, int c, int[] z)
+    {
+        int i = len;
+        while (--i >= 0)
+        {
+            int next = x[i];
+            z[i] = (next >>> 1) | (c << 31);
+            c = next;
+        }
+        return c << 31;
+    }
+
+    public static int shiftDownBit(int len, int[] x, int xOff, int c, int[] z, int zOff)
+    {
+        int i = len;
+        while (--i >= 0)
+        {
+            int next = x[xOff + i];
+            z[zOff + i] = (next >>> 1) | (c << 31);
+            c = next;
+        }
+        return c << 31;
+    }
+
+    public static int shiftDownBits(int len, int[] z, int bits, int c)
+    {
+//        assert bits > 0 && bits < 32;
+        int i = len;
+        while (--i >= 0)
+        {
+            int next = z[i];
+            z[i] = (next >>> bits) | (c << -bits);
+            c = next;
+        }
+        return c << -bits;
+    }
+
+    public static int shiftDownBits(int len, int[] z, int zOff, int bits, int c)
+    {
+//        assert bits > 0 && bits < 32;
+        int i = len;
+        while (--i >= 0)
+        {
+            int next = z[zOff + i];
+            z[zOff + i] = (next >>> bits) | (c << -bits);
+            c = next;
+        }
+        return c << -bits;
+    }
+
+    public static int shiftDownBits(int len, int[] x, int bits, int c, int[] z)
+    {
+//        assert bits > 0 && bits < 32;
+        int i = len;
+        while (--i >= 0)
+        {
+            int next = x[i];
+            z[i] = (next >>> bits) | (c << -bits);
+            c = next;
+        }
+        return c << -bits;
+    }
+
+    public static int shiftDownBits(int len, int[] x, int xOff, int bits, int c, int[] z, int zOff)
+    {
+//        assert bits > 0 && bits < 32;
+        int i = len;
+        while (--i >= 0)
+        {
+            int next = x[xOff + i];
+            z[zOff + i] = (next >>> bits) | (c << -bits);
+            c = next;
+        }
+        return c << -bits;
+    }
+
+    public static int shiftDownWord(int len, int[] z, int c)
+    {
+        int i = len;
+        while (--i >= 0)
+        {
+            int next = z[i];
+            z[i] = c;
+            c = next;
+        }
+        return c;
+    }
+
+    public static int shiftUpBit(int len, int[] z, int c)
+    {
+        for (int i = 0; i < len; ++i)
+        {
+            int next = z[i];
+            z[i] = (next << 1) | (c >>> 31);
+            c = next;
+        }
+        return c >>> 31;
+    }
+
+    public static int shiftUpBit(int len, int[] z, int zOff, int c)
+    {
+        for (int i = 0; i < len; ++i)
+        {
+            int next = z[zOff + i];
+            z[zOff + i] = (next << 1) | (c >>> 31);
+            c = next;
+        }
+        return c >>> 31;
+    }
+
+    public static int shiftUpBit(int len, int[] x, int c, int[] z)
+    {
+        for (int i = 0; i < len; ++i)
+        {
+            int next = x[i];
+            z[i] = (next << 1) | (c >>> 31);
+            c = next;
+        }
+        return c >>> 31;
+    }
+
+    public static int shiftUpBit(int len, int[] x, int xOff, int c, int[] z, int zOff)
+    {
+        for (int i = 0; i < len; ++i)
+        {
+            int next = x[xOff + i];
+            z[zOff + i] = (next << 1) | (c >>> 31);
+            c = next;
+        }
+        return c >>> 31;
+    }
+
+    public static long shiftUpBit64(int len, long[] x, int xOff, long c, long[] z, int zOff)
+    {
+        for (int i = 0; i < len; ++i)
+        {
+            long next = x[xOff + i];
+            z[zOff + i] = (next << 1) | (c >>> 63);
+            c = next;
+        }
+        return c >>> 63;
+    }
+
+    public static int shiftUpBits(int len, int[] z, int bits, int c)
+    {
+//        assert bits > 0 && bits < 32;
+        for (int i = 0; i < len; ++i)
+        {
+            int next = z[i];
+            z[i] = (next << bits) | (c >>> -bits);
+            c = next;
+        }
+        return c >>> -bits;
+    }
+
+    public static int shiftUpBits(int len, int[] z, int zOff, int bits, int c)
+    {
+//        assert bits > 0 && bits < 32;
+        for (int i = 0; i < len; ++i)
+        {
+            int next = z[zOff + i];
+            z[zOff + i] = (next << bits) | (c >>> -bits);
+            c = next;
+        }
+        return c >>> -bits;
+    }
+
+    public static long shiftUpBits64(int len, long[] z, int zOff, int bits, long c)
+    {
+//        assert bits > 0 && bits < 64;
+        for (int i = 0; i < len; ++i)
+        {
+            long next = z[zOff + i];
+            z[zOff + i] = (next << bits) | (c >>> -bits);
+            c = next;
+        }
+        return c >>> -bits;
+    }
+
+    public static int shiftUpBits(int len, int[] x, int bits, int c, int[] z)
+    {
+//        assert bits > 0 && bits < 32;
+        for (int i = 0; i < len; ++i)
+        {
+            int next = x[i];
+            z[i] = (next << bits) | (c >>> -bits);
+            c = next;
+        }
+        return c >>> -bits;
+    }
+
+    public static int shiftUpBits(int len, int[] x, int xOff, int bits, int c, int[] z, int zOff)
+    {
+//        assert bits > 0 && bits < 32;
+        for (int i = 0; i < len; ++i)
+        {
+            int next = x[xOff + i];
+            z[zOff + i] = (next << bits) | (c >>> -bits);
+            c = next;
+        }
+        return c >>> -bits;
+    }
+
+    public static long shiftUpBits64(int len, long[] x, int xOff, int bits, long c, long[] z, int zOff)
+    {
+//        assert bits > 0 && bits < 64;
+        for (int i = 0; i < len; ++i)
+        {
+            long next = x[xOff + i];
+            z[zOff + i] = (next << bits) | (c >>> -bits);
+            c = next;
+        }
+        return c >>> -bits;
+    }
+
+    public static void square(int len, int[] x, int[] zz)
+    {
+        int extLen = len << 1;
+        int c = 0;
+        int j = len, k = extLen;
+        do
+        {
+            long xVal = (x[--j] & M);
+            long p = xVal * xVal;
+            zz[--k] = (c << 31) | (int)(p >>> 33);
+            zz[--k] = (int)(p >>> 1);
+            c = (int)p;
+        }
+        while (j > 0);
+
+        for (int i = 1; i < len; ++i)
+        {
+            c = squareWordAdd(x, i, zz);
+            addWordAt(extLen, c, zz, i << 1);
+        }
+
+        shiftUpBit(extLen, zz, x[0] << 31);
+    }
+
+    public static void square(int len, int[] x, int xOff, int[] zz, int zzOff)
+    {
+        int extLen = len << 1;
+        int c = 0;
+        int j = len, k = extLen;
+        do
+        {
+            long xVal = (x[xOff + --j] & M);
+            long p = xVal * xVal;
+            zz[zzOff + --k] = (c << 31) | (int)(p >>> 33);
+            zz[zzOff + --k] = (int)(p >>> 1);
+            c = (int)p;
+        }
+        while (j > 0);
+
+        for (int i = 1; i < len; ++i)
+        {
+            c = squareWordAdd(x, xOff, i, zz, zzOff);
+            addWordAt(extLen, c, zz, zzOff, i << 1);
+        }
+
+        shiftUpBit(extLen, zz, zzOff, x[xOff] << 31);
+    }
+
+    public static int squareWordAdd(int[] x, int xPos, int[] z)
+    {
+        long c = 0, xVal = x[xPos] & M;
+        int i = 0;
+        do
+        {
+            c += xVal * (x[i] & M) + (z[xPos + i] & M);
+            z[xPos + i] = (int)c;
+            c >>>= 32;
+        }
+        while (++i < xPos);
+        return (int)c;
+    }
+
+    public static int squareWordAdd(int[] x, int xOff, int xPos, int[] z, int zOff)
+    {
+        long c = 0, xVal = x[xOff + xPos] & M;
+        int i = 0;
+        do
+        {
+            c += xVal * (x[xOff + i] & M) + (z[xPos + zOff] & M);
+            z[xPos + zOff] = (int)c;
+            c >>>= 32;
+            ++zOff;
+        }
+        while (++i < xPos);
+        return (int)c;
+    }
+
+    public static int sub(int len, int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (x[i] & M) - (y[i] & M);
+            z[i] = (int)c;
+            c >>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int sub(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (x[xOff + i] & M) - (y[yOff + i] & M);
+            z[zOff + i] = (int)c;
+            c >>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int sub33At(int len, int x, int[] z, int zPos)
+    {
+        // assert zPos <= (len - 2);
+        long c = (z[zPos + 0] & M) - (x & M);
+        z[zPos + 0] = (int)c;
+        c >>= 32;
+        c += (z[zPos + 1] & M) - 1;
+        z[zPos + 1] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z, zPos + 2);
+    }
+
+    public static int sub33At(int len, int x, int[] z, int zOff, int zPos)
+    {
+        // assert zPos <= (len - 2);
+        long c = (z[zOff + zPos] & M) - (x & M);
+        z[zOff + zPos] = (int)c;
+        c >>= 32;
+        c += (z[zOff + zPos + 1] & M) - 1;
+        z[zOff + zPos + 1] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z, zOff, zPos + 2);
+    }
+
+    public static int sub33From(int len, int x, int[] z)
+    {
+        long c = (z[0] & M) - (x & M);
+        z[0] = (int)c;
+        c >>= 32;
+        c += (z[1] & M) - 1;
+        z[1] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z, 2);
+    }
+
+    public static int sub33From(int len, int x, int[] z, int zOff)
+    {
+        long c = (z[zOff + 0] & M) - (x & M);
+        z[zOff + 0] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 1] & M) - 1;
+        z[zOff + 1] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z, zOff, 2);
+    }
+
+    public static int subBothFrom(int len, int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (z[i] & M) - (x[i] & M) - (y[i] & M);
+            z[i] = (int)c;
+            c >>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int subBothFrom(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (z[zOff + i] & M) - (x[xOff + i] & M) - (y[yOff + i] & M);
+            z[zOff + i] = (int)c;
+            c >>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int subDWordAt(int len, long x, int[] z, int zPos)
+    {
+        // assert zPos <= (len - 2);
+        long c = (z[zPos + 0] & M) - (x & M);
+        z[zPos + 0] = (int)c;
+        c >>= 32;
+        c += (z[zPos + 1] & M) - (x >>> 32);
+        z[zPos + 1] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z, zPos + 2);
+    }
+
+    public static int subDWordAt(int len, long x, int[] z, int zOff, int zPos)
+    {
+        // assert zPos <= (len - 2);
+        long c = (z[zOff + zPos] & M) - (x & M);
+        z[zOff + zPos] = (int)c;
+        c >>= 32;
+        c += (z[zOff + zPos + 1] & M) - (x >>> 32);
+        z[zOff + zPos + 1] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z,  zOff, zPos + 2);
+    }
+
+    public static int subDWordFrom(int len, long x, int[] z)
+    {
+        long c = (z[0] & M) - (x & M);
+        z[0] = (int)c;
+        c >>= 32;
+        c += (z[1] & M) - (x >>> 32);
+        z[1] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z, 2);
+    }
+
+    public static int subDWordFrom(int len, long x, int[] z, int zOff)
+    {
+        long c = (z[zOff + 0] & M) - (x & M);
+        z[zOff + 0] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 1] & M) - (x >>> 32);
+        z[zOff + 1] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z, zOff, 2);
+    }
+
+    public static int subFrom(int len, int[] x, int[] z)
+    {
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (z[i] & M) - (x[i] & M);
+            z[i] = (int)c;
+            c >>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int subFrom(int len, int[] x, int xOff, int[] z, int zOff)
+    {
+        long c = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            c += (z[zOff + i] & M) - (x[xOff + i] & M);
+            z[zOff + i] = (int)c;
+            c >>= 32;
+        }
+        return (int)c;
+    }
+
+    public static int subWordAt(int len, int x, int[] z, int zPos)
+    {
+        // assert zPos <= (len - 1);
+        long c = (z[zPos] & M) - (x & M);
+        z[zPos] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z, zPos + 1);
+    }
+
+    public static int subWordAt(int len, int x, int[] z, int zOff, int zPos)
+    {
+        // assert zPos <= (len - 1);
+        long c = (z[zOff + zPos] & M) - (x & M);
+        z[zOff + zPos] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z, zOff, zPos + 1);
+    }
+
+    public static int subWordFrom(int len, int x, int[] z)
+    {
+        long c = (z[0] & M) - (x & M);
+        z[0] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z, 1);
+    }
+
+    public static int subWordFrom(int len, int x, int[] z, int zOff)
+    {
+        long c = (z[zOff + 0] & M) - (x & M);
+        z[zOff + 0] = (int)c;
+        c >>= 32;
+        return c == 0 ? 0 : decAt(len, z, zOff, 1);
+    }
+
+    public static BigInteger toBigInteger(int len, int[] x)
+    {
+        byte[] bs = new byte[len << 2];
+        for (int i = 0; i < len; ++i)
+        {
+            int x_i = x[i];
+            if (x_i != 0)
+            {
+                Pack.intToBigEndian(x_i, bs, (len - 1 - i) << 2);
+            }
+        }
+        return new BigInteger(1, bs);
+    }
+
+    public static void zero(int len, int[] z)
+    {
+        for (int i = 0; i < len; ++i)
+        {
+            z[i] = 0;
+        }
+    }
+
+    public static void zero64(int len, long[] z)
+    {
+        for (int i = 0; i < len; ++i)
+        {
+            z[i] = 0L;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat192.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat192.java
new file mode 100644
index 0000000..5ec313e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat192.java
@@ -0,0 +1,1077 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.raw;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class Nat192
+{
+    private static final long M = 0xFFFFFFFFL;
+
+    public static int add(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) + (y[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += (x[1] & M) + (y[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += (x[2] & M) + (y[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += (x[3] & M) + (y[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += (x[4] & M) + (y[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += (x[5] & M) + (y[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addBothTo(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) + (y[0] & M) + (z[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += (x[1] & M) + (y[1] & M) + (z[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += (x[2] & M) + (y[2] & M) + (z[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += (x[3] & M) + (y[3] & M) + (z[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += (x[4] & M) + (y[4] & M) + (z[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += (x[5] & M) + (y[5] & M) + (z[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addTo(int[] x, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) + (z[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += (x[1] & M) + (z[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += (x[2] & M) + (z[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += (x[3] & M) + (z[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += (x[4] & M) + (z[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += (x[5] & M) + (z[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addTo(int[] x, int xOff, int[] z, int zOff, int cIn)
+    {
+        long c = cIn & M;
+        c += (x[xOff + 0] & M) + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 1] & M) + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 2] & M) + (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 3] & M) + (z[zOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 4] & M) + (z[zOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 5] & M) + (z[zOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addToEachOther(int[] u, int uOff, int[] v, int vOff)
+    {
+        long c = 0;
+        c += (u[uOff + 0] & M) + (v[vOff + 0] & M);
+        u[uOff + 0] = (int)c;
+        v[vOff + 0] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 1] & M) + (v[vOff + 1] & M);
+        u[uOff + 1] = (int)c;
+        v[vOff + 1] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 2] & M) + (v[vOff + 2] & M);
+        u[uOff + 2] = (int)c;
+        v[vOff + 2] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 3] & M) + (v[vOff + 3] & M);
+        u[uOff + 3] = (int)c;
+        v[vOff + 3] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 4] & M) + (v[vOff + 4] & M);
+        u[uOff + 4] = (int)c;
+        v[vOff + 4] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 5] & M) + (v[vOff + 5] & M);
+        u[uOff + 5] = (int)c;
+        v[vOff + 5] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static void copy(int[] x, int[] z)
+    {
+        z[0] = x[0];
+        z[1] = x[1];
+        z[2] = x[2];
+        z[3] = x[3];
+        z[4] = x[4];
+        z[5] = x[5];
+    }
+
+    public static void copy(int[] x, int xOff, int[] z, int zOff)
+    {
+        z[zOff + 0] = x[xOff + 0];
+        z[zOff + 1] = x[xOff + 1];
+        z[zOff + 2] = x[xOff + 2];
+        z[zOff + 3] = x[xOff + 3];
+        z[zOff + 4] = x[xOff + 4];
+        z[zOff + 5] = x[xOff + 5];
+    }
+
+    public static void copy64(long[] x, long[] z)
+    {
+        z[0] = x[0];
+        z[1] = x[1];
+        z[2] = x[2];
+    }
+
+    public static void copy64(long[] x, int xOff, long[] z, int zOff)
+    {
+        z[zOff + 0] = x[xOff + 0];
+        z[zOff + 1] = x[xOff + 1];
+        z[zOff + 2] = x[xOff + 2];
+    }
+
+    public static int[] create()
+    {
+        return new int[6];
+    }
+
+    public static long[] create64()
+    {
+        return new long[3];
+    }
+
+    public static int[] createExt()
+    {
+        return new int[12];
+    }
+
+    public static long[] createExt64()
+    {
+        return new long[6];
+    }
+
+    public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        boolean pos = gte(x, xOff, y, yOff);
+        if (pos)
+        {
+            sub(x, xOff, y, yOff, z, zOff);
+        }
+        else
+        {
+            sub(y, yOff, x, xOff, z, zOff);
+        }
+        return pos;
+    }
+
+    public static boolean eq(int[] x, int[] y)
+    {
+        for (int i = 5; i >= 0; --i)
+        {
+            if (x[i] != y[i])
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean eq64(long[] x, long[] y)
+    {
+        for (int i = 2; i >= 0; --i)
+        {
+            if (x[i] != y[i])
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static int[] fromBigInteger(BigInteger x)
+    {
+        if (x.signum() < 0 || x.bitLength() > 192)
+        {
+            throw new IllegalArgumentException();
+        }
+
+        int[] z = create();
+        int i = 0;
+        while (x.signum() != 0)
+        {
+            z[i++] = x.intValue();
+            x = x.shiftRight(32);
+        }
+        return z;
+    }
+
+    public static long[] fromBigInteger64(BigInteger x)
+    {
+        if (x.signum() < 0 || x.bitLength() > 192)
+        {
+            throw new IllegalArgumentException();
+        }
+
+        long[] z = create64();
+        int i = 0;
+        while (x.signum() != 0)
+        {
+            z[i++] = x.longValue();
+            x = x.shiftRight(64);
+        }
+        return z;
+    }
+
+    public static int getBit(int[] x, int bit)
+    {
+        if (bit == 0)
+        {
+            return x[0] & 1;
+        }
+        int w = bit >> 5;
+        if (w < 0 || w >= 6)
+        {
+            return 0;
+        }
+        int b = bit & 31;
+        return (x[w] >>> b) & 1;
+    }
+
+    public static boolean gte(int[] x, int[] y)
+    {
+        for (int i = 5; i >= 0; --i)
+        {
+            int x_i = x[i] ^ Integer.MIN_VALUE;
+            int y_i = y[i] ^ Integer.MIN_VALUE;
+            if (x_i < y_i)
+                return false;
+            if (x_i > y_i)
+                return true;
+        }
+        return true;
+    }
+
+    public static boolean gte(int[] x, int xOff, int[] y, int yOff)
+    {
+        for (int i = 5; i >= 0; --i)
+        {
+            int x_i = x[xOff + i] ^ Integer.MIN_VALUE;
+            int y_i = y[yOff + i] ^ Integer.MIN_VALUE;
+            if (x_i < y_i)
+                return false;
+            if (x_i > y_i)
+                return true;
+        }
+        return true;
+    }
+
+    public static boolean isOne(int[] x)
+    {
+        if (x[0] != 1)
+        {
+            return false;
+        }
+        for (int i = 1; i < 6; ++i)
+        {
+            if (x[i] != 0)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isOne64(long[] x)
+    {
+        if (x[0] != 1L)
+        {
+            return false;
+        }
+        for (int i = 1; i < 3; ++i)
+        {
+            if (x[i] != 0L)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isZero(int[] x)
+    {
+        for (int i = 0; i < 6; ++i)
+        {
+            if (x[i] != 0)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isZero64(long[] x)
+    {
+        for (int i = 0; i < 3; ++i)
+        {
+            if (x[i] != 0L)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static void mul(int[] x, int[] y, int[] zz)
+    {
+        long y_0 = y[0] & M;
+        long y_1 = y[1] & M;
+        long y_2 = y[2] & M;
+        long y_3 = y[3] & M;
+        long y_4 = y[4] & M;
+        long y_5 = y[5] & M;
+
+        {
+            long c = 0, x_0 = x[0] & M;
+            c += x_0 * y_0;
+            zz[0] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_1;
+            zz[1] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_2;
+            zz[2] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_3;
+            zz[3] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_4;
+            zz[4] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_5;
+            zz[5] = (int)c;
+            c >>>= 32;
+            zz[6] = (int)c;
+        }
+
+        for (int i = 1; i < 6; ++i)
+        {
+            long c = 0, x_i = x[i] & M;
+            c += x_i * y_0 + (zz[i + 0] & M);
+            zz[i + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[i + 1] & M);
+            zz[i + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[i + 2] & M);
+            zz[i + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[i + 3] & M);
+            zz[i + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[i + 4] & M);
+            zz[i + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[i + 5] & M);
+            zz[i + 5] = (int)c;
+            c >>>= 32;
+            zz[i + 6] = (int)c;
+        }
+    }
+
+    public static void mul(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+    {
+        long y_0 = y[yOff + 0] & M;
+        long y_1 = y[yOff + 1] & M;
+        long y_2 = y[yOff + 2] & M;
+        long y_3 = y[yOff + 3] & M;
+        long y_4 = y[yOff + 4] & M;
+        long y_5 = y[yOff + 5] & M;
+
+        {
+            long c = 0, x_0 = x[xOff + 0] & M;
+            c += x_0 * y_0;
+            zz[zzOff + 0] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_1;
+            zz[zzOff + 1] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_2;
+            zz[zzOff + 2] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_3;
+            zz[zzOff + 3] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_4;
+            zz[zzOff + 4] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_5;
+            zz[zzOff + 5] = (int)c;
+            c >>>= 32;
+            zz[zzOff + 6] = (int)c;
+        }
+
+        for (int i = 1; i < 6; ++i)
+        {
+            ++zzOff;
+            long c = 0, x_i = x[xOff + i] & M;
+            c += x_i * y_0 + (zz[zzOff + 0] & M);
+            zz[zzOff + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[zzOff + 1] & M);
+            zz[zzOff + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[zzOff + 2] & M);
+            zz[zzOff + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[zzOff + 3] & M);
+            zz[zzOff + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[zzOff + 4] & M);
+            zz[zzOff + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[zzOff + 5] & M);
+            zz[zzOff + 5] = (int)c;
+            c >>>= 32;
+            zz[zzOff + 6] = (int)c;
+        }
+    }
+
+    public static int mulAddTo(int[] x, int[] y, int[] zz)
+    {
+        long y_0 = y[0] & M;
+        long y_1 = y[1] & M;
+        long y_2 = y[2] & M;
+        long y_3 = y[3] & M;
+        long y_4 = y[4] & M;
+        long y_5 = y[5] & M;
+
+        long zc = 0;
+        for (int i = 0; i < 6; ++i)
+        {
+            long c = 0, x_i = x[i] & M;
+            c += x_i * y_0 + (zz[i + 0] & M);
+            zz[i + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[i + 1] & M);
+            zz[i + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[i + 2] & M);
+            zz[i + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[i + 3] & M);
+            zz[i + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[i + 4] & M);
+            zz[i + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[i + 5] & M);
+            zz[i + 5] = (int)c;
+            c >>>= 32;
+            c += zc + (zz[i + 6] & M);
+            zz[i + 6] = (int)c;
+            zc = c >>> 32;
+        }
+        return (int)zc;
+    }
+
+    public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+    {
+        long y_0 = y[yOff + 0] & M;
+        long y_1 = y[yOff + 1] & M;
+        long y_2 = y[yOff + 2] & M;
+        long y_3 = y[yOff + 3] & M;
+        long y_4 = y[yOff + 4] & M;
+        long y_5 = y[yOff + 5] & M;
+
+        long zc = 0;
+        for (int i = 0; i < 6; ++i)
+        {
+            long c = 0, x_i = x[xOff + i] & M;
+            c += x_i * y_0 + (zz[zzOff + 0] & M);
+            zz[zzOff + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[zzOff + 1] & M);
+            zz[zzOff + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[zzOff + 2] & M);
+            zz[zzOff + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[zzOff + 3] & M);
+            zz[zzOff + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[zzOff + 4] & M);
+            zz[zzOff + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[zzOff + 5] & M);
+            zz[zzOff + 5] = (int)c;
+            c >>>= 32;
+            c += zc + (zz[zzOff + 6] & M);
+            zz[zzOff + 6] = (int)c;
+            zc = c >>> 32;
+            ++zzOff;
+        }
+        return (int)zc;
+    }
+
+    public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        // assert w >>> 31 == 0;
+
+        long c = 0, wVal = w & M;
+        long x0 = x[xOff + 0] & M;
+        c += wVal * x0 + (y[yOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        long x1 = x[xOff + 1] & M;
+        c += wVal * x1 + x0 + (y[yOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        long x2 = x[xOff + 2] & M;
+        c += wVal * x2 + x1 + (y[yOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        long x3 = x[xOff + 3] & M;
+        c += wVal * x3 + x2 + (y[yOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        long x4 = x[xOff + 4] & M;
+        c += wVal * x4 + x3 + (y[yOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        long x5 = x[xOff + 5] & M;
+        c += wVal * x5 + x4 + (y[yOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        c += x5;
+        return c;
+    }
+
+    public static int mulWordAddExt(int x, int[] yy, int yyOff, int[] zz, int zzOff)
+    {
+        // assert yyOff <= 6;
+        // assert zzOff <= 6;
+        long c = 0, xVal = x & M;
+        c += xVal * (yy[yyOff + 0] & M) + (zz[zzOff + 0] & M);
+        zz[zzOff + 0] = (int)c;
+        c >>>= 32;
+        c += xVal * (yy[yyOff + 1] & M) + (zz[zzOff + 1] & M);
+        zz[zzOff + 1] = (int)c;
+        c >>>= 32;
+        c += xVal * (yy[yyOff + 2] & M) + (zz[zzOff + 2] & M);
+        zz[zzOff + 2] = (int)c;
+        c >>>= 32;
+        c += xVal * (yy[yyOff + 3] & M) + (zz[zzOff + 3] & M);
+        zz[zzOff + 3] = (int)c;
+        c >>>= 32;
+        c += xVal * (yy[yyOff + 4] & M) + (zz[zzOff + 4] & M);
+        zz[zzOff + 4] = (int)c;
+        c >>>= 32;
+        c += xVal * (yy[yyOff + 5] & M) + (zz[zzOff + 5] & M);
+        zz[zzOff + 5] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int mul33DWordAdd(int x, long y, int[] z, int zOff)
+    {
+        // assert x >>> 31 == 0;
+        // assert zOff <= 2;
+
+        long c = 0, xVal = x & M;
+        long y00 = y & M;
+        c += xVal * y00 + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        long y01 = y >>> 32;
+        c += xVal * y01 + y00 + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += y01 + (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : Nat.incAt(6, z, zOff, 4);
+    }
+
+    public static int mul33WordAdd(int x, int y, int[] z, int zOff)
+    {
+        // assert x >>> 31 == 0;
+        // assert zOff <= 3;
+
+        long c = 0, xVal = x & M, yVal = y & M;
+        c += yVal * xVal + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += yVal + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : Nat.incAt(6, z, zOff, 3);
+    }
+
+    public static int mulWordDwordAdd(int x, long y, int[] z, int zOff)
+    {
+        // assert zOff <= 3;
+        long c = 0, xVal = x & M;
+        c += xVal * (y & M) + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += xVal * (y >>> 32) + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : Nat.incAt(6, z, zOff, 3);
+    }
+
+    public static int mulWord(int x, int[] y, int[] z, int zOff)
+    {
+        long c = 0, xVal = x & M;
+        int i = 0;
+        do
+        {
+            c += xVal * (y[i] & M);
+            z[zOff + i] = (int)c;
+            c >>>= 32;
+        }
+        while (++i < 6);
+        return (int)c;
+    }
+
+    public static void square(int[] x, int[] zz)
+    {
+        long x_0 = x[0] & M;
+        long zz_1;
+
+        int c = 0, w;
+        {
+            int i = 5, j = 12;
+            do
+            {
+                long xVal = (x[i--] & M);
+                long p = xVal * xVal;
+                zz[--j] = (c << 31) | (int)(p >>> 33);
+                zz[--j] = (int)(p >>> 1);
+                c = (int)p;
+            }
+            while (i > 0);
+
+            {
+                long p = x_0 * x_0;
+                zz_1 = ((c << 31) & M) | (p >>> 33);
+                zz[0] = (int)p;
+                c = (int)(p >>> 32) & 1;
+            }
+        }
+
+        long x_1 = x[1] & M;
+        long zz_2 = zz[2] & M;
+
+        {
+            zz_1 += x_1 * x_0;
+            w = (int)zz_1;
+            zz[1] = (w << 1) | c;
+            c = w >>> 31;
+            zz_2 += zz_1 >>> 32;
+        }
+
+        long x_2 = x[2] & M;
+        long zz_3 = zz[3] & M;
+        long zz_4 = zz[4] & M;
+        {
+            zz_2 += x_2 * x_0;
+            w = (int)zz_2;
+            zz[2] = (w << 1) | c;
+            c = w >>> 31;
+            zz_3 += (zz_2 >>> 32) + x_2 * x_1;
+            zz_4 += zz_3 >>> 32;
+            zz_3 &= M;
+        }
+
+        long x_3 = x[3] & M;
+        long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M;
+        long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M;
+        {
+            zz_3 += x_3 * x_0;
+            w = (int)zz_3;
+            zz[3] = (w << 1) | c;
+            c = w >>> 31;
+            zz_4 += (zz_3 >>> 32) + x_3 * x_1;
+            zz_5 += (zz_4 >>> 32) + x_3 * x_2;
+            zz_4 &= M;
+            zz_6 += zz_5 >>> 32;
+            zz_5 &= M;
+        }
+
+        long x_4 = x[4] & M;
+        long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M;
+        long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M;
+        {
+            zz_4 += x_4 * x_0;
+            w = (int)zz_4;
+            zz[4] = (w << 1) | c;
+            c = w >>> 31;
+            zz_5 += (zz_4 >>> 32) + x_4 * x_1;
+            zz_6 += (zz_5 >>> 32) + x_4 * x_2;
+            zz_5 &= M;
+            zz_7 += (zz_6 >>> 32) + x_4 * x_3;
+            zz_6 &= M;
+            zz_8 += zz_7 >>> 32;
+            zz_7 &= M;
+        }
+
+        long x_5 = x[5] & M;
+        long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M;
+        long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M;
+        {
+            zz_5 += x_5 * x_0;
+            w = (int)zz_5;
+            zz[5] = (w << 1) | c;
+            c = w >>> 31;
+            zz_6 += (zz_5 >>> 32) + x_5 * x_1;
+            zz_7 += (zz_6 >>> 32) + x_5 * x_2;
+            zz_8 += (zz_7 >>> 32) + x_5 * x_3;
+            zz_9 += (zz_8 >>> 32) + x_5 * x_4;
+            zz_10 += zz_9 >>> 32;
+        }
+
+        w = (int)zz_6;
+        zz[6] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_7;
+        zz[7] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_8;
+        zz[8] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_9;
+        zz[9] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_10;
+        zz[10] = (w << 1) | c;
+        c = w >>> 31;
+        w = zz[11] + (int)(zz_10 >>> 32);
+        zz[11] = (w << 1) | c;
+    }
+
+    public static void square(int[] x, int xOff, int[] zz, int zzOff)
+    {
+        long x_0 = x[xOff + 0] & M;
+        long zz_1;
+
+        int c = 0, w;
+        {
+            int i = 5, j = 12;
+            do
+            {
+                long xVal = (x[xOff + i--] & M);
+                long p = xVal * xVal;
+                zz[zzOff + --j] = (c << 31) | (int)(p >>> 33);
+                zz[zzOff + --j] = (int)(p >>> 1);
+                c = (int)p;
+            }
+            while (i > 0);
+
+            {
+                long p = x_0 * x_0;
+                zz_1 = ((c << 31) & M) | (p >>> 33);
+                zz[zzOff + 0] = (int)p;
+                c = (int)(p >>> 32) & 1;
+            }
+        }
+
+        long x_1 = x[xOff + 1] & M;
+        long zz_2 = zz[zzOff + 2] & M;
+
+        {
+            zz_1 += x_1 * x_0;
+            w = (int)zz_1;
+            zz[zzOff + 1] = (w << 1) | c;
+            c = w >>> 31;
+            zz_2 += zz_1 >>> 32;
+        }
+
+        long x_2 = x[xOff + 2] & M;
+        long zz_3 = zz[zzOff + 3] & M;
+        long zz_4 = zz[zzOff + 4] & M;
+        {
+            zz_2 += x_2 * x_0;
+            w = (int)zz_2;
+            zz[zzOff + 2] = (w << 1) | c;
+            c = w >>> 31;
+            zz_3 += (zz_2 >>> 32) + x_2 * x_1;
+            zz_4 += zz_3 >>> 32;
+            zz_3 &= M;
+        }
+
+        long x_3 = x[xOff + 3] & M;
+        long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M;
+        long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M;
+        {
+            zz_3 += x_3 * x_0;
+            w = (int)zz_3;
+            zz[zzOff + 3] = (w << 1) | c;
+            c = w >>> 31;
+            zz_4 += (zz_3 >>> 32) + x_3 * x_1;
+            zz_5 += (zz_4 >>> 32) + x_3 * x_2;
+            zz_4 &= M;
+            zz_6 += zz_5 >>> 32;
+            zz_5 &= M;
+        }
+
+        long x_4 = x[xOff + 4] & M;
+        long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M;
+        long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M;
+        {
+            zz_4 += x_4 * x_0;
+            w = (int)zz_4;
+            zz[zzOff + 4] = (w << 1) | c;
+            c = w >>> 31;
+            zz_5 += (zz_4 >>> 32) + x_4 * x_1;
+            zz_6 += (zz_5 >>> 32) + x_4 * x_2;
+            zz_5 &= M;
+            zz_7 += (zz_6 >>> 32) + x_4 * x_3;
+            zz_6 &= M;
+            zz_8 += zz_7 >>> 32;
+            zz_7 &= M;
+        }
+
+        long x_5 = x[xOff + 5] & M;
+        long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M;
+        long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M;
+        {
+            zz_5 += x_5 * x_0;
+            w = (int)zz_5;
+            zz[zzOff + 5] = (w << 1) | c;
+            c = w >>> 31;
+            zz_6 += (zz_5 >>> 32) + x_5 * x_1;
+            zz_7 += (zz_6 >>> 32) + x_5 * x_2;
+            zz_8 += (zz_7 >>> 32) + x_5 * x_3;
+            zz_9 += (zz_8 >>> 32) + x_5 * x_4;
+            zz_10 += zz_9 >>> 32;
+        }
+
+        w = (int)zz_6;
+        zz[zzOff + 6] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_7;
+        zz[zzOff + 7] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_8;
+        zz[zzOff + 8] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_9;
+        zz[zzOff + 9] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_10;
+        zz[zzOff + 10] = (w << 1) | c;
+        c = w >>> 31;
+        w = zz[zzOff + 11] + (int)(zz_10 >>> 32);
+        zz[zzOff + 11] = (w << 1) | c;
+    }
+
+    public static int sub(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) - (y[0] & M);
+        z[0] = (int)c;
+        c >>= 32;
+        c += (x[1] & M) - (y[1] & M);
+        z[1] = (int)c;
+        c >>= 32;
+        c += (x[2] & M) - (y[2] & M);
+        z[2] = (int)c;
+        c >>= 32;
+        c += (x[3] & M) - (y[3] & M);
+        z[3] = (int)c;
+        c >>= 32;
+        c += (x[4] & M) - (y[4] & M);
+        z[4] = (int)c;
+        c >>= 32;
+        c += (x[5] & M) - (y[5] & M);
+        z[5] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int sub(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0;
+        c += (x[xOff + 0] & M) - (y[yOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 1] & M) - (y[yOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 2] & M) - (y[yOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 3] & M) - (y[yOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 4] & M) - (y[yOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 5] & M) - (y[yOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int subBothFrom(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (z[0] & M) - (x[0] & M) - (y[0] & M);
+        z[0] = (int)c;
+        c >>= 32;
+        c += (z[1] & M) - (x[1] & M) - (y[1] & M);
+        z[1] = (int)c;
+        c >>= 32;
+        c += (z[2] & M) - (x[2] & M) - (y[2] & M);
+        z[2] = (int)c;
+        c >>= 32;
+        c += (z[3] & M) - (x[3] & M) - (y[3] & M);
+        z[3] = (int)c;
+        c >>= 32;
+        c += (z[4] & M) - (x[4] & M) - (y[4] & M);
+        z[4] = (int)c;
+        c >>= 32;
+        c += (z[5] & M) - (x[5] & M) - (y[5] & M);
+        z[5] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int subFrom(int[] x, int[] z)
+    {
+        long c = 0;
+        c += (z[0] & M) - (x[0] & M);
+        z[0] = (int)c;
+        c >>= 32;
+        c += (z[1] & M) - (x[1] & M);
+        z[1] = (int)c;
+        c >>= 32;
+        c += (z[2] & M) - (x[2] & M);
+        z[2] = (int)c;
+        c >>= 32;
+        c += (z[3] & M) - (x[3] & M);
+        z[3] = (int)c;
+        c >>= 32;
+        c += (z[4] & M) - (x[4] & M);
+        z[4] = (int)c;
+        c >>= 32;
+        c += (z[5] & M) - (x[5] & M);
+        z[5] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int subFrom(int[] x, int xOff, int[] z, int zOff)
+    {
+        long c = 0;
+        c += (z[zOff + 0] & M) - (x[xOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 1] & M) - (x[xOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 2] & M) - (x[xOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 3] & M) - (x[xOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 4] & M) - (x[xOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 5] & M) - (x[xOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static BigInteger toBigInteger(int[] x)
+    {
+        byte[] bs = new byte[24];
+        for (int i = 0; i < 6; ++i)
+        {
+            int x_i = x[i];
+            if (x_i != 0)
+            {
+                Pack.intToBigEndian(x_i, bs, (5 - i) << 2);
+            }
+        }
+        return new BigInteger(1, bs);
+    }
+
+    public static BigInteger toBigInteger64(long[] x)
+    {
+        byte[] bs = new byte[24];
+        for (int i = 0; i < 3; ++i)
+        {
+            long x_i = x[i];
+            if (x_i != 0L)
+            {
+                Pack.longToBigEndian(x_i, bs, (2 - i) << 3);
+            }
+        }
+        return new BigInteger(1, bs);
+    }
+
+    public static void zero(int[] z)
+    {
+        z[0] = 0;
+        z[1] = 0;
+        z[2] = 0;
+        z[3] = 0;
+        z[4] = 0;
+        z[5] = 0;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat224.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat224.java
new file mode 100644
index 0000000..f93768b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat224.java
@@ -0,0 +1,1197 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.raw;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class Nat224
+{
+    private static final long M = 0xFFFFFFFFL;
+
+    public static int add(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) + (y[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += (x[1] & M) + (y[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += (x[2] & M) + (y[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += (x[3] & M) + (y[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += (x[4] & M) + (y[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += (x[5] & M) + (y[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        c += (x[6] & M) + (y[6] & M);
+        z[6] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int add(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0;
+        c += (x[xOff + 0] & M) + (y[yOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 1] & M) + (y[yOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 2] & M) + (y[yOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 3] & M) + (y[yOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 4] & M) + (y[yOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 5] & M) + (y[yOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 6] & M) + (y[yOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addBothTo(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) + (y[0] & M) + (z[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += (x[1] & M) + (y[1] & M) + (z[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += (x[2] & M) + (y[2] & M) + (z[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += (x[3] & M) + (y[3] & M) + (z[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += (x[4] & M) + (y[4] & M) + (z[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += (x[5] & M) + (y[5] & M) + (z[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        c += (x[6] & M) + (y[6] & M) + (z[6] & M);
+        z[6] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addBothTo(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0;
+        c += (x[xOff + 0] & M) + (y[yOff + 0] & M) + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 1] & M) + (y[yOff + 1] & M) + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 2] & M) + (y[yOff + 2] & M) + (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 3] & M) + (y[yOff + 3] & M) + (z[zOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 4] & M) + (y[yOff + 4] & M) + (z[zOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 5] & M) + (y[yOff + 5] & M) + (z[zOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 6] & M) + (y[yOff + 6] & M) + (z[zOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addTo(int[] x, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) + (z[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += (x[1] & M) + (z[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += (x[2] & M) + (z[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += (x[3] & M) + (z[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += (x[4] & M) + (z[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += (x[5] & M) + (z[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        c += (x[6] & M) + (z[6] & M);
+        z[6] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addTo(int[] x, int xOff, int[] z, int zOff, int cIn)
+    {
+        long c = cIn & M;
+        c += (x[xOff + 0] & M) + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 1] & M) + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 2] & M) + (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 3] & M) + (z[zOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 4] & M) + (z[zOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 5] & M) + (z[zOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 6] & M) + (z[zOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addToEachOther(int[] u, int uOff, int[] v, int vOff)
+    {
+        long c = 0;
+        c += (u[uOff + 0] & M) + (v[vOff + 0] & M);
+        u[uOff + 0] = (int)c;
+        v[vOff + 0] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 1] & M) + (v[vOff + 1] & M);
+        u[uOff + 1] = (int)c;
+        v[vOff + 1] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 2] & M) + (v[vOff + 2] & M);
+        u[uOff + 2] = (int)c;
+        v[vOff + 2] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 3] & M) + (v[vOff + 3] & M);
+        u[uOff + 3] = (int)c;
+        v[vOff + 3] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 4] & M) + (v[vOff + 4] & M);
+        u[uOff + 4] = (int)c;
+        v[vOff + 4] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 5] & M) + (v[vOff + 5] & M);
+        u[uOff + 5] = (int)c;
+        v[vOff + 5] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 6] & M) + (v[vOff + 6] & M);
+        u[uOff + 6] = (int)c;
+        v[vOff + 6] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static void copy(int[] x, int[] z)
+    {
+        z[0] = x[0];
+        z[1] = x[1];
+        z[2] = x[2];
+        z[3] = x[3];
+        z[4] = x[4];
+        z[5] = x[5];
+        z[6] = x[6];
+    }
+
+    public static void copy(int[] x, int xOff, int[] z, int zOff)
+    {
+        z[zOff + 0] = x[xOff + 0];
+        z[zOff + 1] = x[xOff + 1];
+        z[zOff + 2] = x[xOff + 2];
+        z[zOff + 3] = x[xOff + 3];
+        z[zOff + 4] = x[xOff + 4];
+        z[zOff + 5] = x[xOff + 5];
+        z[zOff + 6] = x[xOff + 6];
+    }
+
+    public static int[] create()
+    {
+        return new int[7];
+    }
+
+    public static int[] createExt()
+    {
+        return new int[14];
+    }
+
+    public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        boolean pos = gte(x, xOff, y, yOff);
+        if (pos)
+        {
+            sub(x, xOff, y, yOff, z, zOff);
+        }
+        else
+        {
+            sub(y, yOff, x, xOff, z, zOff);
+        }
+        return pos;
+    }
+
+    public static boolean eq(int[] x, int[] y)
+    {
+        for (int i = 6; i >= 0; --i)
+        {
+            if (x[i] != y[i])
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static int[] fromBigInteger(BigInteger x)
+    {
+        if (x.signum() < 0 || x.bitLength() > 224)
+        {
+            throw new IllegalArgumentException();
+        }
+
+        int[] z = create();
+        int i = 0;
+        while (x.signum() != 0)
+        {
+            z[i++] = x.intValue();
+            x = x.shiftRight(32);
+        }
+        return z;
+    }
+
+    public static int getBit(int[] x, int bit)
+    {
+        if (bit == 0)
+        {
+            return x[0] & 1;
+        }
+        int w = bit >> 5;
+        if (w < 0 || w >= 7)
+        {
+            return 0;
+        }
+        int b = bit & 31;
+        return (x[w] >>> b) & 1;
+    }
+
+    public static boolean gte(int[] x, int[] y)
+    {
+        for (int i = 6; i >= 0; --i)
+        {
+            int x_i = x[i] ^ Integer.MIN_VALUE;
+            int y_i = y[i] ^ Integer.MIN_VALUE;
+            if (x_i < y_i)
+                return false;
+            if (x_i > y_i)
+                return true;
+        }
+        return true;
+    }
+
+    public static boolean gte(int[] x, int xOff, int[] y, int yOff)
+    {
+        for (int i = 6; i >= 0; --i)
+        {
+            int x_i = x[xOff + i] ^ Integer.MIN_VALUE;
+            int y_i = y[yOff + i] ^ Integer.MIN_VALUE;
+            if (x_i < y_i)
+                return false;
+            if (x_i > y_i)
+                return true;
+        }
+        return true;
+    }
+
+    public static boolean isOne(int[] x)
+    {
+        if (x[0] != 1)
+        {
+            return false;
+        }
+        for (int i = 1; i < 7; ++i)
+        {
+            if (x[i] != 0)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isZero(int[] x)
+    {
+        for (int i = 0; i < 7; ++i)
+        {
+            if (x[i] != 0)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static void mul(int[] x, int[] y, int[] zz)
+    {
+        long y_0 = y[0] & M;
+        long y_1 = y[1] & M;
+        long y_2 = y[2] & M;
+        long y_3 = y[3] & M;
+        long y_4 = y[4] & M;
+        long y_5 = y[5] & M;
+        long y_6 = y[6] & M;
+
+        {
+            long c = 0, x_0 = x[0] & M;
+            c += x_0 * y_0;
+            zz[0] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_1;
+            zz[1] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_2;
+            zz[2] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_3;
+            zz[3] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_4;
+            zz[4] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_5;
+            zz[5] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_6;
+            zz[6] = (int)c;
+            c >>>= 32;
+            zz[7] = (int)c;
+        }
+
+        for (int i = 1; i < 7; ++i)
+        {
+            long c = 0, x_i = x[i] & M;
+            c += x_i * y_0 + (zz[i + 0] & M);
+            zz[i + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[i + 1] & M);
+            zz[i + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[i + 2] & M);
+            zz[i + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[i + 3] & M);
+            zz[i + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[i + 4] & M);
+            zz[i + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[i + 5] & M);
+            zz[i + 5] = (int)c;
+            c >>>= 32;
+            c += x_i * y_6 + (zz[i + 6] & M);
+            zz[i + 6] = (int)c;
+            c >>>= 32;
+            zz[i + 7] = (int)c;
+        }
+    }
+
+    public static void mul(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+    {
+        long y_0 = y[yOff + 0] & M;
+        long y_1 = y[yOff + 1] & M;
+        long y_2 = y[yOff + 2] & M;
+        long y_3 = y[yOff + 3] & M;
+        long y_4 = y[yOff + 4] & M;
+        long y_5 = y[yOff + 5] & M;
+        long y_6 = y[yOff + 6] & M;
+
+        {
+            long c = 0, x_0 = x[xOff + 0] & M;
+            c += x_0 * y_0;
+            zz[zzOff + 0] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_1;
+            zz[zzOff + 1] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_2;
+            zz[zzOff + 2] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_3;
+            zz[zzOff + 3] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_4;
+            zz[zzOff + 4] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_5;
+            zz[zzOff + 5] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_6;
+            zz[zzOff + 6] = (int)c;
+            c >>>= 32;
+            zz[zzOff + 7] = (int)c;
+        }
+
+        for (int i = 1; i < 7; ++i)
+        {
+            ++zzOff;
+            long c = 0, x_i = x[xOff + i] & M;
+            c += x_i * y_0 + (zz[zzOff + 0] & M);
+            zz[zzOff + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[zzOff + 1] & M);
+            zz[zzOff + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[zzOff + 2] & M);
+            zz[zzOff + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[zzOff + 3] & M);
+            zz[zzOff + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[zzOff + 4] & M);
+            zz[zzOff + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[zzOff + 5] & M);
+            zz[zzOff + 5] = (int)c;
+            c >>>= 32;
+            c += x_i * y_6 + (zz[zzOff + 6] & M);
+            zz[zzOff + 6] = (int)c;
+            c >>>= 32;
+            zz[zzOff + 7] = (int)c;
+        }
+    }
+
+    public static int mulAddTo(int[] x, int[] y, int[] zz)
+    {
+        long y_0 = y[0] & M;
+        long y_1 = y[1] & M;
+        long y_2 = y[2] & M;
+        long y_3 = y[3] & M;
+        long y_4 = y[4] & M;
+        long y_5 = y[5] & M;
+        long y_6 = y[6] & M;
+
+        long zc = 0;
+        for (int i = 0; i < 7; ++i)
+        {
+            long c = 0, x_i = x[i] & M;
+            c += x_i * y_0 + (zz[i + 0] & M);
+            zz[i + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[i + 1] & M);
+            zz[i + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[i + 2] & M);
+            zz[i + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[i + 3] & M);
+            zz[i + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[i + 4] & M);
+            zz[i + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[i + 5] & M);
+            zz[i + 5] = (int)c;
+            c >>>= 32;
+            c += x_i * y_6 + (zz[i + 6] & M);
+            zz[i + 6] = (int)c;
+            c >>>= 32;
+            c += zc + (zz[i + 7] & M);
+            zz[i + 7] = (int)c;
+            zc = c >>> 32;
+        }
+        return (int)zc;
+    }
+
+    public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+    {
+        long y_0 = y[yOff + 0] & M;
+        long y_1 = y[yOff + 1] & M;
+        long y_2 = y[yOff + 2] & M;
+        long y_3 = y[yOff + 3] & M;
+        long y_4 = y[yOff + 4] & M;
+        long y_5 = y[yOff + 5] & M;
+        long y_6 = y[yOff + 6] & M;
+
+        long zc = 0;
+        for (int i = 0; i < 7; ++i)
+        {
+            long c = 0, x_i = x[xOff + i] & M;
+            c += x_i * y_0 + (zz[zzOff + 0] & M);
+            zz[zzOff + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[zzOff + 1] & M);
+            zz[zzOff + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[zzOff + 2] & M);
+            zz[zzOff + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[zzOff + 3] & M);
+            zz[zzOff + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[zzOff + 4] & M);
+            zz[zzOff + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[zzOff + 5] & M);
+            zz[zzOff + 5] = (int)c;
+            c >>>= 32;
+            c += x_i * y_6 + (zz[zzOff + 6] & M);
+            zz[zzOff + 6] = (int)c;
+            c >>>= 32;
+            c += zc + (zz[zzOff + 7] & M);
+            zz[zzOff + 7] = (int)c;
+            zc = c >>> 32;
+            ++zzOff;
+        }
+        return (int)zc;
+    }
+
+    public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        // assert w >>> 31 == 0;
+
+        long c = 0, wVal = w & M;
+        long x0 = x[xOff + 0] & M;
+        c += wVal * x0 + (y[yOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        long x1 = x[xOff + 1] & M;
+        c += wVal * x1 + x0 + (y[yOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        long x2 = x[xOff + 2] & M;
+        c += wVal * x2 + x1 + (y[yOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        long x3 = x[xOff + 3] & M;
+        c += wVal * x3 + x2 + (y[yOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        long x4 = x[xOff + 4] & M;
+        c += wVal * x4 + x3 + (y[yOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        long x5 = x[xOff + 5] & M;
+        c += wVal * x5 + x4 + (y[yOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        long x6 = x[xOff + 6] & M;
+        c += wVal * x6 + x5 + (y[yOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>>= 32;
+        c += x6;
+        return c;
+    }
+
+    public static int mulByWord(int x, int[] z)
+    {
+        long c = 0, xVal = x & M;
+        c += xVal * (z[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[6] & M);
+        z[6] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int mulByWordAddTo(int x, int[] y, int[] z)
+    {
+        long c = 0, xVal = x & M;
+        c += xVal * (z[0] & M) + (y[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[1] & M) + (y[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[2] & M) + (y[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[3] & M) + (y[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[4] & M) + (y[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[5] & M) + (y[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[6] & M) + (y[6] & M);
+        z[6] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int mulWordAddTo(int x, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0, xVal = x & M;
+        c += xVal * (y[yOff + 0] & M) + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 1] & M) + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 2] & M) + (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 3] & M) + (z[zOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 4] & M) + (z[zOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 5] & M) + (z[zOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 6] & M) + (z[zOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int mul33DWordAdd(int x, long y, int[] z, int zOff)
+    {
+        // assert x >>> 31 == 0;
+        // assert zOff <= 3;
+
+        long c = 0, xVal = x & M;
+        long y00 = y & M;
+        c += xVal * y00 + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        long y01 = y >>> 32;
+        c += xVal * y01 + y00 + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += y01 + (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : Nat.incAt(7, z, zOff, 4);
+    }
+
+    public static int mul33WordAdd(int x, int y, int[] z, int zOff)
+    {
+        // assert x >>> 31 == 0;
+        // assert zOff <= 4;
+
+        long c = 0, xVal = x & M, yVal = y & M;
+        c += yVal * xVal + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += yVal + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : Nat.incAt(7, z, zOff, 3);
+    }
+
+    public static int mulWordDwordAdd(int x, long y, int[] z, int zOff)
+    {
+        // assert zOff <= 4;
+        long c = 0, xVal = x & M;
+        c += xVal * (y & M) + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += xVal * (y >>> 32) + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : Nat.incAt(7, z, zOff, 3);
+    }
+
+    public static int mulWord(int x, int[] y, int[] z, int zOff)
+    {
+        long c = 0, xVal = x & M;
+        int i = 0;
+        do
+        {
+            c += xVal * (y[i] & M);
+            z[zOff + i] = (int)c;
+            c >>>= 32;
+        }
+        while (++i < 7);
+        return (int)c;
+    }
+
+    public static void square(int[] x, int[] zz)
+    {
+        long x_0 = x[0] & M;
+        long zz_1;
+
+        int c = 0, w;
+        {
+            int i = 6, j = 14;
+            do
+            {
+                long xVal = (x[i--] & M);
+                long p = xVal * xVal;
+                zz[--j] = (c << 31) | (int)(p >>> 33);
+                zz[--j] = (int)(p >>> 1);
+                c = (int)p;
+            }
+            while (i > 0);
+
+            {
+                long p = x_0 * x_0;
+                zz_1 = ((c << 31) & M) | (p >>> 33);
+                zz[0] = (int)p;
+                c = (int)(p >>> 32) & 1;
+            }
+        }
+
+        long x_1 = x[1] & M;
+        long zz_2 = zz[2] & M;
+
+        {
+            zz_1 += x_1 * x_0;
+            w = (int)zz_1;
+            zz[1] = (w << 1) | c;
+            c = w >>> 31;
+            zz_2 += zz_1 >>> 32;
+        }
+
+        long x_2 = x[2] & M;
+        long zz_3 = zz[3] & M;
+        long zz_4 = zz[4] & M;
+        {
+            zz_2 += x_2 * x_0;
+            w = (int)zz_2;
+            zz[2] = (w << 1) | c;
+            c = w >>> 31;
+            zz_3 += (zz_2 >>> 32) + x_2 * x_1;
+            zz_4 += zz_3 >>> 32;
+            zz_3 &= M;
+        }
+
+        long x_3 = x[3] & M;
+        long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M;
+        long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M;
+        {
+            zz_3 += x_3 * x_0;
+            w = (int)zz_3;
+            zz[3] = (w << 1) | c;
+            c = w >>> 31;
+            zz_4 += (zz_3 >>> 32) + x_3 * x_1;
+            zz_5 += (zz_4 >>> 32) + x_3 * x_2;
+            zz_4 &= M;
+            zz_6 += zz_5 >>> 32;
+            zz_5 &= M;
+        }
+
+        long x_4 = x[4] & M;
+        long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M;
+        long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M;
+        {
+            zz_4 += x_4 * x_0;
+            w = (int)zz_4;
+            zz[4] = (w << 1) | c;
+            c = w >>> 31;
+            zz_5 += (zz_4 >>> 32) + x_4 * x_1;
+            zz_6 += (zz_5 >>> 32) + x_4 * x_2;
+            zz_5 &= M;
+            zz_7 += (zz_6 >>> 32) + x_4 * x_3;
+            zz_6 &= M;
+            zz_8 += zz_7 >>> 32;
+            zz_7 &= M;
+        }
+
+        long x_5 = x[5] & M;
+        long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M;
+        long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M;
+        {
+            zz_5 += x_5 * x_0;
+            w = (int)zz_5;
+            zz[5] = (w << 1) | c;
+            c = w >>> 31;
+            zz_6 += (zz_5 >>> 32) + x_5 * x_1;
+            zz_7 += (zz_6 >>> 32) + x_5 * x_2;
+            zz_6 &= M;
+            zz_8 += (zz_7 >>> 32) + x_5 * x_3;
+            zz_7 &= M;
+            zz_9 += (zz_8 >>> 32) + x_5 * x_4;
+            zz_8 &= M;
+            zz_10 += zz_9 >>> 32;
+            zz_9 &= M;
+        }
+
+        long x_6 = x[6] & M;
+        long zz_11 = (zz[11] & M) + (zz_10 >>> 32); zz_10 &= M;
+        long zz_12 = (zz[12] & M) + (zz_11 >>> 32); zz_11 &= M;
+        {
+            zz_6 += x_6 * x_0;
+            w = (int)zz_6;
+            zz[6] = (w << 1) | c;
+            c = w >>> 31;
+            zz_7 += (zz_6 >>> 32) + x_6 * x_1;
+            zz_8 += (zz_7 >>> 32) + x_6 * x_2;
+            zz_9 += (zz_8 >>> 32) + x_6 * x_3;
+            zz_10 += (zz_9 >>> 32) + x_6 * x_4;
+            zz_11 += (zz_10 >>> 32) + x_6 * x_5;
+            zz_12 += zz_11 >>> 32;
+        }
+
+        w = (int)zz_7;
+        zz[7] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_8;
+        zz[8] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_9;
+        zz[9] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_10;
+        zz[10] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_11;
+        zz[11] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_12;
+        zz[12] = (w << 1) | c;
+        c = w >>> 31;
+        w = zz[13] + (int)(zz_12 >>> 32);
+        zz[13] = (w << 1) | c;
+    }
+
+    public static void square(int[] x, int xOff, int[] zz, int zzOff)
+    {
+        long x_0 = x[xOff + 0] & M;
+        long zz_1;
+
+        int c = 0, w;
+        {
+            int i = 6, j = 14;
+            do
+            {
+                long xVal = (x[xOff + i--] & M);
+                long p = xVal * xVal;
+                zz[zzOff + --j] = (c << 31) | (int)(p >>> 33);
+                zz[zzOff + --j] = (int)(p >>> 1);
+                c = (int)p;
+            }
+            while (i > 0);
+
+            {
+                long p = x_0 * x_0;
+                zz_1 = ((c << 31) & M) | (p >>> 33);
+                zz[zzOff + 0] = (int)p;
+                c = (int)(p >>> 32) & 1;
+            }
+        }
+
+        long x_1 = x[xOff + 1] & M;
+        long zz_2 = zz[zzOff + 2] & M;
+
+        {
+            zz_1 += x_1 * x_0;
+            w = (int)zz_1;
+            zz[zzOff + 1] = (w << 1) | c;
+            c = w >>> 31;
+            zz_2 += zz_1 >>> 32;
+        }
+
+        long x_2 = x[xOff + 2] & M;
+        long zz_3 = zz[zzOff + 3] & M;
+        long zz_4 = zz[zzOff + 4] & M;
+        {
+            zz_2 += x_2 * x_0;
+            w = (int)zz_2;
+            zz[zzOff + 2] = (w << 1) | c;
+            c = w >>> 31;
+            zz_3 += (zz_2 >>> 32) + x_2 * x_1;
+            zz_4 += zz_3 >>> 32;
+            zz_3 &= M;
+        }
+
+        long x_3 = x[xOff + 3] & M;
+        long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M;
+        long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M;
+        {
+            zz_3 += x_3 * x_0;
+            w = (int)zz_3;
+            zz[zzOff + 3] = (w << 1) | c;
+            c = w >>> 31;
+            zz_4 += (zz_3 >>> 32) + x_3 * x_1;
+            zz_5 += (zz_4 >>> 32) + x_3 * x_2;
+            zz_4 &= M;
+            zz_6 += zz_5 >>> 32;
+            zz_5 &= M;
+        }
+
+        long x_4 = x[xOff + 4] & M;
+        long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M;
+        long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M;
+        {
+            zz_4 += x_4 * x_0;
+            w = (int)zz_4;
+            zz[zzOff + 4] = (w << 1) | c;
+            c = w >>> 31;
+            zz_5 += (zz_4 >>> 32) + x_4 * x_1;
+            zz_6 += (zz_5 >>> 32) + x_4 * x_2;
+            zz_5 &= M;
+            zz_7 += (zz_6 >>> 32) + x_4 * x_3;
+            zz_6 &= M;
+            zz_8 += zz_7 >>> 32;
+            zz_7 &= M;
+        }
+
+        long x_5 = x[xOff + 5] & M;
+        long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M;
+        long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M;
+        {
+            zz_5 += x_5 * x_0;
+            w = (int)zz_5;
+            zz[zzOff + 5] = (w << 1) | c;
+            c = w >>> 31;
+            zz_6 += (zz_5 >>> 32) + x_5 * x_1;
+            zz_7 += (zz_6 >>> 32) + x_5 * x_2;
+            zz_6 &= M;
+            zz_8 += (zz_7 >>> 32) + x_5 * x_3;
+            zz_7 &= M;
+            zz_9 += (zz_8 >>> 32) + x_5 * x_4;
+            zz_8 &= M;
+            zz_10 += zz_9 >>> 32;
+            zz_9 &= M;
+        }
+
+        long x_6 = x[xOff + 6] & M;
+        long zz_11 = (zz[zzOff + 11] & M) + (zz_10 >>> 32); zz_10 &= M;
+        long zz_12 = (zz[zzOff + 12] & M) + (zz_11 >>> 32); zz_11 &= M;
+        {
+            zz_6 += x_6 * x_0;
+            w = (int)zz_6;
+            zz[zzOff + 6] = (w << 1) | c;
+            c = w >>> 31;
+            zz_7 += (zz_6 >>> 32) + x_6 * x_1;
+            zz_8 += (zz_7 >>> 32) + x_6 * x_2;
+            zz_9 += (zz_8 >>> 32) + x_6 * x_3;
+            zz_10 += (zz_9 >>> 32) + x_6 * x_4;
+            zz_11 += (zz_10 >>> 32) + x_6 * x_5;
+            zz_12 += zz_11 >>> 32;
+        }
+
+        w = (int)zz_7;
+        zz[zzOff + 7] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_8;
+        zz[zzOff + 8] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_9;
+        zz[zzOff + 9] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_10;
+        zz[zzOff + 10] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_11;
+        zz[zzOff + 11] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_12;
+        zz[zzOff + 12] = (w << 1) | c;
+        c = w >>> 31;
+        w = zz[zzOff + 13] + (int)(zz_12 >>> 32);
+        zz[zzOff + 13] = (w << 1) | c;
+    }
+
+    public static int sub(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) - (y[0] & M);
+        z[0] = (int)c;
+        c >>= 32;
+        c += (x[1] & M) - (y[1] & M);
+        z[1] = (int)c;
+        c >>= 32;
+        c += (x[2] & M) - (y[2] & M);
+        z[2] = (int)c;
+        c >>= 32;
+        c += (x[3] & M) - (y[3] & M);
+        z[3] = (int)c;
+        c >>= 32;
+        c += (x[4] & M) - (y[4] & M);
+        z[4] = (int)c;
+        c >>= 32;
+        c += (x[5] & M) - (y[5] & M);
+        z[5] = (int)c;
+        c >>= 32;
+        c += (x[6] & M) - (y[6] & M);
+        z[6] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int sub(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0;
+        c += (x[xOff + 0] & M) - (y[yOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 1] & M) - (y[yOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 2] & M) - (y[yOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 3] & M) - (y[yOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 4] & M) - (y[yOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 5] & M) - (y[yOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 6] & M) - (y[yOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int subBothFrom(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (z[0] & M) - (x[0] & M) - (y[0] & M);
+        z[0] = (int)c;
+        c >>= 32;
+        c += (z[1] & M) - (x[1] & M) - (y[1] & M);
+        z[1] = (int)c;
+        c >>= 32;
+        c += (z[2] & M) - (x[2] & M) - (y[2] & M);
+        z[2] = (int)c;
+        c >>= 32;
+        c += (z[3] & M) - (x[3] & M) - (y[3] & M);
+        z[3] = (int)c;
+        c >>= 32;
+        c += (z[4] & M) - (x[4] & M) - (y[4] & M);
+        z[4] = (int)c;
+        c >>= 32;
+        c += (z[5] & M) - (x[5] & M) - (y[5] & M);
+        z[5] = (int)c;
+        c >>= 32;
+        c += (z[6] & M) - (x[6] & M) - (y[6] & M);
+        z[6] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int subFrom(int[] x, int[] z)
+    {
+        long c = 0;
+        c += (z[0] & M) - (x[0] & M);
+        z[0] = (int)c;
+        c >>= 32;
+        c += (z[1] & M) - (x[1] & M);
+        z[1] = (int)c;
+        c >>= 32;
+        c += (z[2] & M) - (x[2] & M);
+        z[2] = (int)c;
+        c >>= 32;
+        c += (z[3] & M) - (x[3] & M);
+        z[3] = (int)c;
+        c >>= 32;
+        c += (z[4] & M) - (x[4] & M);
+        z[4] = (int)c;
+        c >>= 32;
+        c += (z[5] & M) - (x[5] & M);
+        z[5] = (int)c;
+        c >>= 32;
+        c += (z[6] & M) - (x[6] & M);
+        z[6] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int subFrom(int[] x, int xOff, int[] z, int zOff)
+    {
+        long c = 0;
+        c += (z[zOff + 0] & M) - (x[xOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 1] & M) - (x[xOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 2] & M) - (x[xOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 3] & M) - (x[xOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 4] & M) - (x[xOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 5] & M) - (x[xOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 6] & M) - (x[xOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static BigInteger toBigInteger(int[] x)
+    {
+        byte[] bs = new byte[28];
+        for (int i = 0; i < 7; ++i)
+        {
+            int x_i = x[i];
+            if (x_i != 0)
+            {
+                Pack.intToBigEndian(x_i, bs, (6 - i) << 2);
+            }
+        }
+        return new BigInteger(1, bs);
+    }
+
+    public static void zero(int[] z)
+    {
+        z[0] = 0;
+        z[1] = 0;
+        z[2] = 0;
+        z[3] = 0;
+        z[4] = 0;
+        z[5] = 0;
+        z[6] = 0;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat256.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat256.java
new file mode 100644
index 0000000..20ae3ad
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat256.java
@@ -0,0 +1,1419 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.raw;
+
+import java.math.BigInteger;
+
+import com.android.internal.org.bouncycastle.util.Pack;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class Nat256
+{
+    private static final long M = 0xFFFFFFFFL;
+
+    public static int add(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) + (y[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += (x[1] & M) + (y[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += (x[2] & M) + (y[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += (x[3] & M) + (y[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += (x[4] & M) + (y[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += (x[5] & M) + (y[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        c += (x[6] & M) + (y[6] & M);
+        z[6] = (int)c;
+        c >>>= 32;
+        c += (x[7] & M) + (y[7] & M);
+        z[7] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int add(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0;
+        c += (x[xOff + 0] & M) + (y[yOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 1] & M) + (y[yOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 2] & M) + (y[yOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 3] & M) + (y[yOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 4] & M) + (y[yOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 5] & M) + (y[yOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 6] & M) + (y[yOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 7] & M) + (y[yOff + 7] & M);
+        z[zOff + 7] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addBothTo(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) + (y[0] & M) + (z[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += (x[1] & M) + (y[1] & M) + (z[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += (x[2] & M) + (y[2] & M) + (z[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += (x[3] & M) + (y[3] & M) + (z[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += (x[4] & M) + (y[4] & M) + (z[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += (x[5] & M) + (y[5] & M) + (z[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        c += (x[6] & M) + (y[6] & M) + (z[6] & M);
+        z[6] = (int)c;
+        c >>>= 32;
+        c += (x[7] & M) + (y[7] & M) + (z[7] & M);
+        z[7] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addBothTo(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0;
+        c += (x[xOff + 0] & M) + (y[yOff + 0] & M) + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 1] & M) + (y[yOff + 1] & M) + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 2] & M) + (y[yOff + 2] & M) + (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 3] & M) + (y[yOff + 3] & M) + (z[zOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 4] & M) + (y[yOff + 4] & M) + (z[zOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 5] & M) + (y[yOff + 5] & M) + (z[zOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 6] & M) + (y[yOff + 6] & M) + (z[zOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 7] & M) + (y[yOff + 7] & M) + (z[zOff + 7] & M);
+        z[zOff + 7] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addTo(int[] x, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) + (z[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += (x[1] & M) + (z[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += (x[2] & M) + (z[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += (x[3] & M) + (z[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += (x[4] & M) + (z[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += (x[5] & M) + (z[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        c += (x[6] & M) + (z[6] & M);
+        z[6] = (int)c;
+        c >>>= 32;
+        c += (x[7] & M) + (z[7] & M);
+        z[7] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addTo(int[] x, int xOff, int[] z, int zOff, int cIn)
+    {
+        long c = cIn & M;
+        c += (x[xOff + 0] & M) + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 1] & M) + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 2] & M) + (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 3] & M) + (z[zOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 4] & M) + (z[zOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 5] & M) + (z[zOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 6] & M) + (z[zOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>>= 32;
+        c += (x[xOff + 7] & M) + (z[zOff + 7] & M);
+        z[zOff + 7] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int addToEachOther(int[] u, int uOff, int[] v, int vOff)
+    {
+        long c = 0;
+        c += (u[uOff + 0] & M) + (v[vOff + 0] & M);
+        u[uOff + 0] = (int)c;
+        v[vOff + 0] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 1] & M) + (v[vOff + 1] & M);
+        u[uOff + 1] = (int)c;
+        v[vOff + 1] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 2] & M) + (v[vOff + 2] & M);
+        u[uOff + 2] = (int)c;
+        v[vOff + 2] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 3] & M) + (v[vOff + 3] & M);
+        u[uOff + 3] = (int)c;
+        v[vOff + 3] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 4] & M) + (v[vOff + 4] & M);
+        u[uOff + 4] = (int)c;
+        v[vOff + 4] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 5] & M) + (v[vOff + 5] & M);
+        u[uOff + 5] = (int)c;
+        v[vOff + 5] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 6] & M) + (v[vOff + 6] & M);
+        u[uOff + 6] = (int)c;
+        v[vOff + 6] = (int)c;
+        c >>>= 32;
+        c += (u[uOff + 7] & M) + (v[vOff + 7] & M);
+        u[uOff + 7] = (int)c;
+        v[vOff + 7] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static void copy(int[] x, int[] z)
+    {
+        z[0] = x[0];
+        z[1] = x[1];
+        z[2] = x[2];
+        z[3] = x[3];
+        z[4] = x[4];
+        z[5] = x[5];
+        z[6] = x[6];
+        z[7] = x[7];
+    }
+
+    public static void copy(int[] x, int xOff, int[] z, int zOff)
+    {
+        z[zOff + 0] = x[xOff + 0];
+        z[zOff + 1] = x[xOff + 1];
+        z[zOff + 2] = x[xOff + 2];
+        z[zOff + 3] = x[xOff + 3];
+        z[zOff + 4] = x[xOff + 4];
+        z[zOff + 5] = x[xOff + 5];
+        z[zOff + 6] = x[xOff + 6];
+        z[zOff + 7] = x[xOff + 7];
+    }
+
+    public static void copy64(long[] x, long[] z)
+    {
+        z[0] = x[0];
+        z[1] = x[1];
+        z[2] = x[2];
+        z[3] = x[3];
+    }
+
+    public static void copy64(long[] x, int xOff, long[] z, int zOff)
+    {
+        z[zOff + 0] = x[xOff + 0];
+        z[zOff + 1] = x[xOff + 1];
+        z[zOff + 2] = x[xOff + 2];
+        z[zOff + 3] = x[xOff + 3];
+    }
+
+    public static int[] create()
+    {
+        return new int[8];
+    }
+
+    public static long[] create64()
+    {
+        return new long[4];
+    }
+
+    public static int[] createExt()
+    {
+        return new int[16];
+    }
+
+    public static long[] createExt64()
+    {
+        return new long[8];
+    }
+
+    public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        boolean pos = gte(x, xOff, y, yOff);
+        if (pos)
+        {
+            sub(x, xOff, y, yOff, z, zOff);
+        }
+        else
+        {
+            sub(y, yOff, x, xOff, z, zOff);
+        }
+        return pos;
+    }
+
+    public static boolean eq(int[] x, int[] y)
+    {
+        for (int i = 7; i >= 0; --i)
+        {
+            if (x[i] != y[i])
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean eq64(long[] x, long[] y)
+    {
+        for (int i = 3; i >= 0; --i)
+        {
+            if (x[i] != y[i])
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static int[] fromBigInteger(BigInteger x)
+    {
+        if (x.signum() < 0 || x.bitLength() > 256)
+        {
+            throw new IllegalArgumentException();
+        }
+
+        int[] z = create();
+        int i = 0;
+        while (x.signum() != 0)
+        {
+            z[i++] = x.intValue();
+            x = x.shiftRight(32);
+        }
+        return z;
+    }
+
+    public static long[] fromBigInteger64(BigInteger x)
+    {
+        if (x.signum() < 0 || x.bitLength() > 256)
+        {
+            throw new IllegalArgumentException();
+        }
+
+        long[] z = create64();
+        int i = 0;
+        while (x.signum() != 0)
+        {
+            z[i++] = x.longValue();
+            x = x.shiftRight(64);
+        }
+        return z;
+    }
+
+    public static int getBit(int[] x, int bit)
+    {
+        if (bit == 0)
+        {
+            return x[0] & 1;
+        }
+        if ((bit & 255) != bit)
+        {
+            return 0;
+        }
+        int w = bit >>> 5;
+        int b = bit & 31;
+        return (x[w] >>> b) & 1;
+    }
+
+    public static boolean gte(int[] x, int[] y)
+    {
+        for (int i = 7; i >= 0; --i)
+        {
+            int x_i = x[i] ^ Integer.MIN_VALUE;
+            int y_i = y[i] ^ Integer.MIN_VALUE;
+            if (x_i < y_i)
+                return false;
+            if (x_i > y_i)
+                return true;
+        }
+        return true;
+    }
+
+    public static boolean gte(int[] x, int xOff, int[] y, int yOff)
+    {
+        for (int i = 7; i >= 0; --i)
+        {
+            int x_i = x[xOff + i] ^ Integer.MIN_VALUE;
+            int y_i = y[yOff + i] ^ Integer.MIN_VALUE;
+            if (x_i < y_i)
+                return false;
+            if (x_i > y_i)
+                return true;
+        }
+        return true;
+    }
+
+    public static boolean isOne(int[] x)
+    {
+        if (x[0] != 1)
+        {
+            return false;
+        }
+        for (int i = 1; i < 8; ++i)
+        {
+            if (x[i] != 0)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isOne64(long[] x)
+    {
+        if (x[0] != 1L)
+        {
+            return false;
+        }
+        for (int i = 1; i < 4; ++i)
+        {
+            if (x[i] != 0L)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isZero(int[] x)
+    {
+        for (int i = 0; i < 8; ++i)
+        {
+            if (x[i] != 0)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isZero64(long[] x)
+    {
+        for (int i = 0; i < 4; ++i)
+        {
+            if (x[i] != 0L)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static void mul(int[] x, int[] y, int[] zz)
+    {
+        long y_0 = y[0] & M;
+        long y_1 = y[1] & M;
+        long y_2 = y[2] & M;
+        long y_3 = y[3] & M;
+        long y_4 = y[4] & M;
+        long y_5 = y[5] & M;
+        long y_6 = y[6] & M;
+        long y_7 = y[7] & M;
+
+        {
+            long c = 0, x_0 = x[0] & M;
+            c += x_0 * y_0;
+            zz[0] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_1;
+            zz[1] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_2;
+            zz[2] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_3;
+            zz[3] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_4;
+            zz[4] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_5;
+            zz[5] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_6;
+            zz[6] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_7;
+            zz[7] = (int)c;
+            c >>>= 32;
+            zz[8] = (int)c;
+        }
+
+        for (int i = 1; i < 8; ++i)
+        {
+            long c = 0, x_i = x[i] & M;
+            c += x_i * y_0 + (zz[i + 0] & M);
+            zz[i + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[i + 1] & M);
+            zz[i + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[i + 2] & M);
+            zz[i + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[i + 3] & M);
+            zz[i + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[i + 4] & M);
+            zz[i + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[i + 5] & M);
+            zz[i + 5] = (int)c;
+            c >>>= 32;
+            c += x_i * y_6 + (zz[i + 6] & M);
+            zz[i + 6] = (int)c;
+            c >>>= 32;
+            c += x_i * y_7 + (zz[i + 7] & M);
+            zz[i + 7] = (int)c;
+            c >>>= 32;
+            zz[i + 8] = (int)c;
+        }
+    }
+
+    public static void mul(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+    {
+        long y_0 = y[yOff + 0] & M;
+        long y_1 = y[yOff + 1] & M;
+        long y_2 = y[yOff + 2] & M;
+        long y_3 = y[yOff + 3] & M;
+        long y_4 = y[yOff + 4] & M;
+        long y_5 = y[yOff + 5] & M;
+        long y_6 = y[yOff + 6] & M;
+        long y_7 = y[yOff + 7] & M;
+
+        {
+            long c = 0, x_0 = x[xOff + 0] & M;
+            c += x_0 * y_0;
+            zz[zzOff + 0] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_1;
+            zz[zzOff + 1] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_2;
+            zz[zzOff + 2] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_3;
+            zz[zzOff + 3] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_4;
+            zz[zzOff + 4] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_5;
+            zz[zzOff + 5] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_6;
+            zz[zzOff + 6] = (int)c;
+            c >>>= 32;
+            c += x_0 * y_7;
+            zz[zzOff + 7] = (int)c;
+            c >>>= 32;
+            zz[zzOff + 8] = (int)c;
+        }
+
+        for (int i = 1; i < 8; ++i)
+        {
+            ++zzOff;
+            long c = 0, x_i = x[xOff + i] & M;
+            c += x_i * y_0 + (zz[zzOff + 0] & M);
+            zz[zzOff + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[zzOff + 1] & M);
+            zz[zzOff + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[zzOff + 2] & M);
+            zz[zzOff + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[zzOff + 3] & M);
+            zz[zzOff + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[zzOff + 4] & M);
+            zz[zzOff + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[zzOff + 5] & M);
+            zz[zzOff + 5] = (int)c;
+            c >>>= 32;
+            c += x_i * y_6 + (zz[zzOff + 6] & M);
+            zz[zzOff + 6] = (int)c;
+            c >>>= 32;
+            c += x_i * y_7 + (zz[zzOff + 7] & M);
+            zz[zzOff + 7] = (int)c;
+            c >>>= 32;
+            zz[zzOff + 8] = (int)c;
+        }
+    }
+
+    public static int mulAddTo(int[] x, int[] y, int[] zz)
+    {
+        long y_0 = y[0] & M;
+        long y_1 = y[1] & M;
+        long y_2 = y[2] & M;
+        long y_3 = y[3] & M;
+        long y_4 = y[4] & M;
+        long y_5 = y[5] & M;
+        long y_6 = y[6] & M;
+        long y_7 = y[7] & M;
+
+        long zc = 0;
+        for (int i = 0; i < 8; ++i)
+        {
+            long c = 0, x_i = x[i] & M;
+            c += x_i * y_0 + (zz[i + 0] & M);
+            zz[i + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[i + 1] & M);
+            zz[i + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[i + 2] & M);
+            zz[i + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[i + 3] & M);
+            zz[i + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[i + 4] & M);
+            zz[i + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[i + 5] & M);
+            zz[i + 5] = (int)c;
+            c >>>= 32;
+            c += x_i * y_6 + (zz[i + 6] & M);
+            zz[i + 6] = (int)c;
+            c >>>= 32;
+            c += x_i * y_7 + (zz[i + 7] & M);
+            zz[i + 7] = (int)c;
+            c >>>= 32;
+            c += zc + (zz[i + 8] & M);
+            zz[i + 8] = (int)c;
+            zc = c >>> 32;
+        }
+        return (int)zc;
+    }
+
+    public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff)
+    {
+        long y_0 = y[yOff + 0] & M;
+        long y_1 = y[yOff + 1] & M;
+        long y_2 = y[yOff + 2] & M;
+        long y_3 = y[yOff + 3] & M;
+        long y_4 = y[yOff + 4] & M;
+        long y_5 = y[yOff + 5] & M;
+        long y_6 = y[yOff + 6] & M;
+        long y_7 = y[yOff + 7] & M;
+
+        long zc = 0;
+        for (int i = 0; i < 8; ++i)
+        {
+            long c = 0, x_i = x[xOff + i] & M;
+            c += x_i * y_0 + (zz[zzOff + 0] & M);
+            zz[zzOff + 0] = (int)c;
+            c >>>= 32;
+            c += x_i * y_1 + (zz[zzOff + 1] & M);
+            zz[zzOff + 1] = (int)c;
+            c >>>= 32;
+            c += x_i * y_2 + (zz[zzOff + 2] & M);
+            zz[zzOff + 2] = (int)c;
+            c >>>= 32;
+            c += x_i * y_3 + (zz[zzOff + 3] & M);
+            zz[zzOff + 3] = (int)c;
+            c >>>= 32;
+            c += x_i * y_4 + (zz[zzOff + 4] & M);
+            zz[zzOff + 4] = (int)c;
+            c >>>= 32;
+            c += x_i * y_5 + (zz[zzOff + 5] & M);
+            zz[zzOff + 5] = (int)c;
+            c >>>= 32;
+            c += x_i * y_6 + (zz[zzOff + 6] & M);
+            zz[zzOff + 6] = (int)c;
+            c >>>= 32;
+            c += x_i * y_7 + (zz[zzOff + 7] & M);
+            zz[zzOff + 7] = (int)c;
+            c >>>= 32;
+            c += zc + (zz[zzOff + 8] & M);
+            zz[zzOff + 8] = (int)c;
+            zc = c >>> 32;
+            ++zzOff;
+        }
+        return (int)zc;
+    }
+
+    public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        // assert w >>> 31 == 0;
+
+        long c = 0, wVal = w & M;
+        long x0 = x[xOff + 0] & M;
+        c += wVal * x0 + (y[yOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        long x1 = x[xOff + 1] & M;
+        c += wVal * x1 + x0 + (y[yOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        long x2 = x[xOff + 2] & M;
+        c += wVal * x2 + x1 + (y[yOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        long x3 = x[xOff + 3] & M;
+        c += wVal * x3 + x2 + (y[yOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        long x4 = x[xOff + 4] & M;
+        c += wVal * x4 + x3 + (y[yOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        long x5 = x[xOff + 5] & M;
+        c += wVal * x5 + x4 + (y[yOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        long x6 = x[xOff + 6] & M;
+        c += wVal * x6 + x5 + (y[yOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>>= 32;
+        long x7 = x[xOff + 7] & M;
+        c += wVal * x7 + x6 + (y[yOff + 7] & M);
+        z[zOff + 7] = (int)c;
+        c >>>= 32;
+        c += x7;
+        return c;
+    }
+
+    public static int mulByWord(int x, int[] z)
+    {
+        long c = 0, xVal = x & M;
+        c += xVal * (z[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[6] & M);
+        z[6] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[7] & M);
+        z[7] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int mulByWordAddTo(int x, int[] y, int[] z)
+    {
+        long c = 0, xVal = x & M;
+        c += xVal * (z[0] & M) + (y[0] & M);
+        z[0] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[1] & M) + (y[1] & M);
+        z[1] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[2] & M) + (y[2] & M);
+        z[2] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[3] & M) + (y[3] & M);
+        z[3] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[4] & M) + (y[4] & M);
+        z[4] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[5] & M) + (y[5] & M);
+        z[5] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[6] & M) + (y[6] & M);
+        z[6] = (int)c;
+        c >>>= 32;
+        c += xVal * (z[7] & M) + (y[7] & M);
+        z[7] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int mulWordAddTo(int x, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0, xVal = x & M;
+        c += xVal * (y[yOff + 0] & M) + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 1] & M) + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 2] & M) + (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 3] & M) + (z[zOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 4] & M) + (z[zOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 5] & M) + (z[zOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 6] & M) + (z[zOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>>= 32;
+        c += xVal * (y[yOff + 7] & M) + (z[zOff + 7] & M);
+        z[zOff + 7] = (int)c;
+        c >>>= 32;
+        return (int)c;
+    }
+
+    public static int mul33DWordAdd(int x, long y, int[] z, int zOff)
+    {
+        // assert x >>> 31 == 0;
+        // assert zOff <= 4;
+
+        long c = 0, xVal = x & M;
+        long y00 = y & M;
+        c += xVal * y00 + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        long y01 = y >>> 32;
+        c += xVal * y01 + y00 + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += y01 + (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : Nat.incAt(8, z, zOff, 4);
+    }
+
+    public static int mul33WordAdd(int x, int y, int[] z, int zOff)
+    {
+        // assert x >>> 31 == 0;
+        // assert zOff <= 5;
+
+        long c = 0, xVal = x & M, yVal = y & M;
+        c += yVal * xVal + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += yVal + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : Nat.incAt(8, z, zOff, 3);
+    }
+
+    public static int mulWordDwordAdd(int x, long y, int[] z, int zOff)
+    {
+        // assert zOff <= 5;
+        long c = 0, xVal = x & M;
+        c += xVal * (y & M) + (z[zOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>>= 32;
+        c += xVal * (y >>> 32) + (z[zOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>>= 32;
+        c += (z[zOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>>= 32;
+        return c == 0 ? 0 : Nat.incAt(8, z, zOff, 3);
+    }
+
+    public static int mulWord(int x, int[] y, int[] z, int zOff)
+    {
+        long c = 0, xVal = x & M;
+        int i = 0;
+        do
+        {
+            c += xVal * (y[i] & M);
+            z[zOff + i] = (int)c;
+            c >>>= 32;
+        }
+        while (++i < 8);
+        return (int)c;
+    }
+
+    public static void square(int[] x, int[] zz)
+    {
+        long x_0 = x[0] & M;
+        long zz_1;
+
+        int c = 0, w;
+        {
+            int i = 7, j = 16;
+            do
+            {
+                long xVal = (x[i--] & M);
+                long p = xVal * xVal;
+                zz[--j] = (c << 31) | (int)(p >>> 33);
+                zz[--j] = (int)(p >>> 1);
+                c = (int)p;
+            }
+            while (i > 0);
+
+            {
+                long p = x_0 * x_0;
+                zz_1 = ((c << 31) & M) | (p >>> 33);
+                zz[0] = (int)p;
+                c = (int)(p >>> 32) & 1;
+            }
+        }
+
+        long x_1 = x[1] & M;
+        long zz_2 = zz[2] & M;
+
+        {
+            zz_1 += x_1 * x_0;
+            w = (int)zz_1;
+            zz[1] = (w << 1) | c;
+            c = w >>> 31;
+            zz_2 += zz_1 >>> 32;
+        }
+
+        long x_2 = x[2] & M;
+        long zz_3 = zz[3] & M;
+        long zz_4 = zz[4] & M;
+        {
+            zz_2 += x_2 * x_0;
+            w = (int)zz_2;
+            zz[2] = (w << 1) | c;
+            c = w >>> 31;
+            zz_3 += (zz_2 >>> 32) + x_2 * x_1;
+            zz_4 += zz_3 >>> 32;
+            zz_3 &= M;
+        }
+
+        long x_3 = x[3] & M;
+        long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M;
+        long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M;
+        {
+            zz_3 += x_3 * x_0;
+            w = (int)zz_3;
+            zz[3] = (w << 1) | c;
+            c = w >>> 31;
+            zz_4 += (zz_3 >>> 32) + x_3 * x_1;
+            zz_5 += (zz_4 >>> 32) + x_3 * x_2;
+            zz_4 &= M;
+            zz_6 += zz_5 >>> 32;
+            zz_5 &= M;
+        }
+
+        long x_4 = x[4] & M;
+        long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M;
+        long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M;
+        {
+            zz_4 += x_4 * x_0;
+            w = (int)zz_4;
+            zz[4] = (w << 1) | c;
+            c = w >>> 31;
+            zz_5 += (zz_4 >>> 32) + x_4 * x_1;
+            zz_6 += (zz_5 >>> 32) + x_4 * x_2;
+            zz_5 &= M;
+            zz_7 += (zz_6 >>> 32) + x_4 * x_3;
+            zz_6 &= M;
+            zz_8 += zz_7 >>> 32;
+            zz_7 &= M;
+        }
+
+        long x_5 = x[5] & M;
+        long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M;
+        long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M;
+        {
+            zz_5 += x_5 * x_0;
+            w = (int)zz_5;
+            zz[5] = (w << 1) | c;
+            c = w >>> 31;
+            zz_6 += (zz_5 >>> 32) + x_5 * x_1;
+            zz_7 += (zz_6 >>> 32) + x_5 * x_2;
+            zz_6 &= M;
+            zz_8 += (zz_7 >>> 32) + x_5 * x_3;
+            zz_7 &= M;
+            zz_9 += (zz_8 >>> 32) + x_5 * x_4;
+            zz_8 &= M;
+            zz_10 += zz_9 >>> 32;
+            zz_9 &= M;
+        }
+
+        long x_6 = x[6] & M;
+        long zz_11 = (zz[11] & M) + (zz_10 >>> 32); zz_10 &= M;
+        long zz_12 = (zz[12] & M) + (zz_11 >>> 32); zz_11 &= M;
+        {
+            zz_6 += x_6 * x_0;
+            w = (int)zz_6;
+            zz[6] = (w << 1) | c;
+            c = w >>> 31;
+            zz_7 += (zz_6 >>> 32) + x_6 * x_1;
+            zz_8 += (zz_7 >>> 32) + x_6 * x_2;
+            zz_7 &= M;
+            zz_9 += (zz_8 >>> 32) + x_6 * x_3;
+            zz_8 &= M;
+            zz_10 += (zz_9 >>> 32) + x_6 * x_4;
+            zz_9 &= M;
+            zz_11 += (zz_10 >>> 32) + x_6 * x_5;
+            zz_10 &= M;
+            zz_12 += zz_11 >>> 32;
+            zz_11 &= M;
+        }
+
+        long x_7 = x[7] & M;
+        long zz_13 = (zz[13] & M) + (zz_12 >>> 32); zz_12 &= M;
+        long zz_14 = (zz[14] & M) + (zz_13 >>> 32); zz_13 &= M;
+        {
+            zz_7 += x_7 * x_0;
+            w = (int)zz_7;
+            zz[7] = (w << 1) | c;
+            c = w >>> 31;
+            zz_8 += (zz_7 >>> 32) + x_7 * x_1;
+            zz_9 += (zz_8 >>> 32) + x_7 * x_2;
+            zz_10 += (zz_9 >>> 32) + x_7 * x_3;
+            zz_11 += (zz_10 >>> 32) + x_7 * x_4;
+            zz_12 += (zz_11 >>> 32) + x_7 * x_5;
+            zz_13 += (zz_12 >>> 32) + x_7 * x_6;
+            zz_14 += zz_13 >>> 32;
+        }
+
+        w = (int)zz_8;
+        zz[8] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_9;
+        zz[9] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_10;
+        zz[10] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_11;
+        zz[11] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_12;
+        zz[12] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_13;
+        zz[13] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_14;
+        zz[14] = (w << 1) | c;
+        c = w >>> 31;
+        w = zz[15] + (int)(zz_14 >>> 32);
+        zz[15] = (w << 1) | c;
+    }
+
+    public static void square(int[] x, int xOff, int[] zz, int zzOff)
+    {
+        long x_0 = x[xOff + 0] & M;
+        long zz_1;
+
+        int c = 0, w;
+        {
+            int i = 7, j = 16;
+            do
+            {
+                long xVal = (x[xOff + i--] & M);
+                long p = xVal * xVal;
+                zz[zzOff + --j] = (c << 31) | (int)(p >>> 33);
+                zz[zzOff + --j] = (int)(p >>> 1);
+                c = (int)p;
+            }
+            while (i > 0);
+
+            {
+                long p = x_0 * x_0;
+                zz_1 = ((c << 31) & M) | (p >>> 33);
+                zz[zzOff + 0] = (int)p;
+                c = (int)(p >>> 32) & 1;
+            }
+        }
+
+        long x_1 = x[xOff + 1] & M;
+        long zz_2 = zz[zzOff + 2] & M;
+
+        {
+            zz_1 += x_1 * x_0;
+            w = (int)zz_1;
+            zz[zzOff + 1] = (w << 1) | c;
+            c = w >>> 31;
+            zz_2 += zz_1 >>> 32;
+        }
+
+        long x_2 = x[xOff + 2] & M;
+        long zz_3 = zz[zzOff + 3] & M;
+        long zz_4 = zz[zzOff + 4] & M;
+        {
+            zz_2 += x_2 * x_0;
+            w = (int)zz_2;
+            zz[zzOff + 2] = (w << 1) | c;
+            c = w >>> 31;
+            zz_3 += (zz_2 >>> 32) + x_2 * x_1;
+            zz_4 += zz_3 >>> 32;
+            zz_3 &= M;
+        }
+
+        long x_3 = x[xOff + 3] & M;
+        long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M;
+        long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M;
+        {
+            zz_3 += x_3 * x_0;
+            w = (int)zz_3;
+            zz[zzOff + 3] = (w << 1) | c;
+            c = w >>> 31;
+            zz_4 += (zz_3 >>> 32) + x_3 * x_1;
+            zz_5 += (zz_4 >>> 32) + x_3 * x_2;
+            zz_4 &= M;
+            zz_6 += zz_5 >>> 32;
+            zz_5 &= M;
+        }
+
+        long x_4 = x[xOff + 4] & M;
+        long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M;
+        long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M;
+        {
+            zz_4 += x_4 * x_0;
+            w = (int)zz_4;
+            zz[zzOff + 4] = (w << 1) | c;
+            c = w >>> 31;
+            zz_5 += (zz_4 >>> 32) + x_4 * x_1;
+            zz_6 += (zz_5 >>> 32) + x_4 * x_2;
+            zz_5 &= M;
+            zz_7 += (zz_6 >>> 32) + x_4 * x_3;
+            zz_6 &= M;
+            zz_8 += zz_7 >>> 32;
+            zz_7 &= M;
+        }
+
+        long x_5 = x[xOff + 5] & M;
+        long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M;
+        long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M;
+        {
+            zz_5 += x_5 * x_0;
+            w = (int)zz_5;
+            zz[zzOff + 5] = (w << 1) | c;
+            c = w >>> 31;
+            zz_6 += (zz_5 >>> 32) + x_5 * x_1;
+            zz_7 += (zz_6 >>> 32) + x_5 * x_2;
+            zz_6 &= M;
+            zz_8 += (zz_7 >>> 32) + x_5 * x_3;
+            zz_7 &= M;
+            zz_9 += (zz_8 >>> 32) + x_5 * x_4;
+            zz_8 &= M;
+            zz_10 += zz_9 >>> 32;
+            zz_9 &= M;
+        }
+
+        long x_6 = x[xOff + 6] & M;
+        long zz_11 = (zz[zzOff + 11] & M) + (zz_10 >>> 32); zz_10 &= M;
+        long zz_12 = (zz[zzOff + 12] & M) + (zz_11 >>> 32); zz_11 &= M;
+        {
+            zz_6 += x_6 * x_0;
+            w = (int)zz_6;
+            zz[zzOff + 6] = (w << 1) | c;
+            c = w >>> 31;
+            zz_7 += (zz_6 >>> 32) + x_6 * x_1;
+            zz_8 += (zz_7 >>> 32) + x_6 * x_2;
+            zz_7 &= M;
+            zz_9 += (zz_8 >>> 32) + x_6 * x_3;
+            zz_8 &= M;
+            zz_10 += (zz_9 >>> 32) + x_6 * x_4;
+            zz_9 &= M;
+            zz_11 += (zz_10 >>> 32) + x_6 * x_5;
+            zz_10 &= M;
+            zz_12 += zz_11 >>> 32;
+            zz_11 &= M;
+        }
+
+        long x_7 = x[xOff + 7] & M;
+        long zz_13 = (zz[zzOff + 13] & M) + (zz_12 >>> 32); zz_12 &= M;
+        long zz_14 = (zz[zzOff + 14] & M) + (zz_13 >>> 32); zz_13 &= M;
+        {
+            zz_7 += x_7 * x_0;
+            w = (int)zz_7;
+            zz[zzOff + 7] = (w << 1) | c;
+            c = w >>> 31;
+            zz_8 += (zz_7 >>> 32) + x_7 * x_1;
+            zz_9 += (zz_8 >>> 32) + x_7 * x_2;
+            zz_10 += (zz_9 >>> 32) + x_7 * x_3;
+            zz_11 += (zz_10 >>> 32) + x_7 * x_4;
+            zz_12 += (zz_11 >>> 32) + x_7 * x_5;
+            zz_13 += (zz_12 >>> 32) + x_7 * x_6;
+            zz_14 += zz_13 >>> 32;
+        }
+
+        w = (int)zz_8;
+        zz[zzOff + 8] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_9;
+        zz[zzOff + 9] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_10;
+        zz[zzOff + 10] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_11;
+        zz[zzOff + 11] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_12;
+        zz[zzOff + 12] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_13;
+        zz[zzOff + 13] = (w << 1) | c;
+        c = w >>> 31;
+        w = (int)zz_14;
+        zz[zzOff + 14] = (w << 1) | c;
+        c = w >>> 31;
+        w = zz[zzOff + 15] + (int)(zz_14 >>> 32);
+        zz[zzOff + 15] = (w << 1) | c;
+    }
+
+    public static int sub(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (x[0] & M) - (y[0] & M);
+        z[0] = (int)c;
+        c >>= 32;
+        c += (x[1] & M) - (y[1] & M);
+        z[1] = (int)c;
+        c >>= 32;
+        c += (x[2] & M) - (y[2] & M);
+        z[2] = (int)c;
+        c >>= 32;
+        c += (x[3] & M) - (y[3] & M);
+        z[3] = (int)c;
+        c >>= 32;
+        c += (x[4] & M) - (y[4] & M);
+        z[4] = (int)c;
+        c >>= 32;
+        c += (x[5] & M) - (y[5] & M);
+        z[5] = (int)c;
+        c >>= 32;
+        c += (x[6] & M) - (y[6] & M);
+        z[6] = (int)c;
+        c >>= 32;
+        c += (x[7] & M) - (y[7] & M);
+        z[7] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int sub(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff)
+    {
+        long c = 0;
+        c += (x[xOff + 0] & M) - (y[yOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 1] & M) - (y[yOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 2] & M) - (y[yOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 3] & M) - (y[yOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 4] & M) - (y[yOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 5] & M) - (y[yOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 6] & M) - (y[yOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>= 32;
+        c += (x[xOff + 7] & M) - (y[yOff + 7] & M);
+        z[zOff + 7] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int subBothFrom(int[] x, int[] y, int[] z)
+    {
+        long c = 0;
+        c += (z[0] & M) - (x[0] & M) - (y[0] & M);
+        z[0] = (int)c;
+        c >>= 32;
+        c += (z[1] & M) - (x[1] & M) - (y[1] & M);
+        z[1] = (int)c;
+        c >>= 32;
+        c += (z[2] & M) - (x[2] & M) - (y[2] & M);
+        z[2] = (int)c;
+        c >>= 32;
+        c += (z[3] & M) - (x[3] & M) - (y[3] & M);
+        z[3] = (int)c;
+        c >>= 32;
+        c += (z[4] & M) - (x[4] & M) - (y[4] & M);
+        z[4] = (int)c;
+        c >>= 32;
+        c += (z[5] & M) - (x[5] & M) - (y[5] & M);
+        z[5] = (int)c;
+        c >>= 32;
+        c += (z[6] & M) - (x[6] & M) - (y[6] & M);
+        z[6] = (int)c;
+        c >>= 32;
+        c += (z[7] & M) - (x[7] & M) - (y[7] & M);
+        z[7] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int subFrom(int[] x, int[] z)
+    {
+        long c = 0;
+        c += (z[0] & M) - (x[0] & M);
+        z[0] = (int)c;
+        c >>= 32;
+        c += (z[1] & M) - (x[1] & M);
+        z[1] = (int)c;
+        c >>= 32;
+        c += (z[2] & M) - (x[2] & M);
+        z[2] = (int)c;
+        c >>= 32;
+        c += (z[3] & M) - (x[3] & M);
+        z[3] = (int)c;
+        c >>= 32;
+        c += (z[4] & M) - (x[4] & M);
+        z[4] = (int)c;
+        c >>= 32;
+        c += (z[5] & M) - (x[5] & M);
+        z[5] = (int)c;
+        c >>= 32;
+        c += (z[6] & M) - (x[6] & M);
+        z[6] = (int)c;
+        c >>= 32;
+        c += (z[7] & M) - (x[7] & M);
+        z[7] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static int subFrom(int[] x, int xOff, int[] z, int zOff)
+    {
+        long c = 0;
+        c += (z[zOff + 0] & M) - (x[xOff + 0] & M);
+        z[zOff + 0] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 1] & M) - (x[xOff + 1] & M);
+        z[zOff + 1] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 2] & M) - (x[xOff + 2] & M);
+        z[zOff + 2] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 3] & M) - (x[xOff + 3] & M);
+        z[zOff + 3] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 4] & M) - (x[xOff + 4] & M);
+        z[zOff + 4] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 5] & M) - (x[xOff + 5] & M);
+        z[zOff + 5] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 6] & M) - (x[xOff + 6] & M);
+        z[zOff + 6] = (int)c;
+        c >>= 32;
+        c += (z[zOff + 7] & M) - (x[xOff + 7] & M);
+        z[zOff + 7] = (int)c;
+        c >>= 32;
+        return (int)c;
+    }
+
+    public static BigInteger toBigInteger(int[] x)
+    {
+        byte[] bs = new byte[32];
+        for (int i = 0; i < 8; ++i)
+        {
+            int x_i = x[i];
+            if (x_i != 0)
+            {
+                Pack.intToBigEndian(x_i, bs, (7 - i) << 2);
+            }
+        }
+        return new BigInteger(1, bs);
+    }
+
+    public static BigInteger toBigInteger64(long[] x)
+    {
+        byte[] bs = new byte[32];
+        for (int i = 0; i < 4; ++i)
+        {
+            long x_i = x[i];
+            if (x_i != 0L)
+            {
+                Pack.longToBigEndian(x_i, bs, (3 - i) << 3);
+            }
+        }
+        return new BigInteger(1, bs);
+    }
+
+    public static void zero(int[] z)
+    {
+        z[0] = 0;
+        z[1] = 0;
+        z[2] = 0;
+        z[3] = 0;
+        z[4] = 0;
+        z[5] = 0;
+        z[6] = 0;
+        z[7] = 0;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat384.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat384.java
new file mode 100644
index 0000000..6bb1b17
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat384.java
@@ -0,0 +1,47 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.raw;
+
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class Nat384
+{
+    public static void mul(int[] x, int[] y, int[] zz)
+    {
+        Nat192.mul(x, y, zz);
+        Nat192.mul(x, 6, y, 6, zz, 12);
+
+        int c18 = Nat192.addToEachOther(zz, 6, zz, 12);
+        int c12 = c18 + Nat192.addTo(zz, 0, zz, 6, 0);
+        c18 += Nat192.addTo(zz, 18, zz, 12, c12);
+
+        int[] dx = Nat192.create(), dy = Nat192.create();
+        boolean neg = Nat192.diff(x, 6, x, 0, dx, 0) != Nat192.diff(y, 6, y, 0, dy, 0);
+
+        int[] tt = Nat192.createExt();
+        Nat192.mul(dx, dy, tt);
+
+        c18 += neg ? Nat.addTo(12, tt, 0, zz, 6) : Nat.subFrom(12, tt, 0, zz, 6);
+        Nat.addWordAt(24, c18, zz, 18); 
+    }
+
+    public static void square(int[] x, int[] zz)
+    {
+        Nat192.square(x, zz);
+        Nat192.square(x, 6, zz, 12);
+
+        int c18 = Nat192.addToEachOther(zz, 6, zz, 12);
+        int c12 = c18 + Nat192.addTo(zz, 0, zz, 6, 0);
+        c18 += Nat192.addTo(zz, 18, zz, 12, c12);
+
+        int[] dx = Nat192.create();
+        Nat192.diff(x, 6, x, 0, dx, 0);
+
+        int[] tt = Nat192.createExt();
+        Nat192.square(dx, tt);
+
+        c18 += Nat.subFrom(12, tt, 0, zz, 6);
+        Nat.addWordAt(24, c18, zz, 18); 
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat512.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat512.java
new file mode 100644
index 0000000..bf4d5ac
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/math/raw/Nat512.java
@@ -0,0 +1,47 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.math.raw;
+
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class Nat512
+{
+    public static void mul(int[] x, int[] y, int[] zz)
+    {
+        Nat256.mul(x, y, zz);
+        Nat256.mul(x, 8, y, 8, zz, 16);
+
+        int c24 = Nat256.addToEachOther(zz, 8, zz, 16);
+        int c16 = c24 + Nat256.addTo(zz, 0, zz, 8, 0);
+        c24 += Nat256.addTo(zz, 24, zz, 16, c16);
+
+        int[] dx = Nat256.create(), dy = Nat256.create();
+        boolean neg = Nat256.diff(x, 8, x, 0, dx, 0) != Nat256.diff(y, 8, y, 0, dy, 0);
+
+        int[] tt = Nat256.createExt();
+        Nat256.mul(dx, dy, tt);
+
+        c24 += neg ? Nat.addTo(16, tt, 0, zz, 8) : Nat.subFrom(16, tt, 0, zz, 8);
+        Nat.addWordAt(32, c24, zz, 24); 
+    }
+
+    public static void square(int[] x, int[] zz)
+    {
+        Nat256.square(x, zz);
+        Nat256.square(x, 8, zz, 16);
+
+        int c24 = Nat256.addToEachOther(zz, 8, zz, 16);
+        int c16 = c24 + Nat256.addTo(zz, 0, zz, 8, 0);
+        c24 += Nat256.addTo(zz, 24, zz, 16, c16);
+
+        int[] dx = Nat256.create();
+        Nat256.diff(x, 8, x, 0, dx, 0);
+
+        int[] tt = Nat256.createExt();
+        Nat256.square(dx, tt);
+
+        c24 += Nat.subFrom(16, tt, 0, zz, 8);
+        Nat.addWordAt(32, c24, zz, 24); 
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Arrays.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Arrays.java
new file mode 100644
index 0000000..f83b0ca
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Arrays.java
@@ -0,0 +1,1297 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+import java.math.BigInteger;
+import java.util.NoSuchElementException;
+
+/**
+ * General array utilities.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class Arrays
+{
+    private Arrays()
+    {
+        // static class, hide constructor
+    }
+
+    public static boolean areAllZeroes(byte[] buf, int off, int len)
+    {
+        int bits = 0;
+        for (int i = 0; i < len; ++i)
+        {
+            bits |= buf[off + i];
+        }
+        return bits == 0;
+    }
+
+    public static boolean areEqual(
+        boolean[]  a,
+        boolean[]  b)
+    {
+        if (a == b)
+        {
+            return true;
+        }
+
+        if (a == null || b == null)
+        {
+            return false;
+        }
+
+        if (a.length != b.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != a.length; i++)
+        {
+            if (a[i] != b[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean areEqual(
+        char[]  a,
+        char[]  b)
+    {
+        if (a == b)
+        {
+            return true;
+        }
+
+        if (a == null || b == null)
+        {
+            return false;
+        }
+
+        if (a.length != b.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != a.length; i++)
+        {
+            if (a[i] != b[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean areEqual(
+        byte[]  a,
+        byte[]  b)
+    {
+        if (a == b)
+        {
+            return true;
+        }
+
+        if (a == null || b == null)
+        {
+            return false;
+        }
+
+        if (a.length != b.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != a.length; i++)
+        {
+            if (a[i] != b[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean areEqual(
+        short[]  a,
+        short[]  b)
+    {
+        if (a == b)
+        {
+            return true;
+        }
+
+        if (a == null || b == null)
+        {
+            return false;
+        }
+
+        if (a.length != b.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != a.length; i++)
+        {
+            if (a[i] != b[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * A constant time equals comparison - does not terminate early if
+     * test will fail. For best results always pass the expected value
+     * as the first parameter.
+     *
+     * @param expected first array
+     * @param supplied second array
+     * @return true if arrays equal, false otherwise.
+     */
+    public static boolean constantTimeAreEqual(
+        byte[]  expected,
+        byte[]  supplied)
+    {
+        if (expected == supplied)
+        {
+            return true;
+        }
+
+        if (expected == null || supplied == null)
+        {
+            return false;
+        }
+
+        if (expected.length != supplied.length)
+        {
+            return !Arrays.constantTimeAreEqual(expected, expected);
+        }
+
+        int nonEqual = 0;
+
+        for (int i = 0; i != expected.length; i++)
+        {
+            nonEqual |= (expected[i] ^ supplied[i]);
+        }
+
+        return nonEqual == 0;
+    }
+
+    public static boolean areEqual(
+        int[]  a,
+        int[]  b)
+    {
+        if (a == b)
+        {
+            return true;
+        }
+
+        if (a == null || b == null)
+        {
+            return false;
+        }
+
+        if (a.length != b.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != a.length; i++)
+        {
+            if (a[i] != b[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean areEqual(
+        long[]  a,
+        long[]  b)
+    {
+        if (a == b)
+        {
+            return true;
+        }
+
+        if (a == null || b == null)
+        {
+            return false;
+        }
+
+        if (a.length != b.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != a.length; i++)
+        {
+            if (a[i] != b[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean areEqual(Object[] a, Object[] b)
+    {
+        if (a == b)
+        {
+            return true;
+        }
+        if (a == null || b == null)
+        {
+            return false;
+        }
+        if (a.length != b.length)
+        {
+            return false;
+        }
+        for (int i = 0; i != a.length; i++)
+        {
+            Object objA = a[i], objB = b[i];
+            if (objA == null)
+            {
+                if (objB != null)
+                {
+                    return false;
+                }
+            }
+            else if (!objA.equals(objB))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static int compareUnsigned(byte[] a, byte[] b)
+    {
+        if (a == b)
+        {
+            return 0;
+        }
+        if (a == null)
+        {
+            return -1;
+        }
+        if (b == null)
+        {
+            return 1;
+        }
+        int minLen = Math.min(a.length, b.length);
+        for (int i = 0; i < minLen; ++i)
+        {
+            int aVal = a[i] & 0xFF, bVal = b[i] & 0xFF;
+            if (aVal < bVal)
+            {
+                return -1;
+            }
+            if (aVal > bVal)
+            {
+                return 1;
+            }
+        }
+        if (a.length < b.length)
+        {
+            return -1;
+        }
+        if (a.length > b.length)
+        {
+            return 1;
+        }
+        return 0;
+    }
+
+    public static boolean contains(short[] a, short n)
+    {
+        for (int i = 0; i < a.length; ++i)
+        {
+            if (a[i] == n)
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean contains(int[] a, int n)
+    {
+        for (int i = 0; i < a.length; ++i)
+        {
+            if (a[i] == n)
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static void fill(
+        byte[] array,
+        byte value)
+    {
+        for (int i = 0; i < array.length; i++)
+        {
+            array[i] = value;
+        }
+    }
+
+    public static void fill(
+        byte[] array,
+        int start,
+        int finish,
+        byte value)
+    {
+        for (int i = start; i < finish; i++)
+        {
+            array[i] = value;
+        }
+    }
+
+    public static void fill(
+        char[] array,
+        char value)
+    {
+        for (int i = 0; i < array.length; i++)
+        {
+            array[i] = value;
+        }
+    }
+
+    public static void fill(
+        long[] array,
+        long value)
+    {
+        for (int i = 0; i < array.length; i++)
+        {
+            array[i] = value;
+        }
+    }
+
+    public static void fill(
+        short[] array,
+        short value)
+    {
+        for (int i = 0; i < array.length; i++)
+        {
+            array[i] = value;
+        }
+    }
+
+    public static void fill(
+        int[] array,
+        int value)
+    {
+        for (int i = 0; i < array.length; i++)
+        {
+            array[i] = value;
+        }
+    }
+
+    public static void fill(
+        byte[] array,
+        int out,
+        byte value)
+    {
+        if(out < array.length)
+        {
+            for (int i = out; i < array.length; i++)
+            {
+                array[i] = value;
+            }
+        }
+    }
+
+    public static void fill(
+        int[] array,
+        int out,
+        int value)
+    {
+        if(out < array.length)
+        {
+            for (int i = out; i < array.length; i++)
+            {
+                array[i] = value;
+            }
+        }
+    }
+
+    public static void fill(
+        short[] array,
+        int out,
+        short value)
+    {
+        if(out < array.length)
+        {
+            for (int i = out; i < array.length; i++)
+            {
+                array[i] = value;
+            }
+        }
+    }
+
+    public static void fill(
+        long[] array,
+        int out,
+        long value)
+    {
+        if(out < array.length)
+        {
+            for (int i = out; i < array.length; i++)
+            {
+                array[i] = value;
+            }
+        }
+    }
+
+    public static int hashCode(byte[] data)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = data.length;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            hc *= 257;
+            hc ^= data[i];
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(byte[] data, int off, int len)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = len;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            hc *= 257;
+            hc ^= data[off + i];
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(char[] data)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = data.length;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            hc *= 257;
+            hc ^= data[i];
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(int[][] ints)
+    {
+        int hc = 0;
+
+        for (int i = 0; i != ints.length; i++)
+        {
+            hc = hc * 257 + hashCode(ints[i]);
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(int[] data)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = data.length;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            hc *= 257;
+            hc ^= data[i];
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(int[] data, int off, int len)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = len;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            hc *= 257;
+            hc ^= data[off + i];
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(long[] data)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = data.length;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            long di = data[i];
+            hc *= 257;
+            hc ^= (int)di;
+            hc *= 257;
+            hc ^= (int)(di >>> 32);
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(long[] data, int off, int len)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = len;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            long di = data[off + i];
+            hc *= 257;
+            hc ^= (int)di;
+            hc *= 257;
+            hc ^= (int)(di >>> 32);
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(short[][][] shorts)
+    {
+        int hc = 0;
+
+        for (int i = 0; i != shorts.length; i++)
+        {
+            hc = hc * 257 + hashCode(shorts[i]);
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(short[][] shorts)
+    {
+        int hc = 0;
+
+        for (int i = 0; i != shorts.length; i++)
+        {
+            hc = hc * 257 + hashCode(shorts[i]);
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(short[] data)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = data.length;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            hc *= 257;
+            hc ^= (data[i] & 0xff);
+        }
+
+        return hc;
+    }
+
+    public static int hashCode(Object[] data)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        int i = data.length;
+        int hc = i + 1;
+
+        while (--i >= 0)
+        {
+            hc *= 257;
+            hc ^= data[i].hashCode();
+        }
+
+        return hc;
+    }
+
+    public static byte[] clone(byte[] data)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        byte[] copy = new byte[data.length];
+
+        System.arraycopy(data, 0, copy, 0, data.length);
+
+        return copy;
+    }
+
+    public static char[] clone(char[] data)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        char[] copy = new char[data.length];
+
+        System.arraycopy(data, 0, copy, 0, data.length);
+
+        return copy;
+    }
+
+    public static byte[] clone(byte[] data, byte[] existing)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        if ((existing == null) || (existing.length != data.length))
+        {
+            return clone(data);
+        }
+        System.arraycopy(data, 0, existing, 0, existing.length);
+        return existing;
+    }
+
+    public static byte[][] clone(byte[][] data)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+
+        byte[][] copy = new byte[data.length][];
+
+        for (int i = 0; i != copy.length; i++)
+        {
+            copy[i] = clone(data[i]);
+        }
+
+        return copy;
+    }
+
+    public static byte[][][] clone(byte[][][] data)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+
+        byte[][][] copy = new byte[data.length][][];
+
+        for (int i = 0; i != copy.length; i++)
+        {
+            copy[i] = clone(data[i]);
+        }
+
+        return copy;
+    }
+
+    public static int[] clone(int[] data)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        int[] copy = new int[data.length];
+
+        System.arraycopy(data, 0, copy, 0, data.length);
+
+        return copy;
+    }
+
+    public static long[] clone(long[] data)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        long[] copy = new long[data.length];
+
+        System.arraycopy(data, 0, copy, 0, data.length);
+
+        return copy;
+    }
+
+    public static long[] clone(long[] data, long[] existing)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        if ((existing == null) || (existing.length != data.length))
+        {
+            return clone(data);
+        }
+        System.arraycopy(data, 0, existing, 0, existing.length);
+        return existing;
+    }
+
+    public static short[] clone(short[] data)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        short[] copy = new short[data.length];
+
+        System.arraycopy(data, 0, copy, 0, data.length);
+
+        return copy;
+    }
+
+    public static BigInteger[] clone(BigInteger[] data)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        BigInteger[] copy = new BigInteger[data.length];
+
+        System.arraycopy(data, 0, copy, 0, data.length);
+
+        return copy;
+    }
+
+    public static byte[] copyOf(byte[] data, int newLength)
+    {
+        byte[] tmp = new byte[newLength];
+
+        if (newLength < data.length)
+        {
+            System.arraycopy(data, 0, tmp, 0, newLength);
+        }
+        else
+        {
+            System.arraycopy(data, 0, tmp, 0, data.length);
+        }
+
+        return tmp;
+    }
+
+    public static char[] copyOf(char[] data, int newLength)
+    {
+        char[] tmp = new char[newLength];
+
+        if (newLength < data.length)
+        {
+            System.arraycopy(data, 0, tmp, 0, newLength);
+        }
+        else
+        {
+            System.arraycopy(data, 0, tmp, 0, data.length);
+        }
+
+        return tmp;
+    }
+
+    public static int[] copyOf(int[] data, int newLength)
+    {
+        int[] tmp = new int[newLength];
+
+        if (newLength < data.length)
+        {
+            System.arraycopy(data, 0, tmp, 0, newLength);
+        }
+        else
+        {
+            System.arraycopy(data, 0, tmp, 0, data.length);
+        }
+
+        return tmp;
+    }
+
+    public static long[] copyOf(long[] data, int newLength)
+    {
+        long[] tmp = new long[newLength];
+
+        if (newLength < data.length)
+        {
+            System.arraycopy(data, 0, tmp, 0, newLength);
+        }
+        else
+        {
+            System.arraycopy(data, 0, tmp, 0, data.length);
+        }
+
+        return tmp;
+    }
+
+    public static BigInteger[] copyOf(BigInteger[] data, int newLength)
+    {
+        BigInteger[] tmp = new BigInteger[newLength];
+
+        if (newLength < data.length)
+        {
+            System.arraycopy(data, 0, tmp, 0, newLength);
+        }
+        else
+        {
+            System.arraycopy(data, 0, tmp, 0, data.length);
+        }
+
+        return tmp;
+    }
+
+    /**
+     * Make a copy of a range of bytes from the passed in data array. The range can
+     * extend beyond the end of the input array, in which case the return array will
+     * be padded with zeroes.
+     *
+     * @param data the array from which the data is to be copied.
+     * @param from the start index at which the copying should take place.
+     * @param to the final index of the range (exclusive).
+     *
+     * @return a new byte array containing the range given.
+     */
+    public static byte[] copyOfRange(byte[] data, int from, int to)
+    {
+        int newLength = getLength(from, to);
+
+        byte[] tmp = new byte[newLength];
+
+        if (data.length - from < newLength)
+        {
+            System.arraycopy(data, from, tmp, 0, data.length - from);
+        }
+        else
+        {
+            System.arraycopy(data, from, tmp, 0, newLength);
+        }
+
+        return tmp;
+    }
+
+    public static int[] copyOfRange(int[] data, int from, int to)
+    {
+        int newLength = getLength(from, to);
+
+        int[] tmp = new int[newLength];
+
+        if (data.length - from < newLength)
+        {
+            System.arraycopy(data, from, tmp, 0, data.length - from);
+        }
+        else
+        {
+            System.arraycopy(data, from, tmp, 0, newLength);
+        }
+
+        return tmp;
+    }
+
+    public static long[] copyOfRange(long[] data, int from, int to)
+    {
+        int newLength = getLength(from, to);
+
+        long[] tmp = new long[newLength];
+
+        if (data.length - from < newLength)
+        {
+            System.arraycopy(data, from, tmp, 0, data.length - from);
+        }
+        else
+        {
+            System.arraycopy(data, from, tmp, 0, newLength);
+        }
+
+        return tmp;
+    }
+
+    public static BigInteger[] copyOfRange(BigInteger[] data, int from, int to)
+    {
+        int newLength = getLength(from, to);
+
+        BigInteger[] tmp = new BigInteger[newLength];
+
+        if (data.length - from < newLength)
+        {
+            System.arraycopy(data, from, tmp, 0, data.length - from);
+        }
+        else
+        {
+            System.arraycopy(data, from, tmp, 0, newLength);
+        }
+
+        return tmp;
+    }
+
+    private static int getLength(int from, int to)
+    {
+        int newLength = to - from;
+        if (newLength < 0)
+        {
+            StringBuffer sb = new StringBuffer(from);
+            sb.append(" > ").append(to);
+            throw new IllegalArgumentException(sb.toString());
+        }
+        return newLength;
+    }
+
+    public static byte[] append(byte[] a, byte b)
+    {
+        if (a == null)
+        {
+            return new byte[]{ b };
+        }
+
+        int length = a.length;
+        byte[] result = new byte[length + 1];
+        System.arraycopy(a, 0, result, 0, length);
+        result[length] = b;
+        return result;
+    }
+
+    public static short[] append(short[] a, short b)
+    {
+        if (a == null)
+        {
+            return new short[]{ b };
+        }
+
+        int length = a.length;
+        short[] result = new short[length + 1];
+        System.arraycopy(a, 0, result, 0, length);
+        result[length] = b;
+        return result;
+    }
+
+    public static int[] append(int[] a, int b)
+    {
+        if (a == null)
+        {
+            return new int[]{ b };
+        }
+
+        int length = a.length;
+        int[] result = new int[length + 1];
+        System.arraycopy(a, 0, result, 0, length);
+        result[length] = b;
+        return result;
+    }
+
+    public static String[] append(String[] a, String b)
+    {
+        if (a == null)
+        {
+            return new String[]{ b };
+        }
+
+        int length = a.length;
+        String[] result = new String[length + 1];
+        System.arraycopy(a, 0, result, 0, length);
+        result[length] = b;
+        return result;
+    }
+
+
+
+    public static byte[] concatenate(byte[] a, byte[] b)
+    {
+        if (a != null && b != null)
+        {
+            byte[] rv = new byte[a.length + b.length];
+
+            System.arraycopy(a, 0, rv, 0, a.length);
+            System.arraycopy(b, 0, rv, a.length, b.length);
+
+            return rv;
+        }
+        else if (b != null)
+        {
+            return clone(b);
+        }
+        else
+        {
+            return clone(a);
+        }
+    }
+
+    public static byte[] concatenate(byte[] a, byte[] b, byte[] c)
+    {
+        if (a != null && b != null && c != null)
+        {
+            byte[] rv = new byte[a.length + b.length + c.length];
+
+            System.arraycopy(a, 0, rv, 0, a.length);
+            System.arraycopy(b, 0, rv, a.length, b.length);
+            System.arraycopy(c, 0, rv, a.length + b.length, c.length);
+
+            return rv;
+        }
+        else if (a == null)
+        {
+            return concatenate(b, c);
+        }
+        else if (b == null)
+        {
+            return concatenate(a, c);
+        }
+        else
+        {
+            return concatenate(a, b);
+        }
+    }
+
+    public static byte[] concatenate(byte[] a, byte[] b, byte[] c, byte[] d)
+    {
+        if (a != null && b != null && c != null && d != null)
+        {
+            byte[] rv = new byte[a.length + b.length + c.length + d.length];
+
+            System.arraycopy(a, 0, rv, 0, a.length);
+            System.arraycopy(b, 0, rv, a.length, b.length);
+            System.arraycopy(c, 0, rv, a.length + b.length, c.length);
+            System.arraycopy(d, 0, rv, a.length + b.length + c.length, d.length);
+
+            return rv;
+        }
+        else if (d == null)
+        {
+            return concatenate(a, b, c);
+        }
+        else if (c == null)
+        {
+            return concatenate(a, b, d);
+        }
+        else if (b == null)
+        {
+            return concatenate(a, c, d);
+        }
+        else
+        {
+            return concatenate(b, c, d);
+        }
+    }
+
+    public static byte[] concatenate(byte[][] arrays)
+    {
+        int size = 0;
+        for (int i = 0; i != arrays.length; i++)
+        {
+            size += arrays[i].length;
+        }
+
+        byte[] rv = new byte[size];
+
+        int offSet = 0;
+        for (int i = 0; i != arrays.length; i++)
+        {
+            System.arraycopy(arrays[i], 0, rv, offSet, arrays[i].length);
+            offSet += arrays[i].length;
+        }
+
+        return rv;
+    }
+
+    public static int[] concatenate(int[] a, int[] b)
+    {
+        if (a == null)
+        {
+            return clone(b);
+        }
+        if (b == null)
+        {
+            return clone(a);
+        }
+
+        int[] c = new int[a.length + b.length];
+        System.arraycopy(a, 0, c, 0, a.length);
+        System.arraycopy(b, 0, c, a.length, b.length);
+        return c;
+    }
+
+    public static byte[] prepend(byte[] a, byte b)
+    {
+        if (a == null)
+        {
+            return new byte[]{ b };
+        }
+
+        int length = a.length;
+        byte[] result = new byte[length + 1];
+        System.arraycopy(a, 0, result, 1, length);
+        result[0] = b;
+        return result;
+    }
+
+    public static short[] prepend(short[] a, short b)
+    {
+        if (a == null)
+        {
+            return new short[]{ b };
+        }
+
+        int length = a.length;
+        short[] result = new short[length + 1];
+        System.arraycopy(a, 0, result, 1, length);
+        result[0] = b;
+        return result;
+    }
+
+    public static int[] prepend(int[] a, int b)
+    {
+        if (a == null)
+        {
+            return new int[]{ b };
+        }
+
+        int length = a.length;
+        int[] result = new int[length + 1];
+        System.arraycopy(a, 0, result, 1, length);
+        result[0] = b;
+        return result;
+    }
+
+    public static byte[] reverse(byte[] a)
+    {
+        if (a == null)
+        {
+            return null;
+        }
+
+        int p1 = 0, p2 = a.length;
+        byte[] result = new byte[p2];
+
+        while (--p2 >= 0)
+        {
+            result[p2] = a[p1++];
+        }
+
+        return result;
+    }
+
+    public static int[] reverse(int[] a)
+    {
+        if (a == null)
+        {
+            return null;
+        }
+
+        int p1 = 0, p2 = a.length;
+        int[] result = new int[p2];
+
+        while (--p2 >= 0)
+        {
+            result[p2] = a[p1++];
+        }
+
+        return result;
+    }
+
+    /**
+     * Iterator backed by a specific array.
+     * @hide This class is not part of the Android public SDK API
+     */
+    public static class Iterator<T>
+        implements java.util.Iterator<T>
+    {
+        private final T[] dataArray;
+
+        private int position = 0;
+
+        /**
+         * Base constructor.
+         * <p>
+         * Note: the array is not cloned, changes to it will affect the values returned by next().
+         * </p>
+         *
+         * @param dataArray array backing the iterator.
+         */
+        public Iterator(T[] dataArray)
+        {
+            this.dataArray = dataArray;
+        }
+
+        public boolean hasNext()
+        {
+            return position < dataArray.length;
+        }
+
+        public T next()
+        {
+            if (position == dataArray.length)
+            {
+                throw new NoSuchElementException("Out of elements: " + position);
+            }
+
+            return dataArray[position++];
+        }
+
+        public void remove()
+        {
+            throw new UnsupportedOperationException("Cannot remove element from an Array.");
+        }
+    }
+
+    /**
+     * Fill input array by zeros
+     *
+     * @param array input array
+     */
+    public static void clear(byte[] array)
+    {
+        if (array != null)
+        {
+            for (int i = 0; i < array.length; i++)
+            {
+                array[i] = 0;
+            }
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/BigIntegers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/BigIntegers.java
new file mode 100644
index 0000000..08ba17f
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/BigIntegers.java
@@ -0,0 +1,221 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * BigInteger utilities.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class BigIntegers
+{
+    public static final BigInteger ZERO = BigInteger.valueOf(0);
+    public static final BigInteger ONE = BigInteger.valueOf(1);
+
+    private static final BigInteger TWO = BigInteger.valueOf(2);
+    private static final BigInteger THREE = BigInteger.valueOf(3);
+
+    private static final int MAX_ITERATIONS = 1000;
+
+    /**
+     * Return the passed in value as an unsigned byte array.
+     * 
+     * @param value value to be converted.
+     * @return a byte array without a leading zero byte if present in the signed encoding.
+     */
+    public static byte[] asUnsignedByteArray(
+        BigInteger value)
+    {
+        byte[] bytes = value.toByteArray();
+        
+        if (bytes[0] == 0)
+        {
+            byte[] tmp = new byte[bytes.length - 1];
+            
+            System.arraycopy(bytes, 1, tmp, 0, tmp.length);
+            
+            return tmp;
+        }
+        
+        return bytes;
+    }
+
+    /**
+     * Return the passed in value as an unsigned byte array.
+     *
+     * @param value value to be converted.
+     * @return a byte array without a leading zero byte if present in the signed encoding.
+     */
+    public static byte[] asUnsignedByteArray(int length, BigInteger value)
+    {
+        byte[] bytes = value.toByteArray();
+        if (bytes.length == length)
+        {
+            return bytes;
+        }
+
+        int start = bytes[0] == 0 ? 1 : 0;
+        int count = bytes.length - start;
+
+        if (count > length)
+        {
+            throw new IllegalArgumentException("standard length exceeded for value");
+        }
+
+        byte[] tmp = new byte[length];
+        System.arraycopy(bytes, start, tmp, tmp.length - count, count);
+        return tmp;
+    }
+
+    /**
+     * Return a random BigInteger not less than 'min' and not greater than 'max'
+     * 
+     * @param min the least value that may be generated
+     * @param max the greatest value that may be generated
+     * @param random the source of randomness
+     * @return a random BigInteger value in the range [min,max]
+     */
+    public static BigInteger createRandomInRange(
+        BigInteger      min,
+        BigInteger      max,
+        SecureRandom    random)
+    {
+        int cmp = min.compareTo(max);
+        if (cmp >= 0)
+        {
+            if (cmp > 0)
+            {
+                throw new IllegalArgumentException("'min' may not be greater than 'max'");
+            }
+
+            return min;
+        }
+
+        if (min.bitLength() > max.bitLength() / 2)
+        {
+            return createRandomInRange(ZERO, max.subtract(min), random).add(min);
+        }
+
+        for (int i = 0; i < MAX_ITERATIONS; ++i)
+        {
+            BigInteger x = createRandomBigInteger(max.bitLength(), random);
+            if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0)
+            {
+                return x;
+            }
+        }
+
+        // fall back to a faster (restricted) method
+        return createRandomBigInteger(max.subtract(min).bitLength() - 1, random).add(min);
+    }
+
+    public static BigInteger fromUnsignedByteArray(byte[] buf)
+    {
+        return new BigInteger(1, buf);
+    }
+
+    public static BigInteger fromUnsignedByteArray(byte[] buf, int off, int length)
+    {
+        byte[] mag = buf;
+        if (off != 0 || length != buf.length)
+        {
+            mag = new byte[length];
+            System.arraycopy(buf, off, mag, 0, length);
+        }
+        return new BigInteger(1, mag);
+    }
+
+    public static int getUnsignedByteLength(BigInteger n)
+    {
+        return (n.bitLength() + 7) / 8;
+    }
+
+    /**
+     * Return a positive BigInteger in the range of 0 to 2**bitLength - 1.
+     *
+     * @param bitLength maximum bit length for the generated BigInteger.
+     * @param random a source of randomness.
+     * @return a positive BigInteger
+     */
+    public static BigInteger createRandomBigInteger(int bitLength, SecureRandom random)
+    {
+        return new BigInteger(1, createRandom(bitLength, random));
+    }
+
+    // Hexadecimal value of the product of the 131 smallest odd primes from 3 to 743
+    private static final BigInteger SMALL_PRIMES_PRODUCT = new BigInteger(
+              "8138e8a0fcf3a4e84a771d40fd305d7f4aa59306d7251de54d98af8fe95729a1f"
+            + "73d893fa424cd2edc8636a6c3285e022b0e3866a565ae8108eed8591cd4fe8d2"
+            + "ce86165a978d719ebf647f362d33fca29cd179fb42401cbaf3df0c614056f9c8"
+            + "f3cfd51e474afb6bc6974f78db8aba8e9e517fded658591ab7502bd41849462f",
+        16);
+    private static final int SQR_MAX_SMALL = 20; // bitlength of 743 * 743
+
+    /**
+     * Return a prime number candidate of the specified bit length.
+     *
+     * @param bitLength bit length for the generated BigInteger.
+     * @param random a source of randomness.
+     * @return a positive BigInteger of numBits length
+     */
+    public static BigInteger createRandomPrime(int bitLength, int certainty, SecureRandom random)
+    {
+        if (bitLength < 2)
+        {
+            throw new IllegalArgumentException("bitLength < 2");
+        }
+
+        BigInteger rv;
+
+        if (bitLength == 2)
+        {
+            return (random.nextInt() < 0) ? TWO : THREE;
+        }
+
+        do
+        {
+            byte[] base = createRandom(bitLength, random);
+
+            int xBits = 8 * base.length - bitLength;
+            byte lead = (byte)(1 << (7 - xBits));
+
+            // ensure top and bottom bit set
+            base[0] |= lead;
+            base[base.length - 1] |= 0x01;
+
+            rv = new BigInteger(1, base);
+            if (bitLength > SQR_MAX_SMALL)
+            {
+                while (!rv.gcd(SMALL_PRIMES_PRODUCT).equals(ONE))
+                {
+                    rv = rv.add(TWO);
+                }
+            }
+        }
+        while (!rv.isProbablePrime(certainty));
+
+        return rv;
+    }
+
+    private static byte[] createRandom(int bitLength, SecureRandom random)
+        throws IllegalArgumentException
+    {
+        if (bitLength < 1)
+        {
+            throw new IllegalArgumentException("bitLength must be at least 1");
+        }
+
+        int nBytes = (bitLength + 7) / 8;
+
+        byte[] rv = new byte[nBytes];
+
+        random.nextBytes(rv);
+
+        // strip off any excess bits in the MSB
+        int xBits = 8 * nBytes - bitLength;
+        rv[0] &= (byte)(255 >>> xBits);
+
+        return rv;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/CollectionStore.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/CollectionStore.java
new file mode 100644
index 0000000..f1c1c3b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/CollectionStore.java
@@ -0,0 +1,64 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A simple collection backed store.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class CollectionStore<T>
+    implements Store<T>, Iterable<T>
+{
+    private Collection<T> _local;
+
+    /**
+     * Basic constructor.
+     *
+     * @param collection - initial contents for the store, this is copied.
+     */
+    public CollectionStore(
+        Collection<T> collection)
+    {
+        _local = new ArrayList<T>(collection);
+    }
+
+    /**
+     * Return the matches in the collection for the passed in selector.
+     *
+     * @param selector the selector to match against.
+     * @return a possibly empty collection of matching objects.
+     */
+    public Collection<T> getMatches(Selector<T> selector)
+    {
+        if (selector == null)
+        {
+            return new ArrayList<T>(_local);
+        }
+        else
+        {
+            List<T> col = new ArrayList<T>();
+            Iterator<T> iter = _local.iterator();
+
+            while (iter.hasNext())
+            {
+                T obj = iter.next();
+
+                if (selector.match(obj))
+                {
+                    col.add(obj);
+                }
+            }
+
+            return col;
+        }
+    }
+
+    public Iterator<T> iterator()
+    {
+        return getMatches(null).iterator();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Encodable.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Encodable.java
new file mode 100644
index 0000000..5cdbe5a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Encodable.java
@@ -0,0 +1,20 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+import java.io.IOException;
+
+/**
+ * Interface implemented by objects that can be converted into byte arrays.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Encodable
+{
+    /**
+     * Return a byte array representing the implementing object.
+     *
+     * @return a byte array representing the encoding.
+     * @throws java.io.IOException if an issue arises generation the encoding.
+     */
+    byte[] getEncoded()
+        throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Fingerprint.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Fingerprint.java
new file mode 100644
index 0000000..21bdf6b
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Fingerprint.java
@@ -0,0 +1,182 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+// Android-changed: Use Android digests
+// import org.bouncycastle.crypto.digests.SHA512tDigest;
+// import org.bouncycastle.crypto.digests.SHAKEDigest;
+import com.android.internal.org.bouncycastle.crypto.Digest;
+import com.android.internal.org.bouncycastle.crypto.digests.AndroidDigestFactory;
+
+/**
+ * Basic 20 byte finger print class.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Fingerprint
+{
+    private static char[] encodingTable =
+    {
+        '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+    };
+
+    private final byte[] fingerprint;
+
+    /**
+     * Base constructor - use SHAKE-256 (160 bits). This is the recommended one as it is also
+     * produced by the FIPS API.
+     *
+     * @param source original data to calculate the fingerprint from.
+     */
+    public Fingerprint(byte[] source)
+    {
+        this(source, 160);
+    }
+
+    /**
+     * Constructor with length - use SHAKE-256 (bitLength bits). This is the recommended one as it is also
+     * produced by the FIPS API.
+     *
+     * @param source original data to calculate the fingerprint from.
+     */
+    public Fingerprint(byte[] source, int bitLength)
+    {
+        this.fingerprint = calculateFingerprint(source, bitLength);
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /*
+    /**
+     * Base constructor - for backwards compatibility.
+     *
+     * @param source original data to calculate the fingerprint from.
+     * @param useSHA512t use the old SHA512/160 calculation.
+     * @deprecated use the SHAKE only version.
+     *
+    public Fingerprint(byte[] source, boolean useSHA512t)
+    {
+        if (useSHA512t)
+        {
+            this.fingerprint = calculateFingerprintSHA512_160(source);
+        }
+        else
+        {
+            this.fingerprint = calculateFingerprint(source);
+        }
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+
+    public byte[] getFingerprint()
+    {
+        return Arrays.clone(fingerprint);
+    }
+
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i != fingerprint.length; i++)
+        {
+            if (i > 0)
+            {
+                sb.append(":");
+            }
+            sb.append(encodingTable[(fingerprint[i] >>> 4) & 0xf]);
+            sb.append(encodingTable[fingerprint[i] & 0x0f]);
+        }
+
+        return sb.toString();
+    }
+
+    public boolean equals(Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+        if (o instanceof Fingerprint)
+        {
+            return Arrays.areEqual(((Fingerprint)o).fingerprint, fingerprint);
+        }
+
+        return false;
+    }
+
+    public int hashCode()
+    {
+        return Arrays.hashCode(fingerprint);
+    }
+
+    /**
+     * Return a byte array containing a calculated fingerprint for the passed in input data.
+     * This calculation is compatible with the BC FIPS API.
+     *
+     * @param input data to base the fingerprint on.
+     * @return a byte array containing a 160 bit fingerprint.
+     */
+    public static byte[] calculateFingerprint(byte[] input)
+    {
+        return calculateFingerprint(input, 160);
+    }
+
+    /*
+    /**
+     * Return a byte array containing a calculated fingerprint for the passed in input data.
+     * This calculation is compatible with the BC FIPS API.
+     *
+     * @param input data to base the fingerprint on.
+     * @param bitLength bit length of finger print to be produced.
+     * @return a byte array containing a 20 byte fingerprint.
+     */
+    public static byte[] calculateFingerprint(byte[] input, int bitLength)
+    {
+        if (bitLength % 8 != 0)
+        {
+            throw new IllegalArgumentException("bitLength must be a multiple of 8");
+        }
+
+        // Android-changed: Use SHA-256 instead of SHAKE-256, since we don't support SHAKE
+        // SHAKEDigest digest = new SHAKEDigest(256);
+        Digest digest = AndroidDigestFactory.getSHA256();
+
+        digest.update(input, 0, input.length);
+
+        byte[] rv = new byte[bitLength / 8];
+
+        // Android-changed: Hash and truncate since SHA-256 doesn't support variable length output
+        //
+        // digest.doFinal(rv, 0, bitLength / 8);
+        byte[] untruncated = new byte[32];
+        digest.doFinal(untruncated, 0);
+        if ((bitLength / 8) >= 32) {
+            return untruncated;
+        }
+
+        System.arraycopy(untruncated, 0, rv, 0, rv.length);
+
+        return rv;
+    }
+
+    // BEGIN Android-removed: Unsupported algorithms
+    /**
+     * Return a byte array containing a calculated fingerprint for the passed in input data.
+     * The fingerprint is based on SHA512/160.
+     *
+     * @param input data to base the fingerprint on.
+     * @return a byte array containing a 20 byte fingerprint.
+     * @deprecated use the SHAKE based version.
+     *
+    public static byte[] calculateFingerprintSHA512_160(byte[] input)
+    {
+        SHA512tDigest digest = new SHA512tDigest(160);
+
+        digest.update(input, 0, input.length);
+
+        byte[] rv = new byte[digest.getDigestSize()];
+
+        digest.doFinal(rv, 0);
+
+        return rv;
+    }
+    */
+    // END Android-removed: Unsupported algorithms
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/IPAddress.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/IPAddress.java
new file mode 100644
index 0000000..47c159a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/IPAddress.java
@@ -0,0 +1,193 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+/**
+ * Utility methods for processing String objects containing IP addresses.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class IPAddress
+{
+    /**
+     * Validate the given IPv4 or IPv6 address.
+     *
+     * @param address the IP address as a String.
+     *
+     * @return true if a valid address, false otherwise
+     */
+    public static boolean isValid(
+        String address)
+    {
+        return isValidIPv4(address) || isValidIPv6(address);
+    }
+
+    /**
+     * Validate the given IPv4 or IPv6 address and netmask.
+     *
+     * @param address the IP address as a String.
+     *
+     * @return true if a valid address with netmask, false otherwise
+     */
+    public static boolean isValidWithNetMask(
+        String address)
+    {
+        return isValidIPv4WithNetmask(address) || isValidIPv6WithNetmask(address);
+    }
+
+    /**
+     * Validate the given IPv4 address.
+     * 
+     * @param address the IP address as a String.
+     *
+     * @return true if a valid IPv4 address, false otherwise
+     */
+    public static boolean isValidIPv4(
+        String address)
+    {
+        if (address.length() == 0)
+        {
+            return false;
+        }
+
+        int octet;
+        int octets = 0;
+        
+        String temp = address+".";
+
+        int pos;
+        int start = 0;
+        while (start < temp.length()
+            && (pos = temp.indexOf('.', start)) > start)
+        {
+            if (octets == 4)
+            {
+                return false;
+            }
+            try
+            {
+                octet = Integer.parseInt(temp.substring(start, pos));
+            }
+            catch (NumberFormatException ex)
+            {
+                return false;
+            }
+            if (octet < 0 || octet > 255)
+            {
+                return false;
+            }
+            start = pos + 1;
+            octets++;
+        }
+
+        return octets == 4;
+    }
+
+    public static boolean isValidIPv4WithNetmask(
+        String address)
+    {
+        int index = address.indexOf("/");
+        String mask = address.substring(index + 1);
+
+        return (index > 0) && isValidIPv4(address.substring(0, index))
+                           && (isValidIPv4(mask) || isMaskValue(mask, 32));
+    }
+
+    public static boolean isValidIPv6WithNetmask(
+        String address)
+    {
+        int index = address.indexOf("/");
+        String mask = address.substring(index + 1);
+
+        return (index > 0) && (isValidIPv6(address.substring(0, index))
+                           && (isValidIPv6(mask) || isMaskValue(mask, 128)));
+    }
+
+    private static boolean isMaskValue(String component, int size)
+    {
+        try
+        {
+            int value = Integer.parseInt(component);
+
+            return value >= 0 && value <= size;
+        }
+        catch (NumberFormatException e)
+        {
+            return false;
+        }
+    }
+
+    /**
+     * Validate the given IPv6 address.
+     *
+     * @param address the IP address as a String.
+     *
+     * @return true if a valid IPv6 address, false otherwise
+     */
+    public static boolean isValidIPv6(
+        String address)
+    {
+        if (address.length() == 0)
+        {
+            return false;
+        }
+
+        int octet;
+        int octets = 0;
+
+        String temp = address + ":";
+        boolean doubleColonFound = false;
+        int pos;
+        int start = 0;
+        while (start < temp.length()
+            && (pos = temp.indexOf(':', start)) >= start)
+        {
+            if (octets == 8)
+            {
+                return false;
+            }
+
+            if (start != pos)
+            {
+                String value = temp.substring(start, pos);
+
+                if (pos == (temp.length() - 1) && value.indexOf('.') > 0)
+                {
+                    if (!isValidIPv4(value))
+                    {
+                        return false;
+                    }
+
+                    octets++; // add an extra one as address covers 2 words.
+                }
+                else
+                {
+                    try
+                    {
+                        octet = Integer.parseInt(temp.substring(start, pos), 16);
+                    }
+                    catch (NumberFormatException ex)
+                    {
+                        return false;
+                    }
+                    if (octet < 0 || octet > 0xffff)
+                    {
+                        return false;
+                    }
+                }
+            }
+            else
+            {
+                if (pos != 1 && pos != temp.length() - 1 && doubleColonFound)
+                {
+                    return false;
+                }
+                doubleColonFound = true;
+            }
+            start = pos + 1;
+            octets++;
+        }
+
+        return octets == 8 || doubleColonFound;
+    }
+}
+
+
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Integers.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Integers.java
new file mode 100644
index 0000000..d5e348d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Integers.java
@@ -0,0 +1,24 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+/**
+ * Utility methods for ints.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Integers
+{
+    public static int rotateLeft(int i, int distance)
+    {
+        return Integer.rotateLeft(i, distance);
+    }
+
+    public static int rotateRight(int i, int distance)
+    {
+        return Integer.rotateRight(i, distance);
+    }
+
+    public static Integer valueOf(int value)
+    {
+        return Integer.valueOf(value);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Iterable.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Iterable.java
new file mode 100644
index 0000000..79094a1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Iterable.java
@@ -0,0 +1,19 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+import java.util.Iterator;
+
+/**
+ * Utility class to allow use of Iterable feature in JDK 1.5+
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Iterable<T>
+    extends java.lang.Iterable<T>
+{
+    /**
+     * Returns an iterator over a set of elements of type T.
+     *
+     * @return an Iterator.
+     */
+    Iterator<T> iterator();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Memoable.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Memoable.java
new file mode 100644
index 0000000..75ce09a
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Memoable.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+/**
+ * Interface for Memoable objects. Memoable objects allow the taking of a snapshot of their internal state
+ * via the copy() method and then reseting the object back to that state later using the reset() method.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Memoable
+{
+    /**
+     * Produce a copy of this object with its configuration and in its current state.
+     * <p>
+     * The returned object may be used simply to store the state, or may be used as a similar object
+     * starting from the copied state.
+     */
+    Memoable copy();
+
+    /**
+     * Restore a copied object state into this object.
+     * <p>
+     * Implementations of this method <em>should</em> try to avoid or minimise memory allocation to perform the reset.
+     *
+     * @param other an object originally {@link #copy() copied} from an object of the same type as this instance.
+     * @throws ClassCastException if the provided object is not of the correct type.
+     * @throws MemoableResetException if the <b>other</b> parameter is in some other way invalid.
+     */
+    void reset(Memoable other);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Pack.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Pack.java
new file mode 100644
index 0000000..dc149c1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Pack.java
@@ -0,0 +1,262 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+/**
+ * Utility methods for converting byte arrays into ints and longs, and back again.
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class Pack
+{
+    public static short bigEndianToShort(byte[] bs, int off)
+    {
+        int n = (bs[  off] & 0xff) << 8;
+        n |= (bs[++off] & 0xff);
+        return (short)n;
+    }
+
+    public static int bigEndianToInt(byte[] bs, int off)
+    {
+        int n = bs[  off] << 24;
+        n |= (bs[++off] & 0xff) << 16;
+        n |= (bs[++off] & 0xff) << 8;
+        n |= (bs[++off] & 0xff);
+        return n;
+    }
+
+    public static void bigEndianToInt(byte[] bs, int off, int[] ns)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            ns[i] = bigEndianToInt(bs, off);
+            off += 4;
+        }
+    }
+
+    public static byte[] intToBigEndian(int n)
+    {
+        byte[] bs = new byte[4];
+        intToBigEndian(n, bs, 0);
+        return bs;
+    }
+
+    public static void intToBigEndian(int n, byte[] bs, int off)
+    {
+        bs[  off] = (byte)(n >>> 24);
+        bs[++off] = (byte)(n >>> 16);
+        bs[++off] = (byte)(n >>>  8);
+        bs[++off] = (byte)(n       );
+    }
+
+    public static byte[] intToBigEndian(int[] ns)
+    {
+        byte[] bs = new byte[4 * ns.length];
+        intToBigEndian(ns, bs, 0);
+        return bs;
+    }
+
+    public static void intToBigEndian(int[] ns, byte[] bs, int off)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            intToBigEndian(ns[i], bs, off);
+            off += 4;
+        }
+    }
+
+    public static long bigEndianToLong(byte[] bs, int off)
+    {
+        int hi = bigEndianToInt(bs, off);
+        int lo = bigEndianToInt(bs, off + 4);
+        return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
+    }
+
+    public static void bigEndianToLong(byte[] bs, int off, long[] ns)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            ns[i] = bigEndianToLong(bs, off);
+            off += 8;
+        }
+    }
+
+    public static byte[] longToBigEndian(long n)
+    {
+        byte[] bs = new byte[8];
+        longToBigEndian(n, bs, 0);
+        return bs;
+    }
+
+    public static void longToBigEndian(long n, byte[] bs, int off)
+    {
+        intToBigEndian((int)(n >>> 32), bs, off);
+        intToBigEndian((int)(n & 0xffffffffL), bs, off + 4);
+    }
+
+    public static byte[] longToBigEndian(long[] ns)
+    {
+        byte[] bs = new byte[8 * ns.length];
+        longToBigEndian(ns, bs, 0);
+        return bs;
+    }
+
+    public static void longToBigEndian(long[] ns, byte[] bs, int off)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            longToBigEndian(ns[i], bs, off);
+            off += 8;
+        }
+    }
+
+    public static short littleEndianToShort(byte[] bs, int off)
+    {
+        int n = bs[  off] & 0xff;
+        n |= (bs[++off] & 0xff) << 8;
+        return (short)n;
+    }
+
+    public static int littleEndianToInt(byte[] bs, int off)
+    {
+        int n = bs[  off] & 0xff;
+        n |= (bs[++off] & 0xff) << 8;
+        n |= (bs[++off] & 0xff) << 16;
+        n |= bs[++off] << 24;
+        return n;
+    }
+
+    public static void littleEndianToInt(byte[] bs, int off, int[] ns)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            ns[i] = littleEndianToInt(bs, off);
+            off += 4;
+        }
+    }
+
+    public static void littleEndianToInt(byte[] bs, int bOff, int[] ns, int nOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            ns[nOff + i] = littleEndianToInt(bs, bOff);
+            bOff += 4;
+        }
+    }
+
+    public static int[] littleEndianToInt(byte[] bs, int off, int count)
+    {
+        int[] ns = new int[count];
+        for (int i = 0; i < ns.length; ++i)
+        {
+            ns[i] = littleEndianToInt(bs, off);
+            off += 4;
+        }
+        return ns;
+    }
+
+    public static byte[] shortToLittleEndian(short n)
+    {
+        byte[] bs = new byte[2];
+        shortToLittleEndian(n, bs, 0);
+        return bs;
+    }
+
+    public static void shortToLittleEndian(short n, byte[] bs, int off)
+    {
+        bs[  off] = (byte)(n       );
+        bs[++off] = (byte)(n >>>  8);
+    }
+
+    public static byte[] intToLittleEndian(int n)
+    {
+        byte[] bs = new byte[4];
+        intToLittleEndian(n, bs, 0);
+        return bs;
+    }
+
+    public static void intToLittleEndian(int n, byte[] bs, int off)
+    {
+        bs[  off] = (byte)(n       );
+        bs[++off] = (byte)(n >>>  8);
+        bs[++off] = (byte)(n >>> 16);
+        bs[++off] = (byte)(n >>> 24);
+    }
+
+    public static byte[] intToLittleEndian(int[] ns)
+    {
+        byte[] bs = new byte[4 * ns.length];
+        intToLittleEndian(ns, bs, 0);
+        return bs;
+    }
+
+    public static void intToLittleEndian(int[] ns, byte[] bs, int off)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            intToLittleEndian(ns[i], bs, off);
+            off += 4;
+        }
+    }
+
+    public static long littleEndianToLong(byte[] bs, int off)
+    {
+        int lo = littleEndianToInt(bs, off);
+        int hi = littleEndianToInt(bs, off + 4);
+        return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
+    }
+
+    public static void littleEndianToLong(byte[] bs, int off, long[] ns)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            ns[i] = littleEndianToLong(bs, off);
+            off += 8;
+        }
+    }
+
+    public static void littleEndianToLong(byte[] bs, int bsOff, long[] ns, int nsOff, int nsLen)
+    {
+        for (int i = 0; i < nsLen; ++i)
+        {
+            ns[nsOff + i] = littleEndianToLong(bs, bsOff);
+            bsOff += 8;
+        }
+    }
+
+    public static byte[] longToLittleEndian(long n)
+    {
+        byte[] bs = new byte[8];
+        longToLittleEndian(n, bs, 0);
+        return bs;
+    }
+
+    public static void longToLittleEndian(long n, byte[] bs, int off)
+    {
+        intToLittleEndian((int)(n & 0xffffffffL), bs, off);
+        intToLittleEndian((int)(n >>> 32), bs, off + 4);
+    }
+
+    public static byte[] longToLittleEndian(long[] ns)
+    {
+        byte[] bs = new byte[8 * ns.length];
+        longToLittleEndian(ns, bs, 0);
+        return bs;
+    }
+
+    public static void longToLittleEndian(long[] ns, byte[] bs, int off)
+    {
+        for (int i = 0; i < ns.length; ++i)
+        {
+            longToLittleEndian(ns[i], bs, off);
+            off += 8;
+        }
+    }
+
+    public static void longToLittleEndian(long[] ns, int nsOff, int nsLen, byte[] bs, int bsOff)
+    {
+        for (int i = 0; i < nsLen; ++i)
+        {
+            longToLittleEndian(ns[nsOff + i], bs, bsOff);
+            bsOff += 8;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Properties.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Properties.java
new file mode 100644
index 0000000..34b528c
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Properties.java
@@ -0,0 +1,153 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+import java.math.BigInteger;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * Utility method for accessing system properties.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Properties
+{
+    private Properties()
+    {
+
+    }
+
+    private static final ThreadLocal threadProperties = new ThreadLocal();
+                          
+    /**
+     * Return whether a particular override has been set to true.
+     *
+     * @param propertyName the property name for the override.
+     * @return true if the property is set to "true", false otherwise.
+     */
+    public static boolean isOverrideSet(String propertyName)
+    {
+        try
+        {
+            String p = fetchProperty(propertyName);
+
+            if (p != null)
+            {
+                return "true".equals(Strings.toLowerCase(p));
+            }
+
+            return false;
+        }
+        catch (AccessControlException e)
+        {
+            return false;
+        }
+    }
+
+    /**
+     * Enable the specified override property for the current thread only.
+     *
+     * @param propertyName the property name for the override.
+     * @param enable true if the override should be enabled, false if it should be disabled.
+     * @return true if the override was already set, false otherwise.
+     */
+    public static boolean setThreadOverride(String propertyName, boolean enable)
+    {
+        boolean isSet = isOverrideSet(propertyName);
+
+        Map localProps = (Map)threadProperties.get();
+        if (localProps == null)
+        {
+            localProps = new HashMap();
+        }
+
+        localProps.put(propertyName, enable ? "true" : "false");
+
+        threadProperties.set(localProps);
+
+        return isSet;
+    }
+
+    /**
+     * Enable the specified override property in the current thread only.
+     *
+     * @param propertyName the property name for the override.
+     * @return true if the override set true in thread local, false otherwise.
+     */
+    public static boolean removeThreadOverride(String propertyName)
+    {
+        boolean isSet = isOverrideSet(propertyName);
+
+        Map localProps = (Map)threadProperties.get();
+        if (localProps == null)
+        {
+            return false;
+        }
+
+        localProps.remove(propertyName);
+
+        if (localProps.isEmpty())
+        {
+            threadProperties.remove();
+        }
+        else
+        {
+            threadProperties.set(localProps);
+        }
+
+        return isSet;
+    }
+
+    public static BigInteger asBigInteger(String propertyName)
+    {
+        String p = fetchProperty(propertyName);
+
+        if (p != null)
+        {
+            return new BigInteger(p);
+        }
+
+        return null;
+    }
+
+    public static Set<String> asKeySet(String propertyName)
+    {
+        Set<String> set = new HashSet<String>();
+
+        String p = fetchProperty(propertyName);
+
+        if (p != null)
+        {
+            StringTokenizer sTok = new StringTokenizer(p, ",");
+            while (sTok.hasMoreElements())
+            {
+                set.add(Strings.toLowerCase(sTok.nextToken()).trim());
+            }
+        }
+
+        return Collections.unmodifiableSet(set);
+    }
+
+    private static String fetchProperty(final String propertyName)
+    {
+        return (String)AccessController.doPrivileged(new PrivilegedAction()
+        {
+            public Object run()
+            {
+                Map localProps = (Map)threadProperties.get();
+                if (localProps != null)
+                {
+                    return localProps.get(propertyName);
+                }
+
+                return System.getProperty(propertyName);
+            }
+        });
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Selector.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Selector.java
new file mode 100644
index 0000000..f36d121
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Selector.java
@@ -0,0 +1,22 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+/**
+ * Interface a selector from a store should conform to.
+ *
+ * @param <T> the type stored in the store.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Selector<T>
+    extends Cloneable
+{
+    /**
+     * Match the passed in object, returning true if it would be selected by this selector, false otherwise.
+     *
+     * @param obj the object to be matched.
+     * @return true if the object is a match for this selector, false otherwise.
+     */
+    boolean match(T obj);
+
+    Object clone();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Store.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Store.java
new file mode 100644
index 0000000..afbdea9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Store.java
@@ -0,0 +1,24 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+import java.util.Collection;
+
+/**
+ * A generic interface describing a simple store of objects.
+ *
+ * @param <T> the object type stored.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Store<T>
+{
+    /**
+     * Return a possibly empty collection of objects that match the criteria implemented
+     * in the passed in Selector.
+     *
+     * @param selector the selector defining the match criteria.
+     * @return a collection of matching objects, empty if none available.
+     * @throws StoreException if there is a failure during matching.
+     */
+    Collection<T> getMatches(Selector<T> selector)
+        throws StoreException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/StoreException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/StoreException.java
new file mode 100644
index 0000000..62f4020
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/StoreException.java
@@ -0,0 +1,29 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+/**
+ * Exception thrown if there's an issue doing a match in store.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class StoreException
+    extends RuntimeException
+{
+    private Throwable _e;
+
+    /**
+     * Basic Constructor.
+     *
+     * @param msg message to be associated with this exception.
+     * @param cause the throwable that caused this exception to be raised.
+     */
+    public StoreException(String msg, Throwable cause)
+    {
+        super(msg);
+        _e = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return _e;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/StringList.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/StringList.java
new file mode 100644
index 0000000..b73cc75
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/StringList.java
@@ -0,0 +1,44 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+/**
+ * An interface defining a list of strings.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface StringList
+    extends Iterable<String>
+{
+    /**
+     * Add a String to the list.
+     *
+     * @param s the String to add.
+     * @return true
+     */
+    boolean add(String s);
+
+    /**
+     * Get the string at index index.
+     *
+     * @param index the index position of the String of interest.
+     * @return the String at position index.
+     */
+    String get(int index);
+
+    int size();
+
+    /**
+     * Return the contents of the list as an array.
+     *
+     * @return an array of String.
+     */
+    String[] toStringArray();
+
+    /**
+     * Return a section of the contents of the list. If the list is too short the array is filled with nulls.
+     *
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     * @return an array of length to - from
+     */
+    String[] toStringArray(int from, int to);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Strings.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Strings.java
new file mode 100644
index 0000000..dfbc7f9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/Strings.java
@@ -0,0 +1,347 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Vector;
+
+import com.android.internal.org.bouncycastle.util.encoders.UTF8;
+
+/**
+ * String utilities.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class Strings
+{
+    private static String LINE_SEPARATOR;
+
+    static
+    {
+        try
+        {
+            LINE_SEPARATOR = AccessController.doPrivileged(new PrivilegedAction<String>()
+            {
+                public String run()
+                {
+                    // the easy way
+                    return System.getProperty("line.separator");
+                }
+            });
+
+        }
+        catch (Exception e)
+        {
+            try
+            {
+                // the harder way
+                LINE_SEPARATOR = String.format("%n");
+            }
+            catch (Exception ef)
+            {
+                LINE_SEPARATOR = "\n";   // we're desperate use this...
+            }
+        }
+    }
+
+    public static String fromUTF8ByteArray(byte[] bytes)
+    {
+        char[] chars = new char[bytes.length];
+        int len = UTF8.transcodeToUTF16(bytes, chars);
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Invalid UTF-8 input");
+        }
+        return new String(chars, 0, len);
+    }
+
+    public static byte[] toUTF8ByteArray(String string)
+    {
+        return toUTF8ByteArray(string.toCharArray());
+    }
+
+    public static byte[] toUTF8ByteArray(char[] string)
+    {
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+        try
+        {
+            toUTF8ByteArray(string, bOut);
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("cannot encode string to byte array!");
+        }
+
+        return bOut.toByteArray();
+    }
+
+    public static void toUTF8ByteArray(char[] string, OutputStream sOut)
+        throws IOException
+    {
+        char[] c = string;
+        int i = 0;
+
+        while (i < c.length)
+        {
+            char ch = c[i];
+
+            if (ch < 0x0080)
+            {
+                sOut.write(ch);
+            }
+            else if (ch < 0x0800)
+            {
+                sOut.write(0xc0 | (ch >> 6));
+                sOut.write(0x80 | (ch & 0x3f));
+            }
+            // surrogate pair
+            else if (ch >= 0xD800 && ch <= 0xDFFF)
+            {
+                // in error - can only happen, if the Java String class has a
+                // bug.
+                if (i + 1 >= c.length)
+                {
+                    throw new IllegalStateException("invalid UTF-16 codepoint");
+                }
+                char W1 = ch;
+                ch = c[++i];
+                char W2 = ch;
+                // in error - can only happen, if the Java String class has a
+                // bug.
+                if (W1 > 0xDBFF)
+                {
+                    throw new IllegalStateException("invalid UTF-16 codepoint");
+                }
+                int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000;
+                sOut.write(0xf0 | (codePoint >> 18));
+                sOut.write(0x80 | ((codePoint >> 12) & 0x3F));
+                sOut.write(0x80 | ((codePoint >> 6) & 0x3F));
+                sOut.write(0x80 | (codePoint & 0x3F));
+            }
+            else
+            {
+                sOut.write(0xe0 | (ch >> 12));
+                sOut.write(0x80 | ((ch >> 6) & 0x3F));
+                sOut.write(0x80 | (ch & 0x3F));
+            }
+
+            i++;
+        }
+    }
+
+    /**
+     * A locale independent version of toUpperCase.
+     *
+     * @param string input to be converted
+     * @return a US Ascii uppercase version
+     */
+    public static String toUpperCase(String string)
+    {
+        boolean changed = false;
+        char[] chars = string.toCharArray();
+
+        for (int i = 0; i != chars.length; i++)
+        {
+            char ch = chars[i];
+            if ('a' <= ch && 'z' >= ch)
+            {
+                changed = true;
+                chars[i] = (char)(ch - 'a' + 'A');
+            }
+        }
+
+        if (changed)
+        {
+            return new String(chars);
+        }
+
+        return string;
+    }
+
+    /**
+     * A locale independent version of toLowerCase.
+     *
+     * @param string input to be converted
+     * @return a US ASCII lowercase version
+     */
+    public static String toLowerCase(String string)
+    {
+        boolean changed = false;
+        char[] chars = string.toCharArray();
+
+        for (int i = 0; i != chars.length; i++)
+        {
+            char ch = chars[i];
+            if ('A' <= ch && 'Z' >= ch)
+            {
+                changed = true;
+                chars[i] = (char)(ch - 'A' + 'a');
+            }
+        }
+
+        if (changed)
+        {
+            return new String(chars);
+        }
+
+        return string;
+    }
+
+    public static byte[] toByteArray(char[] chars)
+    {
+        byte[] bytes = new byte[chars.length];
+
+        for (int i = 0; i != bytes.length; i++)
+        {
+            bytes[i] = (byte)chars[i];
+        }
+
+        return bytes;
+    }
+
+
+    public static byte[] toByteArray(String string)
+    {
+        byte[] bytes = new byte[string.length()];
+
+        for (int i = 0; i != bytes.length; i++)
+        {
+            char ch = string.charAt(i);
+
+            bytes[i] = (byte)ch;
+        }
+
+        return bytes;
+    }
+
+    public static int toByteArray(String s, byte[] buf, int off)
+    {
+        int count = s.length();
+        for (int i = 0; i < count; ++i)
+        {
+            char c = s.charAt(i);
+            buf[off + i] = (byte)c;
+        }
+        return count;
+    }
+
+    /**
+     * Convert an array of 8 bit characters into a string.
+     *
+     * @param bytes 8 bit characters.
+     * @return resulting String.
+     */
+    public static String fromByteArray(byte[] bytes)
+    {
+        return new String(asCharArray(bytes));
+    }
+
+    /**
+     * Do a simple conversion of an array of 8 bit characters into a string.
+     *
+     * @param bytes 8 bit characters.
+     * @return resulting String.
+     */
+    public static char[] asCharArray(byte[] bytes)
+    {
+        char[] chars = new char[bytes.length];
+
+        for (int i = 0; i != chars.length; i++)
+        {
+            chars[i] = (char)(bytes[i] & 0xff);
+        }
+
+        return chars;
+    }
+
+    public static String[] split(String input, char delimiter)
+    {
+        Vector v = new Vector();
+        boolean moreTokens = true;
+        String subString;
+
+        while (moreTokens)
+        {
+            int tokenLocation = input.indexOf(delimiter);
+            if (tokenLocation > 0)
+            {
+                subString = input.substring(0, tokenLocation);
+                v.addElement(subString);
+                input = input.substring(tokenLocation + 1);
+            }
+            else
+            {
+                moreTokens = false;
+                v.addElement(input);
+            }
+        }
+
+        String[] res = new String[v.size()];
+
+        for (int i = 0; i != res.length; i++)
+        {
+            res[i] = (String)v.elementAt(i);
+        }
+        return res;
+    }
+
+    public static StringList newList()
+    {
+        return new StringListImpl();
+    }
+
+    public static String lineSeparator()
+    {
+        return LINE_SEPARATOR;
+    }
+
+    private static class StringListImpl
+        extends ArrayList<String>
+        implements StringList
+    {
+        public boolean add(String s)
+        {
+            return super.add(s);
+        }
+
+        public String set(int index, String element)
+        {
+            return super.set(index, element);
+        }
+
+        public void add(int index, String element)
+        {
+            super.add(index, element);
+        }
+
+        public String[] toStringArray()
+        {
+            String[] strs = new String[this.size()];
+
+            for (int i = 0; i != strs.length; i++)
+            {
+                strs[i] = this.get(i);
+            }
+
+            return strs;
+        }
+
+        public String[] toStringArray(int from, int to)
+        {
+            String[] strs = new String[to - from];
+
+            for (int i = from; i != this.size() && i != to; i++)
+            {
+                strs[i - from] = this.get(i);
+            }
+
+            return strs;
+        }
+    }
+
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Base64.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Base64.java
new file mode 100644
index 0000000..fa5bebf
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Base64.java
@@ -0,0 +1,177 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * Utility class for converting Base64 data to bytes and back again.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Base64
+{
+    private static final Encoder encoder = new Base64Encoder();
+
+    public static String toBase64String(
+        byte[] data)
+    {
+        return toBase64String(data, 0, data.length);
+    }
+
+    public static String toBase64String(
+        byte[] data,
+        int off,
+        int length)
+    {
+        byte[] encoded = encode(data, off, length);
+        return Strings.fromByteArray(encoded);
+    }
+
+    /**
+     * encode the input data producing a base 64 encoded byte array.
+     *
+     * @return a byte array containing the base 64 encoded data.
+     */
+    public static byte[] encode(
+        byte[] data)
+    {
+        return encode(data, 0, data.length);
+    }
+
+    /**
+     * encode the input data producing a base 64 encoded byte array.
+     *
+     * @return a byte array containing the base 64 encoded data.
+     */
+    public static byte[] encode(
+        byte[] data,
+        int off,
+        int length)
+    {
+        int len = (length + 2) / 3 * 4;
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+        try
+        {
+            encoder.encode(data, off, length, bOut);
+        }
+        catch (Exception e)
+        {
+            throw new EncoderException("exception encoding base64 string: " + e.getMessage(), e);
+        }
+
+        return bOut.toByteArray();
+    }
+
+    /**
+     * Encode the byte data to base 64 writing it to the given output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int encode(
+        byte[] data,
+        OutputStream out)
+        throws IOException
+    {
+        return encoder.encode(data, 0, data.length, out);
+    }
+
+    /**
+     * Encode the byte data to base 64 writing it to the given output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int encode(
+        byte[] data,
+        int off,
+        int length,
+        OutputStream out)
+        throws IOException
+    {
+        return encoder.encode(data, off, length, out);
+    }
+
+    /**
+     * decode the base 64 encoded input data. It is assumed the input data is valid.
+     *
+     * @return a byte array representing the decoded data.
+     */
+    public static byte[] decode(
+        byte[] data)
+    {
+        int len = data.length / 4 * 3;
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+        try
+        {
+            encoder.decode(data, 0, data.length, bOut);
+        }
+        catch (Exception e)
+        {
+            throw new DecoderException("unable to decode base64 data: " + e.getMessage(), e);
+        }
+
+        return bOut.toByteArray();
+    }
+
+    /**
+     * decode the base 64 encoded String data - whitespace will be ignored.
+     *
+     * @return a byte array representing the decoded data.
+     */
+    public static byte[] decode(
+        String data)
+    {
+        int len = data.length() / 4 * 3;
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+        try
+        {
+            encoder.decode(data, bOut);
+        }
+        catch (Exception e)
+        {
+            throw new DecoderException("unable to decode base64 string: " + e.getMessage(), e);
+        }
+
+        return bOut.toByteArray();
+    }
+
+    /**
+     * decode the base 64 encoded String data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int decode(
+        String data,
+        OutputStream out)
+        throws IOException
+    {
+        return encoder.decode(data, out);
+    }
+
+    /**
+     * Decode to an output stream;
+     *
+     * @param base64Data       The source data.
+     * @param start            Start position.
+     * @param length           the length.
+     * @param out The output stream to write to.
+     */
+    public static int decode(byte[] base64Data, int start, int length, OutputStream out)
+    {
+        try
+        {
+           return encoder.decode(base64Data, start, length, out);
+        }
+        catch (Exception e)
+        {
+            throw new DecoderException("unable to decode base64 data: " + e.getMessage(), e);
+        }
+
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Base64Encoder.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Base64Encoder.java
new file mode 100644
index 0000000..e735008
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Base64Encoder.java
@@ -0,0 +1,380 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A streaming Base64 encoder.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Base64Encoder
+    implements Encoder
+{
+    protected final byte[] encodingTable =
+    {
+        (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+        (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+        (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+        (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+        (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+        (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+        (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+        (byte)'v',
+        (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+        (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
+        (byte)'7', (byte)'8', (byte)'9',
+        (byte)'+', (byte)'/'
+    };
+
+    protected byte    padding = (byte)'=';
+    
+    /*
+     * set up the decoding table.
+     */
+    protected final byte[] decodingTable = new byte[128];
+
+    protected void initialiseDecodingTable()
+    {
+        for (int i = 0; i < decodingTable.length; i++)
+        {
+            decodingTable[i] = (byte)0xff;
+        }
+        
+        for (int i = 0; i < encodingTable.length; i++)
+        {
+            decodingTable[encodingTable[i]] = (byte)i;
+        }
+    }
+    
+    public Base64Encoder()
+    {
+        initialiseDecodingTable();
+    }
+    
+    /**
+     * encode the input data producing a base 64 output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public int encode(
+        byte[]                data,
+        int                    off,
+        int                    length,
+        OutputStream    out) 
+        throws IOException
+    {
+        int modulus = length % 3;
+        int dataLength = (length - modulus);
+        int a1, a2, a3;
+        
+        for (int i = off; i < off + dataLength; i += 3)
+        {
+            a1 = data[i] & 0xff;
+            a2 = data[i + 1] & 0xff;
+            a3 = data[i + 2] & 0xff;
+
+            out.write(encodingTable[(a1 >>> 2) & 0x3f]);
+            out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
+            out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
+            out.write(encodingTable[a3 & 0x3f]);
+        }
+
+        /*
+         * process the tail end.
+         */
+        int    b1, b2, b3;
+        int    d1, d2;
+
+        switch (modulus)
+        {
+        case 0:        /* nothing left to do */
+            break;
+        case 1:
+            d1 = data[off + dataLength] & 0xff;
+            b1 = (d1 >>> 2) & 0x3f;
+            b2 = (d1 << 4) & 0x3f;
+
+            out.write(encodingTable[b1]);
+            out.write(encodingTable[b2]);
+            out.write(padding);
+            out.write(padding);
+            break;
+        case 2:
+            d1 = data[off + dataLength] & 0xff;
+            d2 = data[off + dataLength + 1] & 0xff;
+
+            b1 = (d1 >>> 2) & 0x3f;
+            b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
+            b3 = (d2 << 2) & 0x3f;
+
+            out.write(encodingTable[b1]);
+            out.write(encodingTable[b2]);
+            out.write(encodingTable[b3]);
+            out.write(padding);
+            break;
+        }
+
+        return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
+    }
+
+    private boolean ignore(
+        char    c)
+    {
+        return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
+    }
+    
+    /**
+     * decode the base 64 encoded byte data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public int decode(
+        byte[]          data,
+        int             off,
+        int             length,
+        OutputStream    out)
+        throws IOException
+    {
+        byte    b1, b2, b3, b4;
+        int     outLen = 0;
+        
+        int     end = off + length;
+        
+        while (end > off)
+        {
+            if (!ignore((char)data[end - 1]))
+            {
+                break;
+            }
+            
+            end--;
+        }
+
+        // empty data!
+        if (end == 0)
+        {
+            return 0;
+        }
+        
+        int  i = 0;
+        int  finish = end;
+
+        while (finish > off && i != 4)
+        {
+            if (!ignore((char)data[finish - 1]))
+            {
+                i++;
+            }
+
+            finish--;
+        }
+
+        i = nextI(data, off, finish);
+
+        while (i < finish)
+        {
+            b1 = decodingTable[data[i++]];
+            
+            i = nextI(data, i, finish);
+            
+            b2 = decodingTable[data[i++]];
+            
+            i = nextI(data, i, finish);
+            
+            b3 = decodingTable[data[i++]];
+            
+            i = nextI(data, i, finish);
+            
+            b4 = decodingTable[data[i++]];
+
+            if ((b1 | b2 | b3 | b4) < 0)
+            {
+                throw new IOException("invalid characters encountered in base64 data");
+            }
+            
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+            out.write((b3 << 6) | b4);
+            
+            outLen += 3;
+            
+            i = nextI(data, i, finish);
+        }
+
+        int e0 = nextI(data, i, end);
+        int e1 = nextI(data, e0 + 1, end);
+        int e2 = nextI(data, e1 + 1, end);
+        int e3 = nextI(data, e2 + 1, end);
+
+        outLen += decodeLastBlock(out, (char)data[e0], (char)data[e1], (char)data[e2], (char)data[e3]);
+
+        return outLen;
+    }
+
+    private int nextI(byte[] data, int i, int finish)
+    {
+        while ((i < finish) && ignore((char)data[i]))
+        {
+            i++;
+        }
+        return i;
+    }
+    
+    /**
+     * decode the base 64 encoded String data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public int decode(
+        String          data,
+        OutputStream    out)
+        throws IOException
+    {
+        byte    b1, b2, b3, b4;
+        int     length = 0;
+        
+        int     end = data.length();
+        
+        while (end > 0)
+        {
+            if (!ignore(data.charAt(end - 1)))
+            {
+                break;
+            }
+            
+            end--;
+        }
+
+        // empty data!
+        if (end == 0)
+        {
+            return 0;
+        }
+        
+        int  i = 0;
+        int  finish = end;
+
+        while (finish > 0 && i != 4)
+        {
+            if (!ignore(data.charAt(finish - 1)))
+            {
+                i++;
+            }
+
+            finish--;
+        }
+        
+        i = nextI(data, 0, finish);
+        
+        while (i < finish)
+        {
+            b1 = decodingTable[data.charAt(i++)];
+            
+            i = nextI(data, i, finish);
+            
+            b2 = decodingTable[data.charAt(i++)];
+            
+            i = nextI(data, i, finish);
+            
+            b3 = decodingTable[data.charAt(i++)];
+            
+            i = nextI(data, i, finish);
+            
+            b4 = decodingTable[data.charAt(i++)];
+
+            if ((b1 | b2 | b3 | b4) < 0)
+            {
+                throw new IOException("invalid characters encountered in base64 data");
+            }
+               
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+            out.write((b3 << 6) | b4);
+            
+            length += 3;
+            
+            i = nextI(data, i, finish);
+        }
+
+        int e0 = nextI(data, i, end);
+        int e1 = nextI(data, e0 + 1, end);
+        int e2 = nextI(data, e1 + 1, end);
+        int e3 = nextI(data, e2 + 1, end);
+
+        length += decodeLastBlock(out, data.charAt(e0), data.charAt(e1), data.charAt(e2), data.charAt(e3));
+        
+        return length;
+    }
+
+    private int decodeLastBlock(OutputStream out, char c1, char c2, char c3, char c4) 
+        throws IOException
+    {
+        byte    b1, b2, b3, b4;
+        
+        if (c3 == padding)
+        {
+            if (c4 != padding)
+            {
+                throw new IOException("invalid characters encountered at end of base64 data");
+            }
+            
+            b1 = decodingTable[c1];
+            b2 = decodingTable[c2];
+
+            if ((b1 | b2) < 0)
+            {
+                throw new IOException("invalid characters encountered at end of base64 data");
+            }
+
+            out.write((b1 << 2) | (b2 >> 4));
+            
+            return 1;
+        }
+        else if (c4 == padding)
+        {
+            b1 = decodingTable[c1];
+            b2 = decodingTable[c2];
+            b3 = decodingTable[c3];
+
+            if ((b1 | b2 | b3) < 0)
+            {
+                throw new IOException("invalid characters encountered at end of base64 data");
+            }
+            
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+            
+            return 2;
+        }
+        else
+        {
+            b1 = decodingTable[c1];
+            b2 = decodingTable[c2];
+            b3 = decodingTable[c3];
+            b4 = decodingTable[c4];
+
+            if ((b1 | b2 | b3 | b4) < 0)
+            {
+                throw new IOException("invalid characters encountered at end of base64 data");
+            }
+            
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+            out.write((b3 << 6) | b4);
+            
+            return 3;
+        } 
+    }
+
+    private int nextI(String data, int i, int finish)
+    {
+        while ((i < finish) && ignore(data.charAt(i)))
+        {
+            i++;
+        }
+        return i;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/DecoderException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/DecoderException.java
new file mode 100644
index 0000000..8ae8dc9
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/DecoderException.java
@@ -0,0 +1,24 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.encoders;
+
+/**
+ * Exception thrown if an attempt is made to decode invalid data, or some other failure occurs.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class DecoderException
+    extends IllegalStateException
+{
+    private Throwable cause;
+
+    DecoderException(String msg, Throwable cause)
+    {
+        super(msg);
+
+        this.cause = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Encoder.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Encoder.java
new file mode 100644
index 0000000..59a5114
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Encoder.java
@@ -0,0 +1,19 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Encode and decode byte arrays (typically from binary to 7-bit ASCII 
+ * encodings).
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface Encoder
+{
+    int encode(byte[] data, int off, int length, OutputStream out) throws IOException;
+    
+    int decode(byte[] data, int off, int length, OutputStream out) throws IOException;
+
+    int decode(String data, OutputStream out) throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/EncoderException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/EncoderException.java
new file mode 100644
index 0000000..eda43c7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/EncoderException.java
@@ -0,0 +1,24 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.encoders;
+
+/**
+ * Exception thrown if an attempt is made to encode invalid data, or some other failure occurs.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class EncoderException
+    extends IllegalStateException
+{
+    private Throwable cause;
+
+    EncoderException(String msg, Throwable cause)
+    {
+        super(msg);
+
+        this.cause = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Hex.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Hex.java
new file mode 100644
index 0000000..b73f57d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/Hex.java
@@ -0,0 +1,153 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import com.android.internal.org.bouncycastle.util.Strings;
+
+/**
+ * Utility class for converting hex data to bytes and back again.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class Hex
+{
+    private static final Encoder encoder = new HexEncoder();
+    
+    public static String toHexString(
+        byte[] data)
+    {
+        return toHexString(data, 0, data.length);
+    }
+
+    public static String toHexString(
+        byte[] data,
+        int    off,
+        int    length)
+    {
+        byte[] encoded = encode(data, off, length);
+        return Strings.fromByteArray(encoded);
+    }
+
+    /**
+     * encode the input data producing a Hex encoded byte array.
+     *
+     * @return a byte array containing the Hex encoded data.
+     */
+    public static byte[] encode(
+        byte[]    data)
+    {
+        return encode(data, 0, data.length);
+    }
+    
+    /**
+     * encode the input data producing a Hex encoded byte array.
+     *
+     * @return a byte array containing the Hex encoded data.
+     */
+    public static byte[] encode(
+        byte[]    data,
+        int       off,
+        int       length)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.encode(data, off, length, bOut);
+        }
+        catch (Exception e)
+        {
+            throw new EncoderException("exception encoding Hex string: " + e.getMessage(), e);
+        }
+        
+        return bOut.toByteArray();
+    }
+
+    /**
+     * Hex encode the byte data writing it to the given output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int encode(
+        byte[]         data,
+        OutputStream   out)
+        throws IOException
+    {
+        return encoder.encode(data, 0, data.length, out);
+    }
+    
+    /**
+     * Hex encode the byte data writing it to the given output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int encode(
+        byte[]         data,
+        int            off,
+        int            length,
+        OutputStream   out)
+        throws IOException
+    {
+        return encoder.encode(data, off, length, out);
+    }
+    
+    /**
+     * decode the Hex encoded input data. It is assumed the input data is valid.
+     *
+     * @return a byte array representing the decoded data.
+     */
+    public static byte[] decode(
+        byte[]    data)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.decode(data, 0, data.length, bOut);
+        }
+        catch (Exception e)
+        {
+            throw new DecoderException("exception decoding Hex data: " + e.getMessage(), e);
+        }
+        
+        return bOut.toByteArray();
+    }
+    
+    /**
+     * decode the Hex encoded String data - whitespace will be ignored.
+     *
+     * @return a byte array representing the decoded data.
+     */
+    public static byte[] decode(
+        String    data)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.decode(data, bOut);
+        }
+        catch (Exception e)
+        {
+            throw new DecoderException("exception decoding Hex string: " + e.getMessage(), e);
+        }
+        
+        return bOut.toByteArray();
+    }
+    
+    /**
+     * decode the Hex encoded String data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int decode(
+        String          data,
+        OutputStream    out)
+        throws IOException
+    {
+        return encoder.decode(data, out);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/HexEncoder.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/HexEncoder.java
new file mode 100644
index 0000000..5395fda
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/HexEncoder.java
@@ -0,0 +1,192 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A streaming Hex encoder.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class HexEncoder
+    implements Encoder
+{
+    protected final byte[] encodingTable =
+    {
+        (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+        (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
+    };
+
+    /*
+     * set up the decoding table.
+     */
+    protected final byte[] decodingTable = new byte[128];
+
+    protected void initialiseDecodingTable()
+    {
+        for (int i = 0; i < decodingTable.length; i++)
+        {
+            decodingTable[i] = (byte)0xff;
+        }
+
+        for (int i = 0; i < encodingTable.length; i++)
+        {
+            decodingTable[encodingTable[i]] = (byte)i;
+        }
+        
+        decodingTable['A'] = decodingTable['a'];
+        decodingTable['B'] = decodingTable['b'];
+        decodingTable['C'] = decodingTable['c'];
+        decodingTable['D'] = decodingTable['d'];
+        decodingTable['E'] = decodingTable['e'];
+        decodingTable['F'] = decodingTable['f'];
+    }
+    
+    public HexEncoder()
+    {
+        initialiseDecodingTable();
+    }
+    
+    /**
+     * encode the input data producing a Hex output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public int encode(
+        byte[]                data,
+        int                    off,
+        int                    length,
+        OutputStream    out) 
+        throws IOException
+    {        
+        for (int i = off; i < (off + length); i++)
+        {
+            int    v = data[i] & 0xff;
+
+            out.write(encodingTable[(v >>> 4)]);
+            out.write(encodingTable[v & 0xf]);
+        }
+
+        return length * 2;
+    }
+
+    private static boolean ignore(
+        char    c)
+    {
+        return c == '\n' || c =='\r' || c == '\t' || c == ' ';
+    }
+
+    /**
+     * decode the Hex encoded byte data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public int decode(
+        byte[]          data,
+        int             off,
+        int             length,
+        OutputStream    out)
+        throws IOException
+    {
+        byte    b1, b2;
+        int     outLen = 0;
+        
+        int     end = off + length;
+        
+        while (end > off)
+        {
+            if (!ignore((char)data[end - 1]))
+            {
+                break;
+            }
+            
+            end--;
+        }
+        
+        int i = off;
+        while (i < end)
+        {
+            while (i < end && ignore((char)data[i]))
+            {
+                i++;
+            }
+            
+            b1 = decodingTable[data[i++]];
+            
+            while (i < end && ignore((char)data[i]))
+            {
+                i++;
+            }
+            
+            b2 = decodingTable[data[i++]];
+
+            if ((b1 | b2) < 0)
+            {
+                throw new IOException("invalid characters encountered in Hex data");
+            }
+
+            out.write((b1 << 4) | b2);
+            
+            outLen++;
+        }
+
+        return outLen;
+    }
+    
+    /**
+     * decode the Hex encoded String data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public int decode(
+        String          data,
+        OutputStream    out)
+        throws IOException
+    {
+        byte    b1, b2;
+        int     length = 0;
+        
+        int     end = data.length();
+        
+        while (end > 0)
+        {
+            if (!ignore(data.charAt(end - 1)))
+            {
+                break;
+            }
+            
+            end--;
+        }
+        
+        int i = 0;
+        while (i < end)
+        {
+            while (i < end && ignore(data.charAt(i)))
+            {
+                i++;
+            }
+            
+            b1 = decodingTable[data.charAt(i++)];
+            
+            while (i < end && ignore(data.charAt(i)))
+            {
+                i++;
+            }
+            
+            b2 = decodingTable[data.charAt(i++)];
+
+            if ((b1 | b2) < 0)
+            {
+                throw new IOException("invalid characters encountered in Hex string");
+            }
+
+            out.write((b1 << 4) | b2);
+            
+            length++;
+        }
+
+        return length;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/UTF8.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/UTF8.java
new file mode 100644
index 0000000..c6f49f6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/encoders/UTF8.java
@@ -0,0 +1,158 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.encoders;
+
+/**
+ * Utilities for working with UTF-8 encodings.
+ * 
+ * Decoding of UTF-8 is based on a presentation by Bob Steagall at CppCon2018 (see
+ * https://github.com/BobSteagall/CppCon2018). It uses a Deterministic Finite Automaton (DFA) to
+ * recognize and decode multi-byte code points.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class UTF8
+{
+    // Constants for the categorization of code units
+    private static final byte C_ILL = 0;            //- C0..C1, F5..FF  ILLEGAL octets that should never appear in a UTF-8 sequence
+    private static final byte C_CR1 = 1;            //- 80..8F          Continuation range 1
+    private static final byte C_CR2 = 2;            //- 90..9F          Continuation range 2
+    private static final byte C_CR3 = 3;            //- A0..BF          Continuation range 3
+    private static final byte C_L2A = 4;            //- C2..DF          Leading byte range A / 2-byte sequence
+    private static final byte C_L3A = 5;            //- E0              Leading byte range A / 3-byte sequence
+    private static final byte C_L3B = 6;            //- E1..EC, EE..EF  Leading byte range B / 3-byte sequence
+    private static final byte C_L3C = 7;            //- ED              Leading byte range C / 3-byte sequence
+    private static final byte C_L4A = 8;            //- F0              Leading byte range A / 4-byte sequence
+    private static final byte C_L4B = 9;            //- F1..F3          Leading byte range B / 4-byte sequence
+    private static final byte C_L4C = 10;           //- F4              Leading byte range C / 4-byte sequence
+//  private static final byte C_ASC = 11;           //- 00..7F          ASCII leading byte range
+
+    // Constants for the states of a DFA
+    private static final byte S_ERR = -2;           //- Error state
+    private static final byte S_END = -1;           //- End (or Accept) state
+    private static final byte S_CS1 = 0x00;         //- Continuation state 1
+    private static final byte S_CS2 = 0x10;         //- Continuation state 2
+    private static final byte S_CS3 = 0x20;         //- Continuation state 3
+    private static final byte S_P3A = 0x30;         //- Partial 3-byte sequence state A
+    private static final byte S_P3B = 0x40;         //- Partial 3-byte sequence state B
+    private static final byte S_P4A = 0x50;         //- Partial 4-byte sequence state A
+    private static final byte S_P4B = 0x60;         //- Partial 4-byte sequence state B
+
+    private static final short[] firstUnitTable = new short[128];
+    private static final byte[] transitionTable = new byte[S_P4B + 16];
+
+    private static void fill(byte[] table, int first, int last, byte b)
+    {
+        for (int i = first; i <= last; ++i)
+        {
+            table[i] = b;
+        }
+    }
+
+    static
+    {
+        byte[] categories = new byte[128];
+        fill(categories, 0x00, 0x0F, C_CR1);
+        fill(categories, 0x10, 0x1F, C_CR2);
+        fill(categories, 0x20, 0x3F, C_CR3);
+        fill(categories, 0x40, 0x41, C_ILL);
+        fill(categories, 0x42, 0x5F, C_L2A);
+        fill(categories, 0x60, 0x60, C_L3A);
+        fill(categories, 0x61, 0x6C, C_L3B);
+        fill(categories, 0x6D, 0x6D, C_L3C);
+        fill(categories, 0x6E, 0x6F, C_L3B);
+        fill(categories, 0x70, 0x70, C_L4A);
+        fill(categories, 0x71, 0x73, C_L4B);
+        fill(categories, 0x74, 0x74, C_L4C);
+        fill(categories, 0x75, 0x7F, C_ILL);
+
+        fill(transitionTable, 0, transitionTable.length - 1, S_ERR);
+        fill(transitionTable, S_CS1 + 0x8, S_CS1 + 0xB, S_END);
+        fill(transitionTable, S_CS2 + 0x8, S_CS2 + 0xB, S_CS1);
+        fill(transitionTable, S_CS3 + 0x8, S_CS3 + 0xB, S_CS2);
+        fill(transitionTable, S_P3A + 0xA, S_P3A + 0xB, S_CS1);
+        fill(transitionTable, S_P3B + 0x8, S_P3B + 0x9, S_CS1);
+        fill(transitionTable, S_P4A + 0x9, S_P4A + 0xB, S_CS2);
+        fill(transitionTable, S_P4B + 0x8, S_P4B + 0x8, S_CS2);
+
+        byte[] firstUnitMasks = { 0x00, 0x00, 0x00, 0x00, 0x1F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07 };
+        byte[] firstUnitTransitions = { S_ERR, S_ERR, S_ERR, S_ERR, S_CS1, S_P3A, S_CS2, S_P3B, S_P4A, S_CS3, S_P4B };
+
+        for (int i = 0x00; i < 0x80; ++i)
+        {
+            byte category = categories[i];
+
+            int codePoint = i & firstUnitMasks[category];
+            byte state = firstUnitTransitions[category];
+
+            firstUnitTable[i] = (short)((codePoint << 8) | state);
+        }
+    }
+
+    /**
+     * Transcode a UTF-8 encoding into a UTF-16 representation. In the general case the output
+     * {@code utf16} array should be at least as long as the input {@code utf8} one to handle
+     * arbitrary inputs. The number of output UTF-16 code units is returned, or -1 if any errors are
+     * encountered (in which case an arbitrary amount of data may have been written into the output
+     * array). Errors that will be detected are malformed UTF-8, including incomplete, truncated or
+     * "overlong" encodings, and unmappable code points. In particular, no unmatched surrogates will
+     * be produced. An error will also result if {@code utf16} is found to be too small to store the
+     * complete output.
+     * 
+     * @param utf8
+     *            A non-null array containing a well-formed UTF-8 encoding.
+     * @param utf16
+     *            A non-null array, at least as long as the {@code utf8} array in order to ensure
+     *            the output will fit.
+     * @return The number of UTF-16 code units written to {@code utf16} (beginning from index 0), or
+     *         else -1 if the input was either malformed or encoded any unmappable characters, or if
+     *         the {@code utf16} is too small.
+     */
+    public static int transcodeToUTF16(byte[] utf8, char[] utf16)
+    {
+        int i = 0, j = 0;
+
+        while (i < utf8.length)
+        {
+            byte codeUnit = utf8[i++];
+            if (codeUnit >= 0)
+            {
+                if (j >= utf16.length) { return -1; }
+
+                utf16[j++] = (char)codeUnit;
+                continue;
+            }
+
+            short first = firstUnitTable[codeUnit & 0x7F];
+            int codePoint = first >>> 8;
+            byte state = (byte)first;
+
+            while (state >= 0)
+            {
+                if (i >= utf8.length) { return -1; }
+
+                codeUnit = utf8[i++];
+                codePoint = (codePoint << 6) | (codeUnit & 0x3F);
+                state = transitionTable[state + ((codeUnit & 0xFF) >>> 4)];
+            }
+
+            if (state == S_ERR) { return -1; }
+
+            if (codePoint <= 0xFFFF)
+            {
+                if (j >= utf16.length) { return -1; }
+
+                // Code points from U+D800 to U+DFFF are caught by the DFA
+                utf16[j++] = (char)codePoint;
+            }
+            else
+            {
+                if (j >= utf16.length - 1) { return -1; }
+
+                // Code points above U+10FFFF are caught by the DFA
+                utf16[j++] = (char)(0xD7C0 + (codePoint >>> 10));
+                utf16[j++] = (char)(0xDC00 | (codePoint & 0x3FF));
+            }
+        }
+
+        return j;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/SimpleOutputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/SimpleOutputStream.java
new file mode 100644
index 0000000..b7d673e
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/SimpleOutputStream.java
@@ -0,0 +1,25 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class SimpleOutputStream extends OutputStream
+{
+    public void close()
+    {
+    }
+
+    public void flush()
+    {
+    }
+
+    public void write(int b) throws IOException
+    {
+        byte[] buf = new byte[]{ (byte)b };
+        write(buf, 0, 1);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/StreamOverflowException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/StreamOverflowException.java
new file mode 100644
index 0000000..f493b21
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/StreamOverflowException.java
@@ -0,0 +1,17 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io;
+
+import java.io.IOException;
+
+/**
+ * Exception thrown when too much data is written to an InputStream
+ * @hide This class is not part of the Android public SDK API
+ */
+public class StreamOverflowException
+    extends IOException
+{
+    public StreamOverflowException(String msg)
+    {
+        super(msg);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/Streams.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/Streams.java
new file mode 100644
index 0000000..2c0a2ad
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/Streams.java
@@ -0,0 +1,153 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Utility methods to assist with stream processing.
+ * @hide This class is not part of the Android public SDK API
+ */
+public final class Streams
+{
+    private static int BUFFER_SIZE = 4096;
+
+    /**
+     * Read stream till EOF is encountered.
+     *
+     * @param inStr stream to be emptied.
+     * @throws IOException in case of underlying IOException.
+     */
+    public static void drain(InputStream inStr)
+        throws IOException
+    {
+        byte[] bs = new byte[BUFFER_SIZE];
+        while (inStr.read(bs, 0, bs.length) >= 0)
+        {
+        }
+    }
+
+    /**
+     * Read stream fully, returning contents in a byte array.
+     *
+     * @param inStr stream to be read.
+     * @return a byte array representing the contents of inStr.
+     * @throws IOException in case of underlying IOException.
+     */
+    public static byte[] readAll(InputStream inStr)
+        throws IOException
+    {
+        ByteArrayOutputStream buf = new ByteArrayOutputStream();
+        pipeAll(inStr, buf);
+        return buf.toByteArray();
+    }
+
+    /**
+     * Read from inStr up to a maximum number of bytes, throwing an exception if more the maximum amount
+     * of requested data is available.
+     *
+     * @param inStr stream to be read.
+     * @param limit maximum number of bytes that can be read.
+     * @return a byte array representing the contents of inStr.
+     * @throws IOException in case of underlying IOException, or if limit is reached on inStr still has data in it.
+     */
+    public static byte[] readAllLimited(InputStream inStr, int limit)
+        throws IOException
+    {
+        ByteArrayOutputStream buf = new ByteArrayOutputStream();
+        pipeAllLimited(inStr, limit, buf);
+        return buf.toByteArray();
+    }
+
+    /**
+     * Fully read in buf's length in data, or up to EOF, whichever occurs first,
+     *
+     * @param inStr the stream to be read.
+     * @param buf the buffer to be read into.
+     * @return the number of bytes read into the buffer.
+     * @throws IOException in case of underlying IOException.
+     */
+    public static int readFully(InputStream inStr, byte[] buf)
+        throws IOException
+    {
+        return readFully(inStr, buf, 0, buf.length);
+    }
+
+    /**
+     * Fully read in len's bytes of data into buf, or up to EOF, whichever occurs first,
+     *
+     * @param inStr the stream to be read.
+     * @param buf the buffer to be read into.
+     * @param off offset into buf to start putting bytes into.
+     * @param len  the number of bytes to be read.
+     * @return the number of bytes read into the buffer.
+     * @throws IOException in case of underlying IOException.
+     */
+    public static int readFully(InputStream inStr, byte[] buf, int off, int len)
+        throws IOException
+    {
+        int totalRead = 0;
+        while (totalRead < len)
+        {
+            int numRead = inStr.read(buf, off + totalRead, len - totalRead);
+            if (numRead < 0)
+            {
+                break;
+            }
+            totalRead += numRead;
+        }
+        return totalRead;
+    }
+
+    /**
+     * Write the full contents of inStr to the destination stream outStr.
+     *
+     * @param inStr source input stream.
+     * @param outStr destination output stream.
+     * @throws IOException in case of underlying IOException.
+     */
+    public static void pipeAll(InputStream inStr, OutputStream outStr)
+        throws IOException
+    {
+        byte[] bs = new byte[BUFFER_SIZE];
+        int numRead;
+        while ((numRead = inStr.read(bs, 0, bs.length)) >= 0)
+        {
+            outStr.write(bs, 0, numRead);
+        }
+    }
+
+    /**
+     * Write up to limit bytes of data from inStr to the destination stream outStr.
+     *
+     * @param inStr source input stream.
+     * @param limit the maximum number of bytes allowed to be read.
+     * @param outStr destination output stream.
+     * @throws IOException in case of underlying IOException, or if limit is reached on inStr still has data in it.
+     */
+    public static long pipeAllLimited(InputStream inStr, long limit, OutputStream outStr)
+        throws IOException
+    {
+        long total = 0;
+        byte[] bs = new byte[BUFFER_SIZE];
+        int numRead;
+        while ((numRead = inStr.read(bs, 0, bs.length)) >= 0)
+        {
+            if ((limit - total) < numRead)
+            {
+                throw new StreamOverflowException("Data Overflow");
+            }
+            total += numRead;
+            outStr.write(bs, 0, numRead);
+        }
+        return total;
+    }
+
+    public static void writeBufTo(ByteArrayOutputStream buf, OutputStream output)
+        throws IOException
+    {
+        buf.writeTo(output);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/TeeInputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/TeeInputStream.java
new file mode 100644
index 0000000..1e73bd0
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/TeeInputStream.java
@@ -0,0 +1,73 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * An input stream which copies anything read through it to another stream.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TeeInputStream
+    extends InputStream
+{
+    private final InputStream input;
+    private final OutputStream output;
+
+    /**
+     * Base constructor.
+     *
+     * @param input input stream to be wrapped.
+     * @param output output stream to copy any input read to.
+     */
+    public TeeInputStream(InputStream input, OutputStream output)
+    {
+        this.input = input;
+        this.output = output;
+    }
+
+    public int read(byte[] buf)
+        throws IOException
+    {
+        return read(buf, 0, buf.length);
+    }
+
+    public int read(byte[] buf, int off, int len)
+        throws IOException
+    {
+        int i = input.read(buf, off, len);
+
+        if (i > 0)
+        {
+            output.write(buf, off, i);
+        }
+
+        return i;
+    }
+
+    public int read()
+        throws IOException
+    {
+        int i = input.read();
+
+        if (i >= 0)
+        {
+            output.write(i);
+        }
+
+        return i;
+    }
+
+    public void close()
+        throws IOException
+    {
+        this.input.close();
+        this.output.close();
+    }
+
+    public OutputStream getOutputStream()
+    {
+        return output;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/TeeOutputStream.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/TeeOutputStream.java
new file mode 100644
index 0000000..6ad76cf
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/TeeOutputStream.java
@@ -0,0 +1,64 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+/**
+ * An output stream which copies anything written into it to another stream.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class TeeOutputStream
+    extends OutputStream
+{
+    private OutputStream output1;
+    private OutputStream output2;
+
+    /**
+     * Base constructor.
+     *
+     * @param output1 the output stream that is wrapped.
+     * @param output2 a secondary stream that anything written to output1 is also written to.
+     */
+    public TeeOutputStream(OutputStream output1, OutputStream output2)
+    {
+        this.output1 = output1;
+        this.output2 = output2;
+    }
+
+    public void write(byte[] buf)
+        throws IOException
+    {
+        this.output1.write(buf);
+        this.output2.write(buf);
+    }
+
+    public void write(byte[] buf, int off, int len)
+        throws IOException
+    {
+        this.output1.write(buf, off, len);
+        this.output2.write(buf, off, len);
+    }
+
+    public void write(int b)
+        throws IOException
+    {
+        this.output1.write(b);
+        this.output2.write(b);
+    }
+
+    public void flush()
+        throws IOException
+    {
+        this.output1.flush();
+        this.output2.flush();
+    }
+
+    public void close()
+        throws IOException
+    {
+        this.output1.close();
+        this.output2.close();
+    }
+}
\ No newline at end of file
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemGenerationException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemGenerationException.java
new file mode 100644
index 0000000..0ceacaf
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemGenerationException.java
@@ -0,0 +1,30 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io.pem;
+
+import java.io.IOException;
+
+/**
+ * Exception thrown on failure to generate a PEM object.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PemGenerationException
+    extends IOException
+{
+    private Throwable cause;
+
+    public PemGenerationException(String message, Throwable cause)
+    {
+        super(message);
+        this.cause = cause;
+    }
+
+    public PemGenerationException(String message)
+    {
+        super(message);
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemHeader.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemHeader.java
new file mode 100644
index 0000000..4cdf6d4
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemHeader.java
@@ -0,0 +1,77 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io.pem;
+
+/**
+ * Class representing a PEM header (name, value) pair.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PemHeader
+{
+    private String name;
+    private String value;
+
+    /**
+     * Base constructor.
+     *
+     * @param name name of the header property.
+     * @param value value of the header property.
+     */
+    public PemHeader(String name, String value)
+    {
+        this.name = name;
+        this.value = value;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public String getValue()
+    {
+        return value;
+    }
+
+    public int hashCode()
+    {
+        return getHashCode(this.name) + 31 * getHashCode(this.value);    
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof PemHeader))
+        {
+            return false;
+        }
+
+        PemHeader other = (PemHeader)o;
+
+        return other == this || (isEqual(this.name, other.name) && isEqual(this.value, other.value));
+    }
+
+    private int getHashCode(String s)
+    {
+        if (s == null)
+        {
+            return 1;
+        }
+
+        return s.hashCode();
+    }
+
+    private boolean isEqual(String s1, String s2)
+    {
+        if (s1 == s2)
+        {
+            return true;
+        }
+
+        if (s1 == null || s2 == null)
+        {
+            return false;
+        }
+
+        return s1.equals(s2);
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemObject.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemObject.java
new file mode 100644
index 0000000..0125b03
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemObject.java
@@ -0,0 +1,66 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io.pem;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A generic PEM object - type, header properties, and byte content.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PemObject
+    implements PemObjectGenerator
+{
+    private static final List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());
+
+    private String type;
+    private List   headers;
+    private byte[] content;
+
+    /**
+     * Generic constructor for object without headers.
+     *
+     * @param type pem object type.
+     * @param content the binary content of the object.
+     */
+    public PemObject(String type, byte[] content)
+    {
+        this(type, EMPTY_LIST, content);
+    }
+
+    /**
+     * Generic constructor for object with headers.
+     *
+     * @param type pem object type.
+     * @param headers a list of PemHeader objects.
+     * @param content the binary content of the object.
+     */
+    public PemObject(String type, List headers, byte[] content)
+    {
+        this.type = type;
+        this.headers = Collections.unmodifiableList(headers);
+        this.content = content;
+    }
+
+    public String getType()
+    {
+        return type;
+    }
+
+    public List getHeaders()
+    {
+        return headers;
+    }
+
+    public byte[] getContent()
+    {
+        return content;
+    }
+
+    public PemObject generate()
+        throws PemGenerationException
+    {
+        return this;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemObjectGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemObjectGenerator.java
new file mode 100644
index 0000000..07843b2
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemObjectGenerator.java
@@ -0,0 +1,18 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io.pem;
+
+/**
+ * Base interface for generators of PEM objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface PemObjectGenerator
+{
+    /**
+     * Generate a PEM object.
+     *
+     * @return the generated object.
+     * @throws PemGenerationException on failure.
+     */
+    PemObject generate()
+        throws PemGenerationException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemObjectParser.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemObjectParser.java
new file mode 100644
index 0000000..95bf9aa
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemObjectParser.java
@@ -0,0 +1,21 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io.pem;
+
+import java.io.IOException;
+
+/**
+ * Base interface for parsers to convert PEM objects into specific objects.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface PemObjectParser
+{
+    /**
+     * Parse an object out of the PEM object passed in.
+     *
+     * @param obj the PEM object containing the details for the specific object.
+     * @return a specific object represented by the  PEM object.
+     * @throws IOException on a parsing error.
+     */
+    Object parseObject(PemObject obj)
+            throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemReader.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemReader.java
new file mode 100644
index 0000000..76f8897
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemReader.java
@@ -0,0 +1,95 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io.pem;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.android.internal.org.bouncycastle.util.encoders.Base64;
+
+/**
+ * A generic PEM reader, based on the format outlined in RFC 1421
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PemReader
+    extends BufferedReader
+{
+    private static final String BEGIN = "-----BEGIN ";
+    private static final String END = "-----END ";
+
+    public PemReader(Reader reader)
+    {
+        super(reader);
+    }
+
+    /**
+     * Read the next PEM object as a blob of raw data with header information.
+     *
+     * @return the next object in the stream, null if no objects left.
+     * @throws IOException in case of a parse error.
+     */
+    public PemObject readPemObject()
+        throws IOException
+    {
+        String line = readLine();
+
+        while (line != null && !line.startsWith(BEGIN))
+        {
+            line = readLine();
+        }
+
+        if (line != null)
+        {
+            line = line.substring(BEGIN.length());
+            int index = line.indexOf('-');
+            String type = line.substring(0, index);
+
+            if (index > 0)
+            {
+                return loadObject(type);
+            }
+        }
+
+        return null;
+    }
+
+    private PemObject loadObject(String type)
+        throws IOException
+    {
+        String          line;
+        String          endMarker = END + type;
+        StringBuffer    buf = new StringBuffer();
+        List            headers = new ArrayList();
+
+        while ((line = readLine()) != null)
+        {
+            if (line.indexOf(":") >= 0)
+            {
+                int index = line.indexOf(':');
+                String hdr = line.substring(0, index);
+                String value = line.substring(index + 1).trim();
+
+                headers.add(new PemHeader(hdr, value));
+
+                continue;
+            }
+
+            if (line.indexOf(endMarker) != -1)
+            {
+                break;
+            }
+            
+            buf.append(line.trim());
+        }
+
+        if (line == null)
+        {
+            throw new IOException(endMarker + " not found");
+        }
+
+        return new PemObject(type, headers, Base64.decode(buf.toString()));
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemWriter.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemWriter.java
new file mode 100644
index 0000000..48132c7
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/util/io/pem/PemWriter.java
@@ -0,0 +1,140 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.util.io.pem;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Iterator;
+
+import com.android.internal.org.bouncycastle.util.Strings;
+import com.android.internal.org.bouncycastle.util.encoders.Base64;
+
+/**
+ * A generic PEM writer, based on RFC 1421
+ * @hide This class is not part of the Android public SDK API
+ */
+public class PemWriter
+    extends BufferedWriter
+{
+    private static final int LINE_LENGTH = 64;
+
+    private final int nlLength;
+    private char[]  buf = new char[LINE_LENGTH];
+
+    /**
+     * Base constructor.
+     *
+     * @param out output stream to use.
+     */
+    public PemWriter(Writer out)
+    {
+        super(out);
+
+        String nl = Strings.lineSeparator();
+        if (nl != null)
+        {
+            nlLength = nl.length();
+        }
+        else
+        {
+            nlLength = 2;
+        }
+    }
+
+    /**
+     * Return the number of bytes or characters required to contain the
+     * passed in object if it is PEM encoded.
+     *
+     * @param obj pem object to be output
+     * @return an estimate of the number of bytes
+     */
+    public int getOutputSize(PemObject obj)
+    {
+        // BEGIN and END boundaries.
+        int size = (2 * (obj.getType().length() + 10 + nlLength)) + 6 + 4;
+
+        if (!obj.getHeaders().isEmpty())
+        {
+            for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
+            {
+                PemHeader hdr = (PemHeader)it.next();
+
+                size += hdr.getName().length() + ": ".length() + hdr.getValue().length() + nlLength;
+            }
+
+            size += nlLength;
+        }
+
+        // base64 encoding
+        int dataLen = ((obj.getContent().length + 2) / 3) * 4;
+        
+        size += dataLen + (((dataLen + LINE_LENGTH - 1) / LINE_LENGTH) * nlLength);
+
+        return size;
+    }
+    
+    public void writeObject(PemObjectGenerator objGen)
+        throws IOException
+    {
+        PemObject obj = objGen.generate();
+
+        writePreEncapsulationBoundary(obj.getType());
+
+        if (!obj.getHeaders().isEmpty())
+        {
+            for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
+            {
+                PemHeader hdr = (PemHeader)it.next();
+
+                this.write(hdr.getName());
+                this.write(": ");
+                this.write(hdr.getValue());
+                this.newLine();
+            }
+
+            this.newLine();
+        }
+        
+        writeEncoded(obj.getContent());
+        writePostEncapsulationBoundary(obj.getType());
+    }
+
+    private void writeEncoded(byte[] bytes)
+        throws IOException
+    {
+        bytes = Base64.encode(bytes);
+
+        for (int i = 0; i < bytes.length; i += buf.length)
+        {
+            int index = 0;
+
+            while (index != buf.length)
+            {
+                if ((i + index) >= bytes.length)
+                {
+                    break;
+                }
+                buf[index] = (char)bytes[i + index];
+                index++;
+            }
+            this.write(buf, 0, index);
+            this.newLine();
+        }
+    }
+
+    private void writePreEncapsulationBoundary(
+        String type)
+        throws IOException
+    {
+        this.write("-----BEGIN " + type + "-----");
+        this.newLine();
+    }
+
+    private void writePostEncapsulationBoundary(
+        String type)
+        throws IOException
+    {
+        this.write("-----END " + type + "-----");
+        this.newLine();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/AttributeCertificateHolder.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/AttributeCertificateHolder.java
new file mode 100644
index 0000000..6200245
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/AttributeCertificateHolder.java
@@ -0,0 +1,422 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.Principal;
+import java.security.cert.CertSelector;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralNames;
+import com.android.internal.org.bouncycastle.asn1.x509.Holder;
+import com.android.internal.org.bouncycastle.asn1.x509.IssuerSerial;
+import com.android.internal.org.bouncycastle.asn1.x509.ObjectDigestInfo;
+import com.android.internal.org.bouncycastle.jce.PrincipalUtil;
+import com.android.internal.org.bouncycastle.jce.X509Principal;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Selector;
+
+/**
+ * The Holder object.
+ * 
+ * <pre>
+ *          Holder ::= SEQUENCE {
+ *                baseCertificateID   [0] IssuerSerial OPTIONAL,
+ *                         -- the issuer and serial number of
+ *                         -- the holder's Public Key Certificate
+ *                entityName          [1] GeneralNames OPTIONAL,
+ *                         -- the name of the claimant or role
+ *                objectDigestInfo    [2] ObjectDigestInfo OPTIONAL
+ *                         -- used to directly authenticate the holder,
+ *                         -- for example, an executable
+ *          }
+ * </pre>
+ * @deprecated use org.bouncycastle.cert.AttributeCertificateHolder
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AttributeCertificateHolder
+    implements CertSelector, Selector
+{
+    final Holder holder;
+
+    AttributeCertificateHolder(ASN1Sequence seq)
+    {
+        holder = Holder.getInstance(seq);
+    }
+
+    public AttributeCertificateHolder(X509Principal issuerName,
+        BigInteger serialNumber)
+    {
+        holder = new com.android.internal.org.bouncycastle.asn1.x509.Holder(new IssuerSerial(
+            GeneralNames.getInstance(new DERSequence(new GeneralName(issuerName))),
+            new ASN1Integer(serialNumber)));
+    }
+
+    public AttributeCertificateHolder(X500Principal issuerName,
+        BigInteger serialNumber)
+    {
+        this(X509Util.convertPrincipal(issuerName), serialNumber);
+    }
+
+    public AttributeCertificateHolder(X509Certificate cert)
+        throws CertificateParsingException
+    {
+        X509Principal name;
+
+        try
+        {
+            name = PrincipalUtil.getIssuerX509Principal(cert);
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException(e.getMessage());
+        }
+
+        holder = new Holder(new IssuerSerial(generateGeneralNames(name),
+            new ASN1Integer(cert.getSerialNumber())));
+    }
+
+    public AttributeCertificateHolder(X509Principal principal)
+    {
+        holder = new Holder(generateGeneralNames(principal));
+    }
+
+    public AttributeCertificateHolder(X500Principal principal)
+    {
+        this(X509Util.convertPrincipal(principal));
+    }
+
+    /**
+     * Constructs a holder for v2 attribute certificates with a hash value for
+     * some type of object.
+     * <p>
+     * <code>digestedObjectType</code> can be one of the following:
+     * <ul>
+     * <li>0 - publicKey - A hash of the public key of the holder must be
+     * passed.
+     * <li>1 - publicKeyCert - A hash of the public key certificate of the
+     * holder must be passed.
+     * <li>2 - otherObjectDigest - A hash of some other object type must be
+     * passed. <code>otherObjectTypeID</code> must not be empty.
+     * </ul>
+     * <p>
+     * This cannot be used if a v1 attribute certificate is used.
+     * 
+     * @param digestedObjectType The digest object type.
+     * @param digestAlgorithm The algorithm identifier for the hash.
+     * @param otherObjectTypeID The object type ID if
+     *            <code>digestedObjectType</code> is
+     *            <code>otherObjectDigest</code>.
+     * @param objectDigest The hash value.
+     */
+    public AttributeCertificateHolder(int digestedObjectType,
+        String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest)
+    {
+        holder = new Holder(new ObjectDigestInfo(digestedObjectType,
+            new ASN1ObjectIdentifier(otherObjectTypeID), new AlgorithmIdentifier(new ASN1ObjectIdentifier(digestAlgorithm)), Arrays
+                .clone(objectDigest)));
+    }
+
+    /**
+     * Returns the digest object type if an object digest info is used.
+     * <p>
+     * <ul>
+     * <li>0 - publicKey - A hash of the public key of the holder must be
+     * passed.
+     * <li>1 - publicKeyCert - A hash of the public key certificate of the
+     * holder must be passed.
+     * <li>2 - otherObjectDigest - A hash of some other object type must be
+     * passed. <code>otherObjectTypeID</code> must not be empty.
+     * </ul>
+     * 
+     * @return The digest object type or -1 if no object digest info is set.
+     */
+    public int getDigestedObjectType()
+    {
+        if (holder.getObjectDigestInfo() != null)
+        {
+            return holder.getObjectDigestInfo().getDigestedObjectType()
+                .getValue().intValue();
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the other object type ID if an object digest info is used.
+     * 
+     * @return The other object type ID or <code>null</code> if no object
+     *         digest info is set.
+     */
+    public String getDigestAlgorithm()
+    {
+        if (holder.getObjectDigestInfo() != null)
+        {
+            return holder.getObjectDigestInfo().getDigestAlgorithm().getAlgorithm()
+                .getId();
+        }
+        return null;
+    }
+
+    /**
+     * Returns the hash if an object digest info is used.
+     * 
+     * @return The hash or <code>null</code> if no object digest info is set.
+     */
+    public byte[] getObjectDigest()
+    {
+        if (holder.getObjectDigestInfo() != null)
+        {
+            return holder.getObjectDigestInfo().getObjectDigest().getBytes();
+        }
+        return null;
+    }
+
+    /**
+     * Returns the digest algorithm ID if an object digest info is used.
+     * 
+     * @return The digest algorithm ID or <code>null</code> if no object
+     *         digest info is set.
+     */
+    public String getOtherObjectTypeID()
+    {
+        if (holder.getObjectDigestInfo() != null)
+        {
+            holder.getObjectDigestInfo().getOtherObjectTypeID().getId();
+        }
+        return null;
+    }
+
+    private GeneralNames generateGeneralNames(X509Principal principal)
+    {
+        return GeneralNames.getInstance(new DERSequence(new GeneralName(principal)));
+    }
+
+    private boolean matchesDN(X509Principal subject, GeneralNames targets)
+    {
+        GeneralName[] names = targets.getNames();
+
+        for (int i = 0; i != names.length; i++)
+        {
+            GeneralName gn = names[i];
+
+            if (gn.getTagNo() == GeneralName.directoryName)
+            {
+                try
+                {
+                    if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive()
+                        .getEncoded()).equals(subject))
+                    {
+                        return true;
+                    }
+                }
+                catch (IOException e)
+                {
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private Object[] getNames(GeneralName[] names)
+    {
+        List l = new ArrayList(names.length);
+
+        for (int i = 0; i != names.length; i++)
+        {
+            if (names[i].getTagNo() == GeneralName.directoryName)
+            {
+                try
+                {
+                    l.add(new X500Principal(
+                        ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+                }
+                catch (IOException e)
+                {
+                    throw new RuntimeException("badly formed Name object");
+                }
+            }
+        }
+
+        return l.toArray(new Object[l.size()]);
+    }
+
+    private Principal[] getPrincipals(GeneralNames names)
+    {
+        Object[] p = this.getNames(names.getNames());
+        List l = new ArrayList();
+
+        for (int i = 0; i != p.length; i++)
+        {
+            if (p[i] instanceof Principal)
+            {
+                l.add(p[i]);
+            }
+        }
+
+        return (Principal[])l.toArray(new Principal[l.size()]);
+    }
+
+    /**
+     * Return any principal objects inside the attribute certificate holder
+     * entity names field.
+     * 
+     * @return an array of Principal objects (usually X500Principal), null if no
+     *         entity names field is set.
+     */
+    public Principal[] getEntityNames()
+    {
+        if (holder.getEntityName() != null)
+        {
+            return getPrincipals(holder.getEntityName());
+        }
+
+        return null;
+    }
+
+    /**
+     * Return the principals associated with the issuer attached to this holder
+     * 
+     * @return an array of principals, null if no BaseCertificateID is set.
+     */
+    public Principal[] getIssuer()
+    {
+        if (holder.getBaseCertificateID() != null)
+        {
+            return getPrincipals(holder.getBaseCertificateID().getIssuer());
+        }
+
+        return null;
+    }
+
+    /**
+     * Return the serial number associated with the issuer attached to this
+     * holder.
+     * 
+     * @return the certificate serial number, null if no BaseCertificateID is
+     *         set.
+     */
+    public BigInteger getSerialNumber()
+    {
+        if (holder.getBaseCertificateID() != null)
+        {
+            return holder.getBaseCertificateID().getSerial().getValue();
+        }
+
+        return null;
+    }
+
+    public Object clone()
+    {
+        return new AttributeCertificateHolder((ASN1Sequence)holder
+            .toASN1Primitive());
+    }
+
+    public boolean match(Certificate cert)
+    {
+        if (!(cert instanceof X509Certificate))
+        {
+            return false;
+        }
+
+        X509Certificate x509Cert = (X509Certificate)cert;
+
+        try
+        {
+            if (holder.getBaseCertificateID() != null)
+            {
+                return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+                    && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer());
+            }
+
+            if (holder.getEntityName() != null)
+            {
+                if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert),
+                    holder.getEntityName()))
+                {
+                    return true;
+                }
+            }
+            if (holder.getObjectDigestInfo() != null)
+            {
+                MessageDigest md = null;
+                try
+                {
+                    md = MessageDigest.getInstance(getDigestAlgorithm(), "BC");
+
+                }
+                catch (Exception e)
+                {
+                    return false;
+                }
+                switch (getDigestedObjectType())
+                {
+                case ObjectDigestInfo.publicKey:
+                    // TODO: DSA Dss-parms
+                    md.update(cert.getPublicKey().getEncoded());
+                    break;
+                case ObjectDigestInfo.publicKeyCert:
+                    md.update(cert.getEncoded());
+                    break;
+                }
+                if (!Arrays.areEqual(md.digest(), getObjectDigest()))
+                {
+                    return false;
+                }
+            }
+        }
+        catch (CertificateEncodingException e)
+        {
+            return false;
+        }
+
+        return false;
+    }
+
+    public boolean equals(Object obj)
+    {
+        if (obj == this)
+        {
+            return true;
+        }
+
+        if (!(obj instanceof AttributeCertificateHolder))
+        {
+            return false;
+        }
+
+        AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
+
+        return this.holder.equals(other.holder);
+    }
+
+    public int hashCode()
+    {
+        return this.holder.hashCode();
+    }
+
+    public boolean match(Object obj)
+    {
+        if (!(obj instanceof X509Certificate))
+        {
+            return false;
+        }
+
+        return match((Certificate)obj);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/AttributeCertificateIssuer.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/AttributeCertificateIssuer.java
new file mode 100644
index 0000000..0100d06
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/AttributeCertificateIssuer.java
@@ -0,0 +1,210 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.CertSelector;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AttCertIssuer;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralNames;
+import com.android.internal.org.bouncycastle.asn1.x509.V2Form;
+import com.android.internal.org.bouncycastle.jce.X509Principal;
+import com.android.internal.org.bouncycastle.util.Selector;
+
+/**
+ * Carrying class for an attribute certificate issuer.
+ * @deprecated use org.bouncycastle.cert.AttributeCertificateIssuer
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AttributeCertificateIssuer
+    implements CertSelector, Selector
+{
+    final ASN1Encodable form;
+
+    /**
+     * Set the issuer directly with the ASN.1 structure.
+     * 
+     * @param issuer The issuer
+     */
+    public AttributeCertificateIssuer(AttCertIssuer issuer)
+    {
+        form = issuer.getIssuer();
+    }
+
+    public AttributeCertificateIssuer(X500Principal principal)
+        throws IOException
+    {
+        this(new X509Principal(principal.getEncoded()));
+    }
+
+    public AttributeCertificateIssuer(X509Principal principal)
+    {
+        form = new V2Form(GeneralNames.getInstance(new DERSequence(new GeneralName(principal))));
+    }
+
+    private Object[] getNames()
+    {
+        GeneralNames name;
+
+        if (form instanceof V2Form)
+        {
+            name = ((V2Form)form).getIssuerName();
+        }
+        else
+        {
+            name = (GeneralNames)form;
+        }
+
+        GeneralName[] names = name.getNames();
+
+        List l = new ArrayList(names.length);
+
+        for (int i = 0; i != names.length; i++)
+        {
+            if (names[i].getTagNo() == GeneralName.directoryName)
+            {
+                try
+                {
+                    l.add(new X500Principal(
+                        ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+                }
+                catch (IOException e)
+                {
+                    throw new RuntimeException("badly formed Name object");
+                }
+            }
+        }
+
+        return l.toArray(new Object[l.size()]);
+    }
+
+    /**
+     * Return any principal objects inside the attribute certificate issuer
+     * object.
+     * 
+     * @return an array of Principal objects (usually X500Principal)
+     */
+    public Principal[] getPrincipals()
+    {
+        Object[] p = this.getNames();
+        List l = new ArrayList();
+
+        for (int i = 0; i != p.length; i++)
+        {
+            if (p[i] instanceof Principal)
+            {
+                l.add(p[i]);
+            }
+        }
+
+        return (Principal[])l.toArray(new Principal[l.size()]);
+    }
+
+    private boolean matchesDN(X500Principal subject, GeneralNames targets)
+    {
+        GeneralName[] names = targets.getNames();
+
+        for (int i = 0; i != names.length; i++)
+        {
+            GeneralName gn = names[i];
+
+            if (gn.getTagNo() == GeneralName.directoryName)
+            {
+                try
+                {
+                    if (new X500Principal(((ASN1Encodable)gn.getName()).toASN1Primitive().getEncoded()).equals(subject))
+                    {
+                        return true;
+                    }
+                }
+                catch (IOException e)
+                {
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public Object clone()
+    {
+        return new AttributeCertificateIssuer(AttCertIssuer.getInstance(form));
+    }
+
+    public boolean match(Certificate cert)
+    {
+        if (!(cert instanceof X509Certificate))
+        {
+            return false;
+        }
+
+        X509Certificate x509Cert = (X509Certificate)cert;
+
+        if (form instanceof V2Form)
+        {
+            V2Form issuer = (V2Form)form;
+            if (issuer.getBaseCertificateID() != null)
+            {
+                return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+                    && matchesDN(x509Cert.getIssuerX500Principal(), issuer.getBaseCertificateID().getIssuer());
+            }
+
+            GeneralNames name = issuer.getIssuerName();
+            if (matchesDN(x509Cert.getSubjectX500Principal(), name))
+            {
+                return true;
+            }
+        }
+        else
+        {
+            GeneralNames name = (GeneralNames)form;
+            if (matchesDN(x509Cert.getSubjectX500Principal(), name))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public boolean equals(Object obj)
+    {
+        if (obj == this)
+        {
+            return true;
+        }
+
+        if (!(obj instanceof AttributeCertificateIssuer))
+        {
+            return false;
+        }
+
+        AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;
+
+        return this.form.equals(other.form);
+    }
+
+    public int hashCode()
+    {
+        return this.form.hashCode();
+    }
+
+    public boolean match(Object obj)
+    {
+        if (!(obj instanceof X509Certificate))
+        {
+            return false;
+        }
+
+        return match((Certificate)obj);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/ExtCertificateEncodingException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/ExtCertificateEncodingException.java
new file mode 100644
index 0000000..a899acd
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/ExtCertificateEncodingException.java
@@ -0,0 +1,21 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.security.cert.CertificateEncodingException;
+
+class ExtCertificateEncodingException
+    extends CertificateEncodingException
+{
+    Throwable cause;
+
+    ExtCertificateEncodingException(String message, Throwable cause)
+    {
+        super(message);
+        this.cause = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/ExtendedPKIXBuilderParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/ExtendedPKIXBuilderParameters.java
new file mode 100644
index 0000000..7e7d63d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/ExtendedPKIXBuilderParameters.java
@@ -0,0 +1,213 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import com.android.internal.org.bouncycastle.util.Selector;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class contains extended parameters for PKIX certification path builders.
+ * 
+ * @see java.security.cert.PKIXBuilderParameters
+ * @see com.android.internal.org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi
+ * @deprecated use PKIXExtendedBuilderParameters
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ExtendedPKIXBuilderParameters extends ExtendedPKIXParameters
+{
+
+    private int maxPathLength = 5;
+
+    private Set excludedCerts = Collections.EMPTY_SET;
+
+    /**
+     * Excluded certificates are not used for building a certification path.
+     * <p>
+     * The returned set is immutable.
+     * 
+     * @return Returns the excluded certificates.
+     */
+    public Set getExcludedCerts()
+    {
+        return Collections.unmodifiableSet(excludedCerts);
+    }
+
+    /**
+     * Sets the excluded certificates which are not used for building a
+     * certification path. If the <code>Set</code> is <code>null</code> an
+     * empty set is assumed.
+     * <p>
+     * The given set is cloned to protect it against subsequent modifications.
+     * 
+     * @param excludedCerts The excluded certificates to set.
+     */
+    public void setExcludedCerts(Set excludedCerts)
+    {
+        if (excludedCerts == null)
+        {
+            excludedCerts = Collections.EMPTY_SET;
+        }
+        else
+        {
+            this.excludedCerts = new HashSet(excludedCerts);
+        }
+    }
+
+    /**
+     * Creates an instance of <code>PKIXBuilderParameters</code> with the
+     * specified <code>Set</code> of most-trusted CAs. Each element of the set
+     * is a {@link TrustAnchor TrustAnchor}.
+     * 
+     * <p>
+     * Note that the <code>Set</code> is copied to protect against subsequent
+     * modifications.
+     * 
+     * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
+     * @param targetConstraints a <code>Selector</code> specifying the
+     *            constraints on the target certificate or attribute
+     *            certificate.
+     * @throws InvalidAlgorithmParameterException if <code>trustAnchors</code>
+     *             is empty.
+     * @throws NullPointerException if <code>trustAnchors</code> is
+     *             <code>null</code>
+     * @throws ClassCastException if any of the elements of
+     *             <code>trustAnchors</code> is not of type
+     *             <code>java.security.cert.TrustAnchor</code>
+     */
+    public ExtendedPKIXBuilderParameters(Set trustAnchors,
+            Selector targetConstraints)
+            throws InvalidAlgorithmParameterException
+    {
+        super(trustAnchors);
+        setTargetConstraints(targetConstraints);
+    }
+
+    /**
+     * Sets the maximum number of intermediate non-self-issued certificates in a
+     * certification path. The PKIX <code>CertPathBuilder</code> must not
+     * build paths longer then this length.
+     * <p>
+     * A value of 0 implies that the path can only contain a single certificate.
+     * A value of -1 does not limit the length. The default length is 5.
+     * 
+     * <p>
+     * 
+     * The basic constraints extension of a CA certificate overrides this value
+     * if smaller.
+     * 
+     * @param maxPathLength the maximum number of non-self-issued intermediate
+     *            certificates in the certification path
+     * @throws InvalidParameterException if <code>maxPathLength</code> is set
+     *             to a value less than -1
+     * 
+     * @see com.android.internal.org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi
+     * @see #getMaxPathLength
+     */
+    public void setMaxPathLength(int maxPathLength)
+    {
+        if (maxPathLength < -1)
+        {
+            throw new InvalidParameterException("The maximum path "
+                    + "length parameter can not be less than -1.");
+        }
+        this.maxPathLength = maxPathLength;
+    }
+
+    /**
+     * Returns the value of the maximum number of intermediate non-self-issued
+     * certificates in the certification path.
+     * 
+     * @return the maximum number of non-self-issued intermediate certificates
+     *         in the certification path, or -1 if no limit exists.
+     * 
+     * @see #setMaxPathLength(int)
+     */
+    public int getMaxPathLength()
+    {
+        return maxPathLength;
+    }
+
+    /**
+     * Can alse handle <code>ExtendedPKIXBuilderParameters</code> and
+     * <code>PKIXBuilderParameters</code>.
+     * 
+     * @param params Parameters to set.
+     * @see com.android.internal.org.bouncycastle.x509.ExtendedPKIXParameters#setParams(java.security.cert.PKIXParameters)
+     */
+    protected void setParams(PKIXParameters params)
+    {
+        super.setParams(params);
+        if (params instanceof ExtendedPKIXBuilderParameters)
+        {
+            ExtendedPKIXBuilderParameters _params = (ExtendedPKIXBuilderParameters) params;
+            maxPathLength = _params.maxPathLength;
+            excludedCerts = new HashSet(_params.excludedCerts);
+        }
+        if (params instanceof PKIXBuilderParameters)
+        {
+            PKIXBuilderParameters _params = (PKIXBuilderParameters) params;
+            maxPathLength = _params.getMaxPathLength();
+        }
+    }
+
+    /**
+     * Makes a copy of this <code>PKIXParameters</code> object. Changes to the
+     * copy will not affect the original and vice versa.
+     * 
+     * @return a copy of this <code>PKIXParameters</code> object
+     */
+    public Object clone()
+    {
+        ExtendedPKIXBuilderParameters params = null;
+        try
+        {
+            params = new ExtendedPKIXBuilderParameters(getTrustAnchors(),
+                    getTargetConstraints());
+        }
+        catch (Exception e)
+        {
+            // cannot happen
+            throw new RuntimeException(e.getMessage());
+        }
+        params.setParams(this);
+        return params;
+    }
+
+    /**
+     * Returns an instance of <code>ExtendedPKIXParameters</code> which can be
+     * safely casted to <code>ExtendedPKIXBuilderParameters</code>.
+     * <p>
+     * This method can be used to get a copy from other
+     * <code>PKIXBuilderParameters</code>, <code>PKIXParameters</code>,
+     * and <code>ExtendedPKIXParameters</code> instances.
+     * 
+     * @param pkixParams The PKIX parameters to create a copy of.
+     * @return An <code>ExtendedPKIXBuilderParameters</code> instance.
+     */
+    public static ExtendedPKIXParameters getInstance(PKIXParameters pkixParams)
+    {
+        ExtendedPKIXBuilderParameters params;
+        try
+        {
+            params = new ExtendedPKIXBuilderParameters(pkixParams
+                    .getTrustAnchors(), X509CertStoreSelector
+                    .getInstance((X509CertSelector) pkixParams
+                            .getTargetCertConstraints()));
+        }
+        catch (Exception e)
+        {
+            // cannot happen
+            throw new RuntimeException(e.getMessage());
+        }
+        params.setParams(pkixParams);
+        return params;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/ExtendedPKIXParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/ExtendedPKIXParameters.java
new file mode 100644
index 0000000..9a28dd1
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/ExtendedPKIXParameters.java
@@ -0,0 +1,662 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import com.android.internal.org.bouncycastle.util.Selector;
+import com.android.internal.org.bouncycastle.util.Store;
+
+/**
+ * This class extends the PKIXParameters with a validity model parameter.
+ *
+ * @deprecated use PKIXExtendedParameters
+ * @hide This class is not part of the Android public SDK API
+ */
+public class ExtendedPKIXParameters
+    extends PKIXParameters
+{
+
+    private List stores;
+
+    private Selector selector;
+
+    private boolean additionalLocationsEnabled;
+
+    private List additionalStores;
+
+    private Set trustedACIssuers;
+
+    private Set necessaryACAttributes;
+
+    private Set prohibitedACAttributes;
+
+    private Set attrCertCheckers;
+
+    /**
+     * Creates an instance of <code>PKIXParameters</code> with the specified
+     * <code>Set</code> of most-trusted CAs. Each element of the set is a
+     * {@link TrustAnchor TrustAnchor}.
+     * <p>
+     *     Note that the <code>Set</code>
+     * is copied to protect against subsequent modifications.
+     * </p>
+     * 
+     * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
+     * @throws InvalidAlgorithmParameterException if the specified
+     *             <code>Set</code> is empty.
+     * @throws NullPointerException if the specified <code>Set</code> is
+     *             <code>null</code>
+     * @throws ClassCastException if any of the elements in the <code>Set</code>
+     *             is not of type <code>java.security.cert.TrustAnchor</code>
+     */
+    public ExtendedPKIXParameters(Set trustAnchors)
+        throws InvalidAlgorithmParameterException
+    {
+        super(trustAnchors);
+        stores = new ArrayList();
+        additionalStores = new ArrayList();
+        trustedACIssuers = new HashSet();
+        necessaryACAttributes = new HashSet();
+        prohibitedACAttributes = new HashSet();
+        attrCertCheckers = new HashSet();
+    }
+
+    /**
+     * Returns an instance with the parameters of a given
+     * <code>PKIXParameters</code> object.
+     * 
+     * @param pkixParams The given <code>PKIXParameters</code>
+     * @return an extended PKIX params object
+     */
+    public static ExtendedPKIXParameters getInstance(PKIXParameters pkixParams)
+    {
+        ExtendedPKIXParameters params;
+        try
+        {
+            params = new ExtendedPKIXParameters(pkixParams.getTrustAnchors());
+        }
+        catch (Exception e)
+        {
+            // cannot happen
+            throw new RuntimeException(e.getMessage());
+        }
+        params.setParams(pkixParams);
+        return params;
+    }
+
+    /**
+     * Method to support <code>clone()</code> under J2ME.
+     * <code>super.clone()</code> does not exist and fields are not copied.
+     * 
+     * @param params Parameters to set. If this are
+     *            <code>ExtendedPKIXParameters</code> they are copied to.
+     */
+    protected void setParams(PKIXParameters params)
+    {
+        setDate(params.getDate());
+        setCertPathCheckers(params.getCertPathCheckers());
+        setCertStores(params.getCertStores());
+        setAnyPolicyInhibited(params.isAnyPolicyInhibited());
+        setExplicitPolicyRequired(params.isExplicitPolicyRequired());
+        setPolicyMappingInhibited(params.isPolicyMappingInhibited());
+        setRevocationEnabled(params.isRevocationEnabled());
+        setInitialPolicies(params.getInitialPolicies());
+        setPolicyQualifiersRejected(params.getPolicyQualifiersRejected());
+        setSigProvider(params.getSigProvider());
+        setTargetCertConstraints(params.getTargetCertConstraints());
+        try
+        {
+            setTrustAnchors(params.getTrustAnchors());
+        }
+        catch (Exception e)
+        {
+            // cannot happen
+            throw new RuntimeException(e.getMessage());
+        }
+        if (params instanceof ExtendedPKIXParameters)
+        {
+            ExtendedPKIXParameters _params = (ExtendedPKIXParameters) params;
+            validityModel = _params.validityModel;
+            useDeltas = _params.useDeltas;
+            additionalLocationsEnabled = _params.additionalLocationsEnabled;
+            selector = _params.selector == null ? null
+                : (Selector) _params.selector.clone();
+            stores = new ArrayList(_params.stores);
+            additionalStores = new ArrayList(_params.additionalStores);
+            trustedACIssuers = new HashSet(_params.trustedACIssuers);
+            prohibitedACAttributes = new HashSet(_params.prohibitedACAttributes);
+            necessaryACAttributes = new HashSet(_params.necessaryACAttributes);
+            attrCertCheckers = new HashSet(_params.attrCertCheckers);
+        }
+    }
+
+    /**
+     * This is the default PKIX validity model. Actually there are two variants
+     * of this: The PKIX model and the modified PKIX model. The PKIX model
+     * verifies that all involved certificates must have been valid at the
+     * current time. The modified PKIX model verifies that all involved
+     * certificates were valid at the signing time. Both are indirectly choosen
+     * with the {@link PKIXParameters#setDate(java.util.Date)} method, so this
+     * methods sets the Date when <em>all</em> certificates must have been
+     * valid.
+     */
+    public static final int PKIX_VALIDITY_MODEL = 0;
+
+    /**
+     * This model uses the following validity model. Each certificate must have
+     * been valid at the moment where is was used. That means the end
+     * certificate must have been valid at the time the signature was done. The
+     * CA certificate which signed the end certificate must have been valid,
+     * when the end certificate was signed. The CA (or Root CA) certificate must
+     * have been valid, when the CA certificate was signed and so on. So the
+     * {@link PKIXParameters#setDate(java.util.Date)} method sets the time, when
+     * the <em>end certificate</em> must have been valid.
+     * <p>
+     * It is used e.g.
+     * in the German signature law.
+     * </p>
+     */
+    public static final int CHAIN_VALIDITY_MODEL = 1;
+
+    private int validityModel = PKIX_VALIDITY_MODEL;
+
+    private boolean useDeltas = false;
+
+    /**
+     * Defaults to <code>false</code>.
+     * 
+     * @return Returns if delta CRLs should be used.
+     */
+    public boolean isUseDeltasEnabled()
+    {
+        return useDeltas;
+    }
+
+    /**
+     * Sets if delta CRLs should be used for checking the revocation status.
+     * 
+     * @param useDeltas <code>true</code> if delta CRLs should be used.
+     */
+    public void setUseDeltasEnabled(boolean useDeltas)
+    {
+        this.useDeltas = useDeltas;
+    }
+
+    /**
+     * @return Returns the validity model.
+     * @see #CHAIN_VALIDITY_MODEL
+     * @see #PKIX_VALIDITY_MODEL
+     */
+    public int getValidityModel()
+    {
+        return validityModel;
+    }
+
+    /**
+     * Sets the Java CertStore to this extended PKIX parameters.
+     * 
+     * @throws ClassCastException if an element of <code>stores</code> is not
+     *             a <code>CertStore</code>.
+     */
+    public void setCertStores(List stores)
+    {
+        if (stores != null)
+        {
+            Iterator it = stores.iterator();
+            while (it.hasNext())
+            {
+                addCertStore((CertStore)it.next());
+            }
+        }
+    }
+
+    /**
+     * Sets the Bouncy Castle Stores for finding CRLs, certificates, attribute
+     * certificates or cross certificates.
+     * <p>
+     * The <code>List</code> is cloned.
+     * 
+     * @param stores A list of stores to use.
+     * @see #getStores
+     * @throws ClassCastException if an element of <code>stores</code> is not
+     *             a {@link Store}.
+     */
+    public void setStores(List stores)
+    {
+        if (stores == null)
+        {
+            this.stores = new ArrayList();
+        }
+        else
+        {
+            for (Iterator i = stores.iterator(); i.hasNext();)
+            {
+                if (!(i.next() instanceof Store))
+                {
+                    throw new ClassCastException(
+                        "All elements of list must be "
+                            + "of type com.android.internal.org.bouncycastle.util.Store.");
+                }
+            }
+            this.stores = new ArrayList(stores);
+        }
+    }
+
+    /**
+     * Adds a Bouncy Castle {@link Store} to find CRLs, certificates, attribute
+     * certificates or cross certificates.
+     * <p>
+     * This method should be used to add local stores, like collection based
+     * X.509 stores, if available. Local stores should be considered first,
+     * before trying to use additional (remote) locations, because they do not
+     * need possible additional network traffic.
+     * <p>
+     * If <code>store</code> is <code>null</code> it is ignored.
+     * 
+     * @param store The store to add.
+     * @see #getStores
+     */
+    public void addStore(Store store)
+    {
+        if (store != null)
+        {
+            stores.add(store);
+        }
+    }
+
+    /**
+     * Adds an additional Bouncy Castle {@link Store} to find CRLs, certificates,
+     * attribute certificates or cross certificates.
+     * <p>
+     * You should not use this method. This method is used for adding additional
+     * X.509 stores, which are used to add (remote) locations, e.g. LDAP, found
+     * during X.509 object processing, e.g. in certificates or CRLs. This method
+     * is used in PKIX certification path processing.
+     * <p>
+     * If <code>store</code> is <code>null</code> it is ignored.
+     * 
+     * @param store The store to add.
+     * @see #getStores()
+     * @deprecated use addStore().
+     */
+    public void addAdditionalStore(Store store)
+    {
+        if (store != null)
+        {
+            additionalStores.add(store);
+        }
+    }
+
+    /**
+     * @deprecated
+     */
+    public void addAddionalStore(Store store)
+    {
+        addAdditionalStore(store);      
+    }
+
+    /**
+     * Returns an immutable <code>List</code> of additional Bouncy Castle
+     * <code>Store</code>s used for finding CRLs, certificates, attribute
+     * certificates or cross certificates.
+     * 
+     * @return an immutable <code>List</code> of additional Bouncy Castle
+     *         <code>Store</code>s. Never <code>null</code>.
+     * 
+     * @see #addAdditionalStore(Store)
+     */
+    public List getAdditionalStores()
+    {
+        return Collections.unmodifiableList(additionalStores);
+    }
+
+    /**
+     * Returns an immutable <code>List</code> of Bouncy Castle
+     * <code>Store</code>s used for finding CRLs, certificates, attribute
+     * certificates or cross certificates.
+     * 
+     * @return an immutable <code>List</code> of Bouncy Castle
+     *         <code>Store</code>s. Never <code>null</code>.
+     * 
+     * @see #setStores(List)
+     */
+    public List getStores()
+    {
+        return Collections.unmodifiableList(new ArrayList(stores));
+    }
+
+    /**
+     * @param validityModel The validity model to set.
+     * @see #CHAIN_VALIDITY_MODEL
+     * @see #PKIX_VALIDITY_MODEL
+     */
+    public void setValidityModel(int validityModel)
+    {
+        this.validityModel = validityModel;
+    }
+
+    public Object clone()
+    {
+        ExtendedPKIXParameters params;
+        try
+        {
+            params = new ExtendedPKIXParameters(getTrustAnchors());
+        }
+        catch (Exception e)
+        {
+            // cannot happen
+            throw new RuntimeException(e.getMessage());
+        }
+        params.setParams(this);
+        return params;
+    }
+
+    /**
+     * Returns if additional {@link X509Store}s for locations like LDAP found
+     * in certificates or CRLs should be used.
+     * 
+     * @return Returns <code>true</code> if additional stores are used.
+     */
+    public boolean isAdditionalLocationsEnabled()
+    {
+        return additionalLocationsEnabled;
+    }
+
+    /**
+     * Sets if additional {@link X509Store}s for locations like LDAP found in
+     * certificates or CRLs should be used.
+     * 
+     * @param enabled <code>true</code> if additional stores are used.
+     */
+    public void setAdditionalLocationsEnabled(boolean enabled)
+    {
+        additionalLocationsEnabled = enabled;
+    }
+
+    /**
+     * Returns the required constraints on the target certificate or attribute
+     * certificate. The constraints are returned as an instance of
+     * <code>Selector</code>. If <code>null</code>, no constraints are
+     * defined.
+     * 
+     * <p>
+     * The target certificate in a PKIX path may be a certificate or an
+     * attribute certificate.
+     * <p>
+     * Note that the <code>Selector</code> returned is cloned to protect
+     * against subsequent modifications.
+     * 
+     * @return a <code>Selector</code> specifying the constraints on the
+     *         target certificate or attribute certificate (or <code>null</code>)
+     * @see #setTargetConstraints
+     * @see X509CertStoreSelector
+     * @see X509AttributeCertStoreSelector
+     */
+    public Selector getTargetConstraints()
+    {
+        if (selector != null)
+        {
+            return (Selector) selector.clone();
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    /**
+     * Sets the required constraints on the target certificate or attribute
+     * certificate. The constraints are specified as an instance of
+     * <code>Selector</code>. If <code>null</code>, no constraints are
+     * defined.
+     * <p>
+     * The target certificate in a PKIX path may be a certificate or an
+     * attribute certificate.
+     * <p>
+     * Note that the <code>Selector</code> specified is cloned to protect
+     * against subsequent modifications.
+     * 
+     * @param selector a <code>Selector</code> specifying the constraints on
+     *            the target certificate or attribute certificate (or
+     *            <code>null</code>)
+     * @see #getTargetConstraints
+     * @see X509CertStoreSelector
+     * @see X509AttributeCertStoreSelector
+     */
+    public void setTargetConstraints(Selector selector)
+    {
+        if (selector != null)
+        {
+            this.selector = (Selector) selector.clone();
+        }
+        else
+        {
+            this.selector = null;
+        }
+    }
+
+    /**
+     * Sets the required constraints on the target certificate. The constraints
+     * are specified as an instance of <code>X509CertSelector</code>. If
+     * <code>null</code>, no constraints are defined.
+     * 
+     * <p>
+     * This method wraps the given <code>X509CertSelector</code> into a
+     * <code>X509CertStoreSelector</code>.
+     * <p>
+     * Note that the <code>X509CertSelector</code> specified is cloned to
+     * protect against subsequent modifications.
+     * 
+     * @param selector a <code>X509CertSelector</code> specifying the
+     *            constraints on the target certificate (or <code>null</code>)
+     * @see #getTargetCertConstraints
+     * @see X509CertStoreSelector
+     */
+    public void setTargetCertConstraints(CertSelector selector)
+    {
+        super.setTargetCertConstraints(selector);
+        if (selector != null)
+        {
+            this.selector = X509CertStoreSelector
+                .getInstance((X509CertSelector) selector);
+        }
+        else
+        {
+            this.selector = null;
+        }
+    }
+
+    /**
+     * Returns the trusted attribute certificate issuers. If attribute
+     * certificates is verified the trusted AC issuers must be set.
+     * <p>
+     * The returned <code>Set</code> consists of <code>TrustAnchor</code>s.
+     * <p>
+     * The returned <code>Set</code> is immutable. Never <code>null</code>
+     * 
+     * @return Returns an immutable set of the trusted AC issuers.
+     */
+    public Set getTrustedACIssuers()
+    {
+        return Collections.unmodifiableSet(trustedACIssuers);
+    }
+
+    /**
+     * Sets the trusted attribute certificate issuers. If attribute certificates
+     * is verified the trusted AC issuers must be set.
+     * <p>
+     * The <code>trustedACIssuers</code> must be a <code>Set</code> of
+     * <code>TrustAnchor</code>
+     * <p>
+     * The given set is cloned.
+     * 
+     * @param trustedACIssuers The trusted AC issuers to set. Is never
+     *            <code>null</code>.
+     * @throws ClassCastException if an element of <code>stores</code> is not
+     *             a <code>TrustAnchor</code>.
+     */
+    public void setTrustedACIssuers(Set trustedACIssuers)
+    {
+        if (trustedACIssuers == null)
+        {
+            this.trustedACIssuers.clear();
+            return;
+        }
+        for (Iterator it = trustedACIssuers.iterator(); it.hasNext();)
+        {
+            if (!(it.next() instanceof TrustAnchor))
+            {
+                throw new ClassCastException("All elements of set must be "
+                    + "of type " + TrustAnchor.class.getName() + ".");
+            }
+        }
+        this.trustedACIssuers.clear();
+        this.trustedACIssuers.addAll(trustedACIssuers);
+    }
+
+    /**
+     * Returns the neccessary attributes which must be contained in an attribute
+     * certificate.
+     * <p>
+     * The returned <code>Set</code> is immutable and contains
+     * <code>String</code>s with the OIDs.
+     * 
+     * @return Returns the necessary AC attributes.
+     */
+    public Set getNecessaryACAttributes()
+    {
+        return Collections.unmodifiableSet(necessaryACAttributes);
+    }
+
+    /**
+     * Sets the neccessary which must be contained in an attribute certificate.
+     * <p>
+     * The <code>Set</code> must contain <code>String</code>s with the
+     * OIDs.
+     * <p>
+     * The set is cloned.
+     * 
+     * @param necessaryACAttributes The necessary AC attributes to set.
+     * @throws ClassCastException if an element of
+     *             <code>necessaryACAttributes</code> is not a
+     *             <code>String</code>.
+     */
+    public void setNecessaryACAttributes(Set necessaryACAttributes)
+    {
+        if (necessaryACAttributes == null)
+        {
+            this.necessaryACAttributes.clear();
+            return;
+        }
+        for (Iterator it = necessaryACAttributes.iterator(); it.hasNext();)
+        {
+            if (!(it.next() instanceof String))
+            {
+                throw new ClassCastException("All elements of set must be "
+                    + "of type String.");
+            }
+        }
+        this.necessaryACAttributes.clear();
+        this.necessaryACAttributes.addAll(necessaryACAttributes);
+    }
+
+    /**
+     * Returns the attribute certificates which are not allowed.
+     * <p>
+     * The returned <code>Set</code> is immutable and contains
+     * <code>String</code>s with the OIDs.
+     * 
+     * @return Returns the prohibited AC attributes. Is never <code>null</code>.
+     */
+    public Set getProhibitedACAttributes()
+    {
+        return Collections.unmodifiableSet(prohibitedACAttributes);
+    }
+
+    /**
+     * Sets the attribute certificates which are not allowed.
+     * <p>
+     * The <code>Set</code> must contain <code>String</code>s with the
+     * OIDs.
+     * <p>
+     * The set is cloned.
+     * 
+     * @param prohibitedACAttributes The prohibited AC attributes to set.
+     * @throws ClassCastException if an element of
+     *             <code>prohibitedACAttributes</code> is not a
+     *             <code>String</code>.
+     */
+    public void setProhibitedACAttributes(Set prohibitedACAttributes)
+    {
+        if (prohibitedACAttributes == null)
+        {
+            this.prohibitedACAttributes.clear();
+            return;
+        }
+        for (Iterator it = prohibitedACAttributes.iterator(); it.hasNext();)
+        {
+            if (!(it.next() instanceof String))
+            {
+                throw new ClassCastException("All elements of set must be "
+                    + "of type String.");
+            }
+        }
+        this.prohibitedACAttributes.clear();
+        this.prohibitedACAttributes.addAll(prohibitedACAttributes);
+    }
+
+    /**
+     * Returns the attribute certificate checker. The returned set contains
+     * {@link PKIXAttrCertChecker}s and is immutable.
+     * 
+     * @return Returns the attribute certificate checker. Is never
+     *         <code>null</code>.
+     */
+    public Set getAttrCertCheckers()
+    {
+        return Collections.unmodifiableSet(attrCertCheckers);
+    }
+
+    /**
+     * Sets the attribute certificate checkers.
+     * <p>
+     * All elements in the <code>Set</code> must a {@link PKIXAttrCertChecker}.
+     * <p>
+     * The given set is cloned.
+     * 
+     * @param attrCertCheckers The attribute certificate checkers to set. Is
+     *            never <code>null</code>.
+     * @throws ClassCastException if an element of <code>attrCertCheckers</code>
+     *             is not a <code>PKIXAttrCertChecker</code>.
+     */
+    public void setAttrCertCheckers(Set attrCertCheckers)
+    {
+        if (attrCertCheckers == null)
+        {
+            this.attrCertCheckers.clear();
+            return;
+        }
+        for (Iterator it = attrCertCheckers.iterator(); it.hasNext();)
+        {
+            if (!(it.next() instanceof PKIXAttrCertChecker))
+            {
+                throw new ClassCastException("All elements of set must be "
+                    + "of type " + PKIXAttrCertChecker.class.getName() + ".");
+            }
+        }
+        this.attrCertCheckers.clear();
+        this.attrCertCheckers.addAll(attrCertCheckers);
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/NoSuchStoreException.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/NoSuchStoreException.java
new file mode 100644
index 0000000..008f558
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/NoSuchStoreException.java
@@ -0,0 +1,14 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class NoSuchStoreException
+    extends Exception
+{
+    public NoSuchStoreException(String message)
+    {
+        super(message);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/PKIXAttrCertChecker.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/PKIXAttrCertChecker.java
new file mode 100644
index 0000000..24d2655
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/PKIXAttrCertChecker.java
@@ -0,0 +1,60 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class PKIXAttrCertChecker
+    implements Cloneable
+{
+
+    /**
+     * Returns an immutable <code>Set</code> of X.509 attribute certificate
+     * extensions that this <code>PKIXAttrCertChecker</code> supports or
+     * <code>null</code> if no extensions are supported.
+     * <p>
+     * Each element of the set is a <code>String</code> representing the
+     * Object Identifier (OID) of the X.509 extension that is supported.
+     * <p>
+     * All X.509 attribute certificate extensions that a
+     * <code>PKIXAttrCertChecker</code> might possibly be able to process
+     * should be included in the set.
+     * 
+     * @return an immutable <code>Set</code> of X.509 extension OIDs (in
+     *         <code>String</code> format) supported by this
+     *         <code>PKIXAttrCertChecker</code>, or <code>null</code> if no
+     *         extensions are supported
+     */
+    public abstract Set getSupportedExtensions();
+
+    /**
+     * Performs checks on the specified attribute certificate. Every handled
+     * extension is rmeoved from the <code>unresolvedCritExts</code>
+     * collection.
+     * 
+     * @param attrCert The attribute certificate to be checked.
+     * @param certPath The certificate path which belongs to the attribute
+     *            certificate issuer public key certificate.
+     * @param holderCertPath The certificate path which belongs to the holder
+     *            certificate.
+     * @param unresolvedCritExts a <code>Collection</code> of OID strings
+     *            representing the current set of unresolved critical extensions
+     * @throws CertPathValidatorException if the specified attribute certificate
+     *             does not pass the check.
+     */
+    public abstract void check(X509AttributeCertificate attrCert, CertPath certPath,
+                                 CertPath holderCertPath, Collection unresolvedCritExts)
+        throws CertPathValidatorException;
+
+    /**
+     * Returns a clone of this object.
+     * 
+     * @return a copy of this <code>PKIXAttrCertChecker</code>
+     */
+    public abstract Object clone();
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509Attribute.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509Attribute.java
new file mode 100644
index 0000000..d561b75
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509Attribute.java
@@ -0,0 +1,82 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Object;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1Set;
+import com.android.internal.org.bouncycastle.asn1.DERSet;
+import com.android.internal.org.bouncycastle.asn1.x509.Attribute;
+
+/**
+ * Class for carrying the values in an X.509 Attribute.
+ * @deprecated see X509CertificateHolder class in the PKIX package.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509Attribute
+    extends ASN1Object
+{
+    Attribute    attr;
+    
+    /**
+     * @param at an object representing an attribute.
+     */
+    X509Attribute(
+        ASN1Encodable   at)
+    {
+        this.attr = Attribute.getInstance(at);
+    }
+
+    /**
+     * Create an X.509 Attribute with the type given by the passed in oid and
+     * the value represented by an ASN.1 Set containing value.
+     * 
+     * @param oid type of the attribute
+     * @param value value object to go into the atribute's value set.
+     */
+    public X509Attribute(
+        String          oid,
+        ASN1Encodable   value)
+    {
+        this.attr = new Attribute(new ASN1ObjectIdentifier(oid), new DERSet(value));
+    }
+    
+    /**
+     * Create an X.59 Attribute with the type given by the passed in oid and the
+     * value represented by an ASN.1 Set containing the objects in value.
+     * 
+     * @param oid type of the attribute
+     * @param value vector of values to go in the attribute's value set.
+     */
+    public X509Attribute(
+        String              oid,
+        ASN1EncodableVector value)
+    {
+        this.attr = new Attribute(new ASN1ObjectIdentifier(oid), new DERSet(value));
+    }
+    
+    public String getOID()
+    {
+        return attr.getAttrType().getId();
+    }
+    
+    public ASN1Encodable[] getValues()
+    {
+        ASN1Set         s = attr.getAttrValues();
+        ASN1Encodable[] values = new ASN1Encodable[s.size()];
+        
+        for (int i = 0; i != s.size(); i++)
+        {
+            values[i] = (ASN1Encodable)s.getObjectAt(i);
+        }
+        
+        return values;
+    }
+    
+    public ASN1Primitive toASN1Primitive()
+    {
+        return attr.toASN1Primitive();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509AttributeCertificate.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509AttributeCertificate.java
new file mode 100644
index 0000000..49ec829
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509AttributeCertificate.java
@@ -0,0 +1,104 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Extension;
+import java.util.Date;
+
+/**
+ * Interface for an X.509 Attribute Certificate.
+ * @deprecated use X509CertificateHolder class in the PKIX package.
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface X509AttributeCertificate
+    extends X509Extension
+{   
+    /**
+     * Return the version number for the certificate.
+     * 
+     * @return the version number.
+     */
+    public int getVersion();
+    
+    /**
+     * Return the serial number for the certificate.
+     * 
+     * @return the serial number.
+     */
+    public BigInteger getSerialNumber();
+    
+    /**
+     * Return the date before which the certificate is not valid.
+     * 
+     * @return the "not valid before" date.
+     */
+    public Date getNotBefore();
+    
+    /**
+     * Return the date after which the certificate is not valid.
+     * 
+     * @return the "not valid afer" date.
+     */
+    public Date getNotAfter();
+    
+    /**
+     * Return the holder of the certificate.
+     * 
+     * @return the holder.
+     */
+    public AttributeCertificateHolder getHolder();
+    
+    /**
+     * Return the issuer details for the certificate.
+     * 
+     * @return the issuer details.
+     */
+    public AttributeCertificateIssuer getIssuer();
+    
+    /**
+     * Return the attributes contained in the attribute block in the certificate.
+     * 
+     * @return an array of attributes.
+     */
+    public X509Attribute[] getAttributes();
+    
+    /**
+     * Return the attributes with the same type as the passed in oid.
+     * 
+     * @param oid the object identifier we wish to match.
+     * @return an array of matched attributes, null if there is no match.
+     */
+    public X509Attribute[] getAttributes(String oid);
+    
+    public boolean[] getIssuerUniqueID();
+    
+    public void checkValidity()
+        throws CertificateExpiredException, CertificateNotYetValidException;
+    
+    public void checkValidity(Date date)
+        throws CertificateExpiredException, CertificateNotYetValidException;
+    
+    public byte[] getSignature();
+    
+    public void verify(PublicKey key, String provider)
+            throws CertificateException, NoSuchAlgorithmException,
+            InvalidKeyException, NoSuchProviderException, SignatureException;
+    
+    /**
+     * Return an ASN.1 encoded byte array representing the attribute certificate.
+     * 
+     * @return an ASN.1 encoded byte array.
+     * @throws IOException if the certificate cannot be encoded.
+     */
+    public byte[] getEncoded()
+        throws IOException;
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509CRLStoreSelector.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509CRLStoreSelector.java
new file mode 100644
index 0000000..09af8a5
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509CRLStoreSelector.java
@@ -0,0 +1,332 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRL;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLSelector;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.util.Arrays;
+import com.android.internal.org.bouncycastle.util.Selector;
+import com.android.internal.org.bouncycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * This class is a Selector implementation for X.509 certificate revocation
+ * lists.
+ * 
+ * @see com.android.internal.org.bouncycastle.util.Selector
+ * @see com.android.internal.org.bouncycastle.x509.X509Store
+ * @see com.android.internal.org.bouncycastle.jce.provider.X509StoreCRLCollection
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509CRLStoreSelector
+    extends X509CRLSelector
+    implements Selector
+{
+    private boolean deltaCRLIndicator = false;
+
+    private boolean completeCRLEnabled = false;
+
+    private BigInteger maxBaseCRLNumber = null;
+
+    private byte[] issuingDistributionPoint = null;
+
+    private boolean issuingDistributionPointEnabled = false;
+
+    private X509AttributeCertificate attrCertChecking;
+
+    /**
+     * Returns if the issuing distribution point criteria should be applied.
+     * Defaults to <code>false</code>.
+     * <p>
+     * You may also set the issuing distribution point criteria if not a missing
+     * issuing distribution point should be assumed.
+     * 
+     * @return Returns if the issuing distribution point check is enabled.
+     */
+    public boolean isIssuingDistributionPointEnabled()
+    {
+        return issuingDistributionPointEnabled;
+    }
+
+    /**
+     * Enables or disables the issuing distribution point check.
+     * 
+     * @param issuingDistributionPointEnabled <code>true</code> to enable the
+     *            issuing distribution point check.
+     */
+    public void setIssuingDistributionPointEnabled(
+        boolean issuingDistributionPointEnabled)
+    {
+        this.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+    }
+
+    /**
+     * Sets the attribute certificate being checked. This is not a criterion.
+     * Rather, it is optional information that may help a {@link X509Store} find
+     * CRLs that would be relevant when checking revocation for the specified
+     * attribute certificate. If <code>null</code> is specified, then no such
+     * optional information is provided.
+     * 
+     * @param attrCert the <code>X509AttributeCertificate</code> being checked (or
+     *            <code>null</code>)
+     * @see #getAttrCertificateChecking()
+     */
+    public void setAttrCertificateChecking(X509AttributeCertificate attrCert)
+    {
+        attrCertChecking = attrCert;
+    }
+
+    /**
+     * Returns the attribute certificate being checked.
+     * 
+     * @return Returns the attribute certificate being checked.
+     * @see #setAttrCertificateChecking(X509AttributeCertificate)
+     */
+    public X509AttributeCertificate getAttrCertificateChecking()
+    {
+        return attrCertChecking;
+    }
+
+    public boolean match(Object obj)
+    {
+        if (!(obj instanceof X509CRL))
+        {
+            return false;
+        }
+        X509CRL crl = (X509CRL)obj;
+        ASN1Integer dci = null;
+        try
+        {
+            byte[] bytes = crl
+                .getExtensionValue(Extension.deltaCRLIndicator.getId());
+            if (bytes != null)
+            {
+                dci = ASN1Integer.getInstance(X509ExtensionUtil
+                    .fromExtensionValue(bytes));
+            }
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+        if (isDeltaCRLIndicatorEnabled())
+        {
+            if (dci == null)
+            {
+                return false;
+            }
+        }
+        if (isCompleteCRLEnabled())
+        {
+            if (dci != null)
+            {
+                return false;
+            }
+        }
+        if (dci != null)
+        {
+
+            if (maxBaseCRLNumber != null)
+            {
+                if (dci.getPositiveValue().compareTo(maxBaseCRLNumber) == 1)
+                {
+                    return false;
+                }
+            }
+        }
+        if (issuingDistributionPointEnabled)
+        {
+            byte[] idp = crl
+                .getExtensionValue(Extension.issuingDistributionPoint
+                    .getId());
+            if (issuingDistributionPoint == null)
+            {
+                if (idp != null)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                if (!Arrays.areEqual(idp, issuingDistributionPoint))
+                {
+                    return false;
+                }
+            }
+
+        }
+        return super.match((X509CRL)obj);
+    }
+
+    public boolean match(CRL crl)
+    {
+        return match((Object)crl);
+    }
+
+    /**
+     * Returns if this selector must match CRLs with the delta CRL indicator
+     * extension set. Defaults to <code>false</code>.
+     * 
+     * @return Returns <code>true</code> if only CRLs with the delta CRL
+     *         indicator extension are selected.
+     */
+    public boolean isDeltaCRLIndicatorEnabled()
+    {
+        return deltaCRLIndicator;
+    }
+
+    /**
+     * If this is set to <code>true</code> the CRL reported contains the delta
+     * CRL indicator CRL extension.
+     * <p>
+     * {@link #setCompleteCRLEnabled(boolean)} and
+     * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+     * 
+     * @param deltaCRLIndicator <code>true</code> if the delta CRL indicator
+     *            extension must be in the CRL.
+     */
+    public void setDeltaCRLIndicatorEnabled(boolean deltaCRLIndicator)
+    {
+        this.deltaCRLIndicator = deltaCRLIndicator;
+    }
+
+    /**
+     * Returns an instance of this from a <code>X509CRLSelector</code>.
+     * 
+     * @param selector A <code>X509CRLSelector</code> instance.
+     * @return An instance of an <code>X509CRLStoreSelector</code>.
+     * @exception IllegalArgumentException if selector is null or creation
+     *                fails.
+     */
+    public static X509CRLStoreSelector getInstance(X509CRLSelector selector)
+    {
+        if (selector == null)
+        {
+            throw new IllegalArgumentException(
+                "cannot create from null selector");
+        }
+        X509CRLStoreSelector cs = new X509CRLStoreSelector();
+        cs.setCertificateChecking(selector.getCertificateChecking());
+        cs.setDateAndTime(selector.getDateAndTime());
+        try
+        {
+            cs.setIssuerNames(selector.getIssuerNames());
+        }
+        catch (IOException e)
+        {
+            // cannot happen
+            throw new IllegalArgumentException(e.getMessage());
+        }
+        cs.setIssuers(selector.getIssuers());
+        cs.setMaxCRLNumber(selector.getMaxCRL());
+        cs.setMinCRLNumber(selector.getMinCRL());
+        return cs;
+    }
+    
+    public Object clone()
+    {
+        X509CRLStoreSelector sel = X509CRLStoreSelector.getInstance(this);
+        sel.deltaCRLIndicator = deltaCRLIndicator;
+        sel.completeCRLEnabled = completeCRLEnabled;
+        sel.maxBaseCRLNumber = maxBaseCRLNumber;
+        sel.attrCertChecking = attrCertChecking;
+        sel.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+        sel.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+        return sel;
+    }
+
+    /**
+     * If <code>true</code> only complete CRLs are returned. Defaults to
+     * <code>false</code>.
+     * 
+     * @return <code>true</code> if only complete CRLs are returned.
+     */
+    public boolean isCompleteCRLEnabled()
+    {
+        return completeCRLEnabled;
+    }
+
+    /**
+     * If set to <code>true</code> only complete CRLs are returned.
+     * <p>
+     * {@link #setCompleteCRLEnabled(boolean)} and
+     * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+     * 
+     * @param completeCRLEnabled <code>true</code> if only complete CRLs
+     *            should be returned.
+     */
+    public void setCompleteCRLEnabled(boolean completeCRLEnabled)
+    {
+        this.completeCRLEnabled = completeCRLEnabled;
+    }
+
+    /**
+     * Get the maximum base CRL number. Defaults to <code>null</code>.
+     * 
+     * @return Returns the maximum base CRL number.
+     * @see #setMaxBaseCRLNumber(BigInteger)
+     */
+    public BigInteger getMaxBaseCRLNumber()
+    {
+        return maxBaseCRLNumber;
+    }
+
+    /**
+     * Sets the maximum base CRL number. Setting to <code>null</code> disables
+     * this cheack.
+     * <p>
+     * This is only meaningful for delta CRLs. Complete CRLs must have a CRL
+     * number which is greater or equal than the base number of the
+     * corresponding CRL.
+     * 
+     * @param maxBaseCRLNumber The maximum base CRL number to set.
+     */
+    public void setMaxBaseCRLNumber(BigInteger maxBaseCRLNumber)
+    {
+        this.maxBaseCRLNumber = maxBaseCRLNumber;
+    }
+
+    /**
+     * Returns the issuing distribution point. Defaults to <code>null</code>,
+     * which is a missing issuing distribution point extension.
+     * <p>
+     * The internal byte array is cloned before it is returned.
+     * <p>
+     * The criteria must be enable with
+     * {@link #setIssuingDistributionPointEnabled(boolean)}.
+     * 
+     * @return Returns the issuing distribution point.
+     * @see #setIssuingDistributionPoint(byte[])
+     */
+    public byte[] getIssuingDistributionPoint()
+    {
+        return Arrays.clone(issuingDistributionPoint);
+    }
+
+    /**
+     * Sets the issuing distribution point.
+     * <p>
+     * The issuing distribution point extension is a CRL extension which
+     * identifies the scope and the distribution point of a CRL. The scope
+     * contains among others information about revocation reasons contained in
+     * the CRL. Delta CRLs and complete CRLs must have matching issuing
+     * distribution points.
+     * <p>
+     * The byte array is cloned to protect against subsequent modifications.
+     * <p>
+     * You must also enable or disable this criteria with
+     * {@link #setIssuingDistributionPointEnabled(boolean)}.
+     * 
+     * @param issuingDistributionPoint The issuing distribution point to set.
+     *            This is the DER encoded OCTET STRING extension value.
+     * @see #getIssuingDistributionPoint()
+     */
+    public void setIssuingDistributionPoint(byte[] issuingDistributionPoint)
+    {
+        this.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509CertStoreSelector.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509CertStoreSelector.java
new file mode 100644
index 0000000..fad3661
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509CertStoreSelector.java
@@ -0,0 +1,90 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.security.cert.Certificate;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+
+import com.android.internal.org.bouncycastle.util.Selector;
+
+/**
+ * This class is a Selector implementation for X.509 certificates.
+ * 
+ * @see com.android.internal.org.bouncycastle.util.Selector
+ * @see com.android.internal.org.bouncycastle.x509.X509Store
+ * @see com.android.internal.org.bouncycastle.jce.provider.X509StoreCertCollection
+ * @deprecated use the classes under org.bouncycastle.cert.selector
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509CertStoreSelector
+    extends X509CertSelector
+    implements Selector
+{
+    public boolean match(Object obj)
+    {
+        if (!(obj instanceof X509Certificate))
+        {
+            return false;
+        }
+
+        X509Certificate other = (X509Certificate)obj;
+
+        return super.match(other);
+    }
+
+    public boolean match(Certificate cert)
+    {
+        return match((Object)cert);
+    }
+
+    public Object clone()
+    {
+        X509CertStoreSelector selector = (X509CertStoreSelector)super.clone();
+
+        return selector;
+    }
+
+    /**
+     * Returns an instance of this from a <code>X509CertSelector</code>.
+     *
+     * @param selector A <code>X509CertSelector</code> instance.
+     * @return An instance of an <code>X509CertStoreSelector</code>.
+     * @exception IllegalArgumentException if selector is null or creation fails.
+     */
+    public static X509CertStoreSelector getInstance(X509CertSelector selector)
+    {
+        if (selector == null)
+        {
+            throw new IllegalArgumentException("cannot create from null selector");
+        }
+        X509CertStoreSelector cs = new X509CertStoreSelector();
+        cs.setAuthorityKeyIdentifier(selector.getAuthorityKeyIdentifier());
+        cs.setBasicConstraints(selector.getBasicConstraints());
+        cs.setCertificate(selector.getCertificate());
+        cs.setCertificateValid(selector.getCertificateValid());
+        cs.setMatchAllSubjectAltNames(selector.getMatchAllSubjectAltNames());
+        try
+        {
+            cs.setPathToNames(selector.getPathToNames());
+            cs.setExtendedKeyUsage(selector.getExtendedKeyUsage());
+            cs.setNameConstraints(selector.getNameConstraints());
+            cs.setPolicy(selector.getPolicy());
+            cs.setSubjectPublicKeyAlgID(selector.getSubjectPublicKeyAlgID());
+            cs.setSubjectAlternativeNames(selector.getSubjectAlternativeNames());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("error in passed in selector: " + e);
+        }
+        cs.setIssuer(selector.getIssuer());
+        cs.setKeyUsage(selector.getKeyUsage());
+        cs.setPrivateKeyValid(selector.getPrivateKeyValid());
+        cs.setSerialNumber(selector.getSerialNumber());
+        cs.setSubject(selector.getSubject());
+        cs.setSubjectKeyIdentifier(selector.getSubjectKeyIdentifier());
+        cs.setSubjectPublicKey(selector.getSubjectPublicKey());
+        return cs;
+    }
+
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509CollectionStoreParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509CollectionStoreParameters.java
new file mode 100644
index 0000000..9787368
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509CollectionStoreParameters.java
@@ -0,0 +1,72 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * This class contains a collection for collection based <code>X509Store</code>s.
+ * 
+ * @see com.android.internal.org.bouncycastle.x509.X509Store
+ * @hide This class is not part of the Android public SDK API
+ * 
+ */
+public class X509CollectionStoreParameters
+    implements X509StoreParameters
+{
+    private Collection collection;
+
+    /**
+     * Constructor.
+     * <p>
+     * The collection is copied.
+     * </p>
+     * 
+     * @param collection
+     *            The collection containing X.509 object types.
+     * @throws NullPointerException if <code>collection</code> is <code>null</code>.
+     */
+    public X509CollectionStoreParameters(Collection collection)
+    {
+        if (collection == null)
+        {
+            throw new NullPointerException("collection cannot be null");
+        }
+        this.collection = collection;
+    }
+
+    /**
+     * Returns a shallow clone. The returned contents are not copied, so adding
+     * or removing objects will effect this.
+     * 
+     * @return a shallow clone.
+     */
+    public Object clone()
+    {
+        return new X509CollectionStoreParameters(collection);
+    }
+    
+    /**
+     * Returns a copy of the <code>Collection</code>.
+     * 
+     * @return The <code>Collection</code>. Is never <code>null</code>.
+     */
+    public Collection getCollection()
+    {
+        return new ArrayList(collection);
+    }
+    
+    /**
+     * Returns a formatted string describing the parameters.
+     * 
+     * @return a formatted string describing the parameters
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append("X509CollectionStoreParameters: [\n");
+        sb.append("  collection: " + collection + "\n");
+        sb.append("]");
+        return sb.toString();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509StoreParameters.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509StoreParameters.java
new file mode 100644
index 0000000..4f80000
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509StoreParameters.java
@@ -0,0 +1,9 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public interface X509StoreParameters
+{
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509StoreSpi.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509StoreSpi.java
new file mode 100644
index 0000000..22ee2e6
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509StoreSpi.java
@@ -0,0 +1,16 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import com.android.internal.org.bouncycastle.util.Selector;
+
+import java.util.Collection;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public abstract class X509StoreSpi
+{
+    public abstract void engineInit(X509StoreParameters parameters);
+
+    public abstract Collection engineGetMatches(Selector selector);
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509Util.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509Util.java
new file mode 100644
index 0000000..93da538
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509Util.java
@@ -0,0 +1,423 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DERNull;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+// Android-removed: Unsupported algorithms
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import com.android.internal.org.bouncycastle.jce.X509Principal;
+import com.android.internal.org.bouncycastle.util.Strings;
+
+class X509Util
+{
+    private static Hashtable algorithms = new Hashtable();
+    private static Hashtable params = new Hashtable();
+    private static Set       noParams = new HashSet();
+    
+    static
+    {   
+        // BEGIN Android-removed: Unsupported algorithms
+        // algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
+        // algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
+        // END Android-removed: Unsupported algorithms
+        algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
+        algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
+        algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+        algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+        algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+        algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+        algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+        algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+        algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+        algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        // BEGIN Android-removed: Unsupported algorithms
+        // algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+        // algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+        // algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+        // algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+        // algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+        // algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+        // END Android-removed: Unsupported algorithms
+        algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+        algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+        algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+        algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+        algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+        algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+        algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+        algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+        algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+        algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+        algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+        algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+        // BEGIN Android-removed: Unsupported algorithms
+        // algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        // algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        // algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // END Android-removed: Unsupported algorithms
+
+        //
+        // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. 
+        // The parameters field SHALL be NULL for RSA based signature algorithms.
+        //
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+        noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
+        
+        //
+        // RFC 4491
+        //
+        // BEGIN Android-removed: Unsupported algorithms
+        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // END Android-removed: Unsupported algorithms
+
+        //
+        // explicit params
+        //
+        AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+        params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
+
+        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+        params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+
+        AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
+        params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
+
+        AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE);
+        params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
+
+        AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE);
+        params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
+    }
+
+    private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+    {
+        return new RSASSAPSSparams(
+            hashAlgId,
+            new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+            new ASN1Integer(saltSize),
+            new ASN1Integer(1));
+    }
+
+    static ASN1ObjectIdentifier getAlgorithmOID(
+        String algorithmName)
+    {
+        algorithmName = Strings.toUpperCase(algorithmName);
+        
+        if (algorithms.containsKey(algorithmName))
+        {
+            return (ASN1ObjectIdentifier)algorithms.get(algorithmName);
+        }
+        
+        return new ASN1ObjectIdentifier(algorithmName);
+    }
+    
+    static AlgorithmIdentifier getSigAlgID(
+        ASN1ObjectIdentifier sigOid,
+        String              algorithmName)
+    {
+        if (noParams.contains(sigOid))
+        {
+            return new AlgorithmIdentifier(sigOid);
+        }
+
+        algorithmName = Strings.toUpperCase(algorithmName);
+
+        if (params.containsKey(algorithmName))
+        {
+            return new AlgorithmIdentifier(sigOid, (ASN1Encodable)params.get(algorithmName));
+        }
+        else
+        {
+            return new AlgorithmIdentifier(sigOid, DERNull.INSTANCE);
+        }
+    }
+    
+    static Iterator getAlgNames()
+    {
+        Enumeration e = algorithms.keys();
+        List        l = new ArrayList();
+        
+        while (e.hasMoreElements())
+        {
+            l.add(e.nextElement());
+        }
+        
+        return l.iterator();
+    }
+
+    static Signature getSignatureInstance(
+        String algorithm)
+        throws NoSuchAlgorithmException
+    {
+        return Signature.getInstance(algorithm);
+    }
+
+    static Signature getSignatureInstance(
+        String algorithm,
+        String provider)
+        throws NoSuchProviderException, NoSuchAlgorithmException
+    {
+        if (provider != null)
+        {
+            return Signature.getInstance(algorithm, provider);
+        }
+        else
+        {
+            return Signature.getInstance(algorithm);
+        }
+    }
+
+    static byte[] calculateSignature(
+        ASN1ObjectIdentifier sigOid,
+        String              sigName,
+        PrivateKey          key,
+        SecureRandom        random,
+        ASN1Encodable       object)
+        throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+    {
+        Signature sig;
+
+        if (sigOid == null)
+        {
+            throw new IllegalStateException("no signature algorithm specified");
+        }
+
+        sig = X509Util.getSignatureInstance(sigName);
+
+        if (random != null)
+        {
+            sig.initSign(key, random);
+        }
+        else
+        {
+            sig.initSign(key);
+        }
+
+        sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+        return sig.sign();
+    }
+
+    static byte[] calculateSignature(
+        ASN1ObjectIdentifier sigOid,
+        String              sigName,
+        String              provider,
+        PrivateKey          key,
+        SecureRandom        random,
+        ASN1Encodable       object)
+        throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+    {
+        Signature sig;
+
+        if (sigOid == null)
+        {
+            throw new IllegalStateException("no signature algorithm specified");
+        }
+
+        sig = X509Util.getSignatureInstance(sigName, provider);
+
+        if (random != null)
+        {
+            sig.initSign(key, random);
+        }
+        else
+        {
+            sig.initSign(key);
+        }
+
+        sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+        return sig.sign();
+    }
+
+    static X509Principal convertPrincipal(
+        X500Principal principal)
+    {
+        try
+        {
+            return new X509Principal(principal.getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("cannot convert principal");
+        }
+    }
+
+    static class Implementation
+    {
+        Object      engine;
+        Provider provider;
+
+        Implementation(
+            Object      engine,
+            Provider    provider)
+        {
+            this.engine = engine;
+            this.provider = provider;
+        }
+
+        Object getEngine()
+        {
+            return engine;
+        }
+
+        Provider getProvider()
+        {
+            return provider;
+        }
+    }
+
+    /**
+     * see if we can find an algorithm (or its alias and what it represents) in
+     * the property table for the given provider.
+     */
+    static Implementation getImplementation(
+        String      baseName,
+        String      algorithm,
+        Provider    prov)
+        throws NoSuchAlgorithmException
+    {
+        algorithm = Strings.toUpperCase(algorithm);
+
+        String      alias;
+
+        while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null)
+        {
+            algorithm = alias;
+        }
+
+        String      className = prov.getProperty(baseName + "." + algorithm);
+
+        if (className != null)
+        {
+            try
+            {
+                Class       cls;
+                ClassLoader clsLoader = prov.getClass().getClassLoader();
+
+                if (clsLoader != null)
+                {
+                    cls = clsLoader.loadClass(className);
+                }
+                else
+                {
+                    cls = Class.forName(className);
+                }
+
+                return new Implementation(cls.newInstance(), prov);
+            }
+            catch (ClassNotFoundException e)
+            {
+                throw new IllegalStateException(
+                    "algorithm " + algorithm + " in provider " + prov.getName() + " but no class \"" + className + "\" found!");
+            }
+            catch (Exception e)
+            {
+                throw new IllegalStateException(
+                    "algorithm " + algorithm + " in provider " + prov.getName() + " but class \"" + className + "\" inaccessible!");
+            }
+        }
+
+        throw new NoSuchAlgorithmException("cannot find implementation " + algorithm + " for provider " + prov.getName());
+    }
+
+    /**
+     * return an implementation for a given algorithm/provider.
+     * If the provider is null, we grab the first avalaible who has the required algorithm.
+     */
+    static Implementation getImplementation(
+        String      baseName,
+        String      algorithm)
+        throws NoSuchAlgorithmException
+    {
+        Provider[] prov = Security.getProviders();
+
+        //
+        // search every provider looking for the algorithm we want.
+        //
+        for (int i = 0; i != prov.length; i++)
+        {
+            //
+            // try case insensitive
+            //
+            Implementation imp = getImplementation(baseName, Strings.toUpperCase(algorithm), prov[i]);
+            if (imp != null)
+            {
+                return imp;
+            }
+
+            try
+            {
+                imp = getImplementation(baseName, algorithm, prov[i]);
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                // continue
+            }
+        }
+
+        throw new NoSuchAlgorithmException("cannot find implementation " + algorithm);
+    }
+
+    static Provider getProvider(String provider)
+        throws NoSuchProviderException
+    {
+        Provider prov = Security.getProvider(provider);
+
+        if (prov == null)
+        {
+            throw new NoSuchProviderException("Provider " + provider + " not found");
+        }
+
+        return prov;
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509V1CertificateGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509V1CertificateGenerator.java
new file mode 100644
index 0000000..035ab5d
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509V1CertificateGenerator.java
@@ -0,0 +1,381 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.TBSCertificate;
+import com.android.internal.org.bouncycastle.asn1.x509.Time;
+import com.android.internal.org.bouncycastle.asn1.x509.V1TBSCertificateGenerator;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Name;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
+import com.android.internal.org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.jce.X509Principal;
+
+/**
+ * class to produce an X.509 Version 1 certificate.
+ * @deprecated use org.bouncycastle.cert.X509v1CertificateBuilder.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509V1CertificateGenerator
+{
+    private final JcaJceHelper bcHelper = new BCJcaJceHelper(); // needed to force provider loading
+    private final CertificateFactory certificateFactory = new CertificateFactory();
+
+    private V1TBSCertificateGenerator   tbsGen;
+    private ASN1ObjectIdentifier         sigOID;
+    private AlgorithmIdentifier         sigAlgId;
+    private String                      signatureAlgorithm;
+
+    public X509V1CertificateGenerator()
+    {
+        tbsGen = new V1TBSCertificateGenerator();
+    }
+
+    /**
+     * reset the generator
+     */
+    public void reset()
+    {
+        tbsGen = new V1TBSCertificateGenerator();
+    }
+
+    /**
+     * set the serial number for the certificate.
+     */
+    public void setSerialNumber(
+        BigInteger      serialNumber)
+    {
+        if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+        {
+            throw new IllegalArgumentException("serial number must be a positive integer");
+        }
+        
+        tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+    }
+
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X500Principal   issuer)
+    {
+        try
+        {
+            tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't process principal: " + e);
+        }
+    }
+    
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X509Name   issuer)
+    {
+        tbsGen.setIssuer(issuer);
+    }
+
+    public void setNotBefore(
+        Date    date)
+    {
+        tbsGen.setStartDate(new Time(date));
+    }
+
+    public void setNotAfter(
+        Date    date)
+    {
+        tbsGen.setEndDate(new Time(date));
+    }
+
+    /**
+     * Set the subject distinguished name. The subject describes the entity associated with the public key.
+     */
+    public void setSubjectDN(
+        X500Principal   subject)
+    {
+        try
+        {
+            tbsGen.setSubject(new X509Principal(subject.getEncoded()));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't process principal: " + e);
+        }
+    }
+    
+    /**
+     * Set the subject distinguished name. The subject describes the entity associated with the public key.
+     */
+    public void setSubjectDN(
+        X509Name   subject)
+    {
+        tbsGen.setSubject(subject);
+    }
+
+    public void setPublicKey(
+        PublicKey       key)
+    {
+        try
+        {
+            tbsGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(key.getEncoded()));
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("unable to process key - " + e.toString());
+        }
+    }
+
+    /**
+     * Set the signature algorithm. This can be either a name or an OID, names
+     * are treated as case insensitive.
+     * 
+     * @param signatureAlgorithm string representation of the algorithm name.
+     */
+    public void setSignatureAlgorithm(
+        String  signatureAlgorithm)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+
+        try
+        {
+            sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("Unknown signature type requested");
+        }
+
+        sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+        tbsGen.setSignature(sigAlgId);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC".
+     * @deprecated use generate(key, "BC")
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", null);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC" and the passed in source of randomness
+     * @deprecated use generate(key, random, "BC")
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        SecureRandom    random)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", random);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing, and the passed in source
+     * of randomness (if required).
+     * @deprecated use generate()
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        return generateX509Certificate(key, provider, null);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing, and the passed in source
+     * of randomness (if required).
+     * @deprecated use generate()
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider,
+        SecureRandom    random)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generate(key, provider, random);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw e;
+        }
+        catch (SignatureException e)
+        {
+            throw e;
+        }
+        catch (InvalidKeyException e)
+        {
+            throw e;
+        }
+        catch (GeneralSecurityException e)
+        {
+            throw new SecurityException("exception: " + e);
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider.
+     * <p>
+     * <b>Note:</b> this differs from the deprecated method in that the default provider is
+     * used - not "BC".
+     * </p>
+     */
+    public X509Certificate generate(
+        PrivateKey      key)
+        throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        return generate(key, (SecureRandom)null);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider and the passed in source of randomness
+     * <p>
+     * <b>Note:</b> this differs from the deprecated method in that the default provider is
+     * used - not "BC".
+     * </p>
+     */
+    public X509Certificate generate(
+        PrivateKey      key,
+        SecureRandom    random)
+        throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+        byte[] signature;
+
+        try
+        {
+            signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+        }
+        catch (IOException e)
+        {
+            throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+        }
+
+        return generateJcaObject(tbsCert, signature);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing, and the passed in source
+     * of randomness (if required).
+     */
+    public X509Certificate generate(
+        PrivateKey      key,
+        String          provider)
+        throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        return generate(key, provider, null);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing, and the passed in source
+     * of randomness (if required).
+     */
+    public X509Certificate generate(
+        PrivateKey      key,
+        String          provider,
+        SecureRandom    random)
+        throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+        byte[] signature;
+
+        try
+        {
+            signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+        }
+        catch (IOException e)
+        {
+            throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+        }
+
+        return generateJcaObject(tbsCert, signature);
+    }
+
+    private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+        throws CertificateEncodingException
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(tbsCert);
+        v.add(sigAlgId);
+        v.add(new DERBitString(signature));
+
+        try
+        {
+            return (X509Certificate)certificateFactory.engineGenerateCertificate(
+                new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER)));
+        }
+        catch (Exception e)
+        {
+            throw new ExtCertificateEncodingException("exception producing certificate object", e);
+        }
+    }
+
+    /**
+     * Return an iterator of the signature names supported by the generator.
+     * 
+     * @return an iterator containing recognised names.
+     */
+    public Iterator getSignatureAlgNames()
+    {
+        return X509Util.getAlgNames();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509V2AttributeCertificate.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509V2AttributeCertificate.java
new file mode 100644
index 0000000..a9cbdf3
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509V2AttributeCertificate.java
@@ -0,0 +1,352 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.x509.AttributeCertificate;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.Extensions;
+import com.android.internal.org.bouncycastle.util.Arrays;
+
+/**
+ * An implementation of a version 2 X.509 Attribute Certificate.
+ * @deprecated use org.bouncycastle.cert.X509AttributeCertificateHolder
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509V2AttributeCertificate
+    implements X509AttributeCertificate
+{
+    private AttributeCertificate    cert;
+    private Date                    notBefore;
+    private Date                    notAfter;
+
+    private static AttributeCertificate getObject(InputStream in)
+        throws IOException
+    {
+        try
+        {
+            return AttributeCertificate.getInstance(new ASN1InputStream(in).readObject());
+        }
+        catch (IOException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            throw new IOException("exception decoding certificate structure: " + e.toString());
+        }
+    }
+
+    public X509V2AttributeCertificate(
+        InputStream encIn)
+        throws IOException
+    {
+        this(getObject(encIn));
+    }
+    
+    public X509V2AttributeCertificate(
+        byte[]  encoded)
+        throws IOException
+    {
+        this(new ByteArrayInputStream(encoded));
+    }
+    
+    X509V2AttributeCertificate(
+        AttributeCertificate    cert)
+        throws IOException
+    {
+        this.cert = cert;
+        
+        try
+        {
+            this.notAfter = cert.getAcinfo().getAttrCertValidityPeriod().getNotAfterTime().getDate();
+            this.notBefore = cert.getAcinfo().getAttrCertValidityPeriod().getNotBeforeTime().getDate();
+        }
+        catch (ParseException e)
+        {
+            throw new IOException("invalid data structure in certificate!");
+        }
+    }
+    
+    public int getVersion()
+    {
+        return cert.getAcinfo().getVersion().getValue().intValue() + 1;
+    }
+    
+    public BigInteger getSerialNumber()
+    {
+        return cert.getAcinfo().getSerialNumber().getValue();
+    }
+    
+    public AttributeCertificateHolder getHolder()
+    {
+        return new AttributeCertificateHolder((ASN1Sequence)cert.getAcinfo().getHolder().toASN1Primitive());
+    }
+    
+    public AttributeCertificateIssuer getIssuer()
+    {
+        return new AttributeCertificateIssuer(cert.getAcinfo().getIssuer());
+    }
+    
+    public Date getNotBefore()
+    {
+        return notBefore;
+    }
+    
+    public Date getNotAfter()
+    {
+        return notAfter;
+    }
+    
+    public boolean[] getIssuerUniqueID()
+    {
+        DERBitString    id = cert.getAcinfo().getIssuerUniqueID();
+
+        if (id != null)
+        {
+            byte[]          bytes = id.getBytes();
+            boolean[]       boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+            for (int i = 0; i != boolId.length; i++)
+            {
+                boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+            }
+
+            return boolId;
+        }
+            
+        return null;
+    }
+    
+    public void checkValidity() 
+        throws CertificateExpiredException, CertificateNotYetValidException
+    {
+        this.checkValidity(new Date());
+    }
+    
+    public void checkValidity(
+        Date    date)
+        throws CertificateExpiredException, CertificateNotYetValidException
+    {
+        if (date.after(this.getNotAfter()))
+        {
+            throw new CertificateExpiredException("certificate expired on " + this.getNotAfter());
+        }
+
+        if (date.before(this.getNotBefore()))
+        {
+            throw new CertificateNotYetValidException("certificate not valid till " + this.getNotBefore());
+        }
+    }
+    
+    public byte[] getSignature()
+    {
+        return cert.getSignatureValue().getOctets();
+    }
+    
+    public final void verify(
+            PublicKey   key,
+            String      provider)
+            throws CertificateException, NoSuchAlgorithmException,
+            InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        Signature   signature = null;
+
+        if (!cert.getSignatureAlgorithm().equals(cert.getAcinfo().getSignature()))
+        {
+            throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
+        }
+
+        signature = Signature.getInstance(cert.getSignatureAlgorithm().getAlgorithm().getId(), provider);
+
+        signature.initVerify(key);
+
+        try
+        {
+            signature.update(cert.getAcinfo().getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new SignatureException("Exception encoding certificate info object");
+        }
+
+        if (!signature.verify(this.getSignature()))
+        {
+            throw new InvalidKeyException("Public key presented not for certificate signature");
+        }
+    }
+    
+    public byte[] getEncoded()
+        throws IOException
+    {
+        return cert.getEncoded();
+    }
+
+    public byte[] getExtensionValue(String oid) 
+    {
+        Extensions extensions = cert.getAcinfo().getExtensions();
+
+        if (extensions != null)
+        {
+            Extension ext = extensions.getExtension(new ASN1ObjectIdentifier(oid));
+
+            if (ext != null)
+            {
+                try
+                {
+                    return ext.getExtnValue().getEncoded(ASN1Encoding.DER);
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException("error encoding " + e.toString());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private Set getExtensionOIDs(
+        boolean critical) 
+    {
+        Extensions  extensions = cert.getAcinfo().getExtensions();
+
+        if (extensions != null)
+        {
+            Set             set = new HashSet();
+            Enumeration     e = extensions.oids();
+
+            while (e.hasMoreElements())
+            {
+                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+                Extension            ext = extensions.getExtension(oid);
+
+                if (ext.isCritical() == critical)
+                {
+                    set.add(oid.getId());
+                }
+            }
+
+            return set;
+        }
+
+        return null;
+    }
+    
+    public Set getNonCriticalExtensionOIDs() 
+    {
+        return getExtensionOIDs(false);
+    }
+
+    public Set getCriticalExtensionOIDs() 
+    {
+        return getExtensionOIDs(true);
+    }
+    
+    public boolean hasUnsupportedCriticalExtension()
+    {
+        Set  extensions = getCriticalExtensionOIDs();
+
+        return extensions != null && !extensions.isEmpty();
+    }
+
+    public X509Attribute[] getAttributes()
+    {
+        ASN1Sequence    seq = cert.getAcinfo().getAttributes();
+        X509Attribute[] attrs = new X509Attribute[seq.size()];
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            attrs[i] = new X509Attribute((ASN1Encodable)seq.getObjectAt(i));
+        }
+        
+        return attrs;
+    }
+    
+    public X509Attribute[] getAttributes(String oid)
+    {
+        ASN1Sequence    seq = cert.getAcinfo().getAttributes();
+        List            list = new ArrayList();
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            X509Attribute attr = new X509Attribute((ASN1Encodable)seq.getObjectAt(i));
+            if (attr.getOID().equals(oid))
+            {
+                list.add(attr);
+            }
+        }
+        
+        if (list.size() == 0)
+        {
+            return null;
+        }
+        
+        return (X509Attribute[])list.toArray(new X509Attribute[list.size()]);
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (!(o instanceof X509AttributeCertificate))
+        {
+            return false;
+        }
+
+        X509AttributeCertificate other = (X509AttributeCertificate)o;
+
+        try
+        {
+            byte[] b1 = this.getEncoded();
+            byte[] b2 = other.getEncoded();
+
+            return Arrays.areEqual(b1, b2);
+        }
+        catch (IOException e)
+        {
+            return false;
+        }
+    }
+
+    public int hashCode()
+    {
+        try
+        {
+            return Arrays.hashCode(this.getEncoded());
+        }
+        catch (IOException e)
+        {
+            return 0;
+        }
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509V3CertificateGenerator.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509V3CertificateGenerator.java
new file mode 100644
index 0000000..655ed66
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/X509V3CertificateGenerator.java
@@ -0,0 +1,535 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
+import com.android.internal.org.bouncycastle.asn1.ASN1Encoding;
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.DERBitString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.TBSCertificate;
+import com.android.internal.org.bouncycastle.asn1.x509.Time;
+import com.android.internal.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
+import com.android.internal.org.bouncycastle.asn1.x509.X509ExtensionsGenerator;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Name;
+import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
+import com.android.internal.org.bouncycastle.jcajce.util.BCJcaJceHelper;
+import com.android.internal.org.bouncycastle.jcajce.util.JcaJceHelper;
+import com.android.internal.org.bouncycastle.jce.X509Principal;
+import com.android.internal.org.bouncycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * class to produce an X.509 Version 3 certificate.
+ *  @deprecated use org.bouncycastle.cert.X509v3CertificateBuilder.
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509V3CertificateGenerator
+{
+    private final JcaJceHelper bcHelper = new BCJcaJceHelper(); // needed to force provider loading
+    private final CertificateFactory certificateFactory = new CertificateFactory();
+
+    private V3TBSCertificateGenerator   tbsGen;
+    private ASN1ObjectIdentifier        sigOID;
+    private AlgorithmIdentifier         sigAlgId;
+    private String                      signatureAlgorithm;
+    private X509ExtensionsGenerator     extGenerator;
+
+    public X509V3CertificateGenerator()
+    {
+        tbsGen = new V3TBSCertificateGenerator();
+        extGenerator = new X509ExtensionsGenerator();
+    }
+
+    /**
+     * reset the generator
+     */
+    public void reset()
+    {
+        tbsGen = new V3TBSCertificateGenerator();
+        extGenerator.reset();
+    }
+
+    /**
+     * set the serial number for the certificate.
+     */
+    public void setSerialNumber(
+        BigInteger      serialNumber)
+    {
+        if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+        {
+            throw new IllegalArgumentException("serial number must be a positive integer");
+        }
+        
+        tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+    }
+
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X500Principal   issuer)
+    {
+        try
+        {
+            tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't process principal: " + e);
+        }
+    }
+    
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X509Name   issuer)
+    {
+        tbsGen.setIssuer(issuer);
+    }
+
+    public void setNotBefore(
+        Date    date)
+    {
+        tbsGen.setStartDate(new Time(date));
+    }
+
+    public void setNotAfter(
+        Date    date)
+    {
+        tbsGen.setEndDate(new Time(date));
+    }
+
+    /**
+     * Set the subject distinguished name. The subject describes the entity associated with the public key.
+     */
+    public void setSubjectDN(
+        X500Principal   subject)
+    {
+        try
+        {
+            tbsGen.setSubject(new X509Principal(subject.getEncoded()));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't process principal: " + e);
+        }
+    }
+    
+    /**
+     * Set the subject distinguished name. The subject describes the entity associated with the public key.
+     */
+    public void setSubjectDN(
+        X509Name   subject)
+    {
+        tbsGen.setSubject(subject);
+    }
+
+    public void setPublicKey(
+        PublicKey       key)
+        throws IllegalArgumentException
+    {
+        try
+        {
+            tbsGen.setSubjectPublicKeyInfo(
+                       SubjectPublicKeyInfo.getInstance(new ASN1InputStream(key.getEncoded()).readObject()));
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("unable to process key - " + e.toString());
+        }
+    }
+
+    /**
+     * Set the signature algorithm. This can be either a name or an OID, names
+     * are treated as case insensitive.
+     * 
+     * @param signatureAlgorithm string representation of the algorithm name.
+     */
+    public void setSignatureAlgorithm(
+        String  signatureAlgorithm)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+
+        try
+        {
+            sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+        }
+
+        sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+        tbsGen.setSignature(sigAlgId);
+    }
+
+    /**
+     * Set the subject unique ID - note: it is very rare that it is correct to do this.
+     */
+    public void setSubjectUniqueID(boolean[] uniqueID)
+    {
+        tbsGen.setSubjectUniqueID(booleanToBitString(uniqueID));
+    }
+
+    /**
+     * Set the issuer unique ID - note: it is very rare that it is correct to do this.
+     */
+    public void setIssuerUniqueID(boolean[] uniqueID)
+    {
+        tbsGen.setIssuerUniqueID(booleanToBitString(uniqueID));
+    }
+
+    private DERBitString booleanToBitString(boolean[] id)
+    {
+        byte[] bytes = new byte[(id.length + 7) / 8];
+
+        for (int i = 0; i != id.length; i++)
+        {
+            bytes[i / 8] |= (id[i]) ? (1 << ((7 - (i % 8)))) : 0;
+        }
+
+        int pad = id.length % 8;
+
+        if (pad == 0)
+        {
+            return new DERBitString(bytes);
+        }
+        else
+        {
+            return new DERBitString(bytes, 8 - pad);
+        }
+    }
+    
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     */
+    public void addExtension(
+        String          oid,
+        boolean         critical,
+        ASN1Encodable    value)
+    {
+        this.addExtension(new ASN1ObjectIdentifier(oid), critical, value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     */
+    public void addExtension(
+        ASN1ObjectIdentifier oid,
+        boolean             critical,
+        ASN1Encodable        value)
+    {
+        extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical,  value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     * The value parameter becomes the contents of the octet string associated
+     * with the extension.
+     */
+    public void addExtension(
+        String          oid,
+        boolean         critical,
+        byte[]          value)
+    {
+        this.addExtension(new ASN1ObjectIdentifier(oid), critical, value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     */
+    public void addExtension(
+        ASN1ObjectIdentifier oid,
+        boolean             critical,
+        byte[]              value)
+    {
+        extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     * copying the extension value from another certificate.
+     * @throws CertificateParsingException if the extension cannot be extracted.
+     */
+    public void copyAndAddExtension(
+        String          oid,
+        boolean         critical,
+        X509Certificate cert) 
+        throws CertificateParsingException
+    {
+        byte[] extValue = cert.getExtensionValue(oid);
+        
+        if (extValue == null)
+        {
+            throw new CertificateParsingException("extension " + oid + " not present");
+        }
+        
+        try
+        {
+            ASN1Encodable value = X509ExtensionUtil.fromExtensionValue(extValue);
+    
+            this.addExtension(oid, critical, value);
+        }
+        catch (IOException e)
+        {
+            throw new CertificateParsingException(e.toString());
+        }
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     * copying the extension value from another certificate.
+     * @throws CertificateParsingException if the extension cannot be extracted.
+     */
+    public void copyAndAddExtension(
+        ASN1ObjectIdentifier oid,
+        boolean             critical,
+        X509Certificate     cert)
+        throws CertificateParsingException
+    {
+        this.copyAndAddExtension(oid.getId(), critical, cert);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC".
+     * @deprecated use generate(key, "BC")
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", null);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC", and the passed in source of randomness
+     * (if required).
+     * @deprecated use generate(key, random, "BC")
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        SecureRandom    random)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", random);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing.
+     * @deprecated use generate()
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        return generateX509Certificate(key, provider, null);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing and the supplied source
+     * of randomness, if required.
+     * @deprecated use generate()
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider,
+        SecureRandom    random)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generate(key, provider, random);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw e;
+        }
+        catch (SignatureException e)
+        {
+            throw e;
+        }
+        catch (InvalidKeyException e)
+        {
+            throw e;
+        }
+        catch (GeneralSecurityException e)
+        {
+            throw new SecurityException("exception: " + e);
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider.
+     * <p>
+     * <b>Note:</b> this differs from the deprecated method in that the default provider is
+     * used - not "BC".
+     * </p>
+     */
+    public X509Certificate generate(
+        PrivateKey      key)
+        throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        return generate(key, (SecureRandom)null);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider, and the passed in source of randomness
+     * (if required).
+     * <p>
+     * <b>Note:</b> this differs from the deprecated method in that the default provider is
+     * used - not "BC".
+     * </p>
+     */
+    public X509Certificate generate(
+        PrivateKey      key,
+        SecureRandom    random)
+        throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        TBSCertificate tbsCert = generateTbsCert();
+        byte[] signature;
+
+        try
+        {
+            signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+        }
+        catch (IOException e)
+        {
+            throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+        }
+
+        try
+        {
+            return generateJcaObject(tbsCert, signature);
+        }
+        catch (Exception e)
+        {
+            throw new ExtCertificateEncodingException("exception producing certificate object", e);
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing.
+     */
+    public X509Certificate generate(
+        PrivateKey      key,
+        String          provider)
+        throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        return generate(key, provider, null);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing and the supplied source
+     * of randomness, if required.
+     */
+    public X509Certificate generate(
+        PrivateKey      key,
+        String          provider,
+        SecureRandom    random)
+        throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        TBSCertificate tbsCert = generateTbsCert();
+        byte[] signature;
+
+        try
+        {
+            signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+        }
+        catch (IOException e)
+        {
+            throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+        }
+
+        try
+        {
+            return generateJcaObject(tbsCert, signature);
+        }
+        catch (Exception e)
+        {
+            throw new ExtCertificateEncodingException("exception producing certificate object", e);
+        }
+    }
+
+    private TBSCertificate generateTbsCert()
+    {
+        if (!extGenerator.isEmpty())
+        {
+            tbsGen.setExtensions(extGenerator.generate());
+        }
+
+        return tbsGen.generateTBSCertificate();
+    }
+
+    private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+        throws Exception
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(tbsCert);
+        v.add(sigAlgId);
+        v.add(new DERBitString(signature));
+
+        return (X509Certificate)certificateFactory.engineGenerateCertificate(
+            new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER)));
+    }
+
+    /**
+     * Return an iterator of the signature names supported by the generator.
+     * 
+     * @return an iterator containing recognised names.
+     */
+    public Iterator getSignatureAlgNames()
+    {
+        return X509Util.getAlgNames();
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java
new file mode 100644
index 0000000..cc07aaa
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java
@@ -0,0 +1,149 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509.extension;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.PublicKey;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralNames;
+import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.internal.org.bouncycastle.asn1.x509.X509Extension;
+import com.android.internal.org.bouncycastle.jce.PrincipalUtil;
+
+/**
+ * A high level authority key identifier.
+ * @deprecated use JcaX509ExtensionUtils and AuthorityKeyIdentifier.getInstance()
+ * @hide This class is not part of the Android public SDK API
+ */
+public class AuthorityKeyIdentifierStructure
+    extends AuthorityKeyIdentifier
+{
+    /**
+     * Constructor which will take the byte[] returned from getExtensionValue()
+     * 
+     * @param encodedValue a DER octet encoded string with the extension structure in it.
+     * @throws IOException on parsing errors.
+     */
+    public AuthorityKeyIdentifierStructure(
+        byte[]  encodedValue)
+        throws IOException
+    {
+        super((ASN1Sequence)X509ExtensionUtil.fromExtensionValue(encodedValue));
+    }
+
+    /**
+     * Constructor which will take an extension
+     *
+     * @param extension a X509Extension object containing an AuthorityKeyIdentifier.
+     * @deprecated use constructor that takes Extension
+     */
+    public AuthorityKeyIdentifierStructure(
+        X509Extension extension)
+    {
+        super((ASN1Sequence)extension.getParsedValue());
+    }
+
+    /**
+     * Constructor which will take an extension
+     *
+     * @param extension a X509Extension object containing an AuthorityKeyIdentifier.
+     */
+    public AuthorityKeyIdentifierStructure(
+        Extension extension)
+    {
+        super((ASN1Sequence)extension.getParsedValue());
+    }
+
+    private static ASN1Sequence fromCertificate(
+        X509Certificate certificate)
+        throws CertificateParsingException
+    {
+        try
+        {
+            if (certificate.getVersion() != 3)
+            {
+                GeneralName          genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate));
+                SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(certificate.getPublicKey().getEncoded());
+                
+                return (ASN1Sequence)new AuthorityKeyIdentifier(
+                               info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Primitive();
+            }
+            else
+            {
+                GeneralName             genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate));
+                
+                byte[]                  ext = certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId());
+                
+                if (ext != null)
+                {
+                    ASN1OctetString     str = (ASN1OctetString)X509ExtensionUtil.fromExtensionValue(ext);
+                
+                    return (ASN1Sequence)new AuthorityKeyIdentifier(
+                                    str.getOctets(), new GeneralNames(genName), certificate.getSerialNumber()).toASN1Primitive();
+                }
+                else
+                {
+                    SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(certificate.getPublicKey().getEncoded());
+                    
+                    return (ASN1Sequence)new AuthorityKeyIdentifier(
+                            info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Primitive();
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException("Exception extracting certificate details: " + e.toString());
+        }
+    }
+    
+    private static ASN1Sequence fromKey(
+        PublicKey pubKey)
+        throws InvalidKeyException
+    {
+        try
+        {
+            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+        
+            return (ASN1Sequence)new AuthorityKeyIdentifier(info).toASN1Primitive();
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeyException("can't process key: " + e);
+        }
+    }
+    
+    /**
+     * Create an AuthorityKeyIdentifier using the passed in certificate's public
+     * key, issuer and serial number.
+     * 
+     * @param certificate the certificate providing the information.
+     * @throws CertificateParsingException if there is a problem processing the certificate
+     */
+    public AuthorityKeyIdentifierStructure(
+        X509Certificate certificate)
+        throws CertificateParsingException
+    {
+        super(fromCertificate(certificate));
+    }
+    
+    /**
+     * Create an AuthorityKeyIdentifier using just the hash of the 
+     * public key.
+     * 
+     * @param pubKey the key to generate the hash from.
+     * @throws InvalidKeyException if there is a problem using the key.
+     */
+    public AuthorityKeyIdentifierStructure(
+        PublicKey pubKey) 
+        throws InvalidKeyException
+    {
+        super(fromKey(pubKey));
+    }
+}
diff --git a/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/extension/X509ExtensionUtil.java b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/extension/X509ExtensionUtil.java
new file mode 100644
index 0000000..4e6c808
--- /dev/null
+++ b/repackaged_platform/bcprov/src/main/java/com/android/internal/org/bouncycastle/x509/extension/X509ExtensionUtil.java
@@ -0,0 +1,115 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.internal.org.bouncycastle.x509.extension;
+
+import java.io.IOException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Primitive;
+import com.android.internal.org.bouncycastle.asn1.ASN1String;
+import com.android.internal.org.bouncycastle.asn1.DEROctetString;
+import com.android.internal.org.bouncycastle.asn1.DERSequence;
+import com.android.internal.org.bouncycastle.asn1.x500.X500Name;
+import com.android.internal.org.bouncycastle.asn1.x509.Extension;
+import com.android.internal.org.bouncycastle.asn1.x509.GeneralName;
+import com.android.internal.org.bouncycastle.util.Integers;
+
+
+/**
+ * @deprecated use org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils
+ * @hide This class is not part of the Android public SDK API
+ */
+public class X509ExtensionUtil
+{
+    /**
+     * @deprecated use org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils.parseExtensionValue()
+     */
+    public static ASN1Primitive fromExtensionValue(
+        byte[]  encodedValue) 
+        throws IOException
+    {
+        ASN1OctetString octs = (ASN1OctetString)ASN1Primitive.fromByteArray(encodedValue);
+        
+        return ASN1Primitive.fromByteArray(octs.getOctets());
+    }
+
+    /**
+     * @deprecated use org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils.getIssuerAlternativeNames()
+     */
+    public static Collection getIssuerAlternativeNames(X509Certificate cert)
+            throws CertificateParsingException
+    {
+        byte[] extVal = cert.getExtensionValue(Extension.issuerAlternativeName.getId());
+
+        return getAlternativeNames(extVal);
+    }
+
+    /**
+     * @deprecated use org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils.getSubjectAlternativeNames()
+     */
+    public static Collection getSubjectAlternativeNames(X509Certificate cert)
+            throws CertificateParsingException
+    {        
+        byte[] extVal = cert.getExtensionValue(Extension.subjectAlternativeName.getId());
+
+        return getAlternativeNames(extVal);
+    }
+
+    private static Collection getAlternativeNames(byte[] extVal)
+        throws CertificateParsingException
+    {
+        if (extVal == null)
+        {
+            return Collections.EMPTY_LIST;
+        }
+        try
+        {
+            Collection temp = new ArrayList();
+            Enumeration it = DERSequence.getInstance(fromExtensionValue(extVal)).getObjects();
+            while (it.hasMoreElements())
+            {
+                GeneralName genName = GeneralName.getInstance(it.nextElement());
+                List list = new ArrayList();
+                list.add(Integers.valueOf(genName.getTagNo()));
+                switch (genName.getTagNo())
+                {
+                case GeneralName.ediPartyName:
+                case GeneralName.x400Address:
+                case GeneralName.otherName:
+                    list.add(genName.getName().toASN1Primitive());
+                    break;
+                case GeneralName.directoryName:
+                    list.add(X500Name.getInstance(genName.getName()).toString());
+                    break;
+                case GeneralName.dNSName:
+                case GeneralName.rfc822Name:
+                case GeneralName.uniformResourceIdentifier:
+                    list.add(((ASN1String)genName.getName()).getString());
+                    break;
+                case GeneralName.registeredID:
+                    list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+                    break;
+                case GeneralName.iPAddress:
+                    list.add(DEROctetString.getInstance(genName.getName()).getOctets());
+                    break;
+                default:
+                    throw new IOException("Bad tag number: " + genName.getTagNo());
+                }
+
+                temp.add(list);
+            }
+            return Collections.unmodifiableCollection(temp);
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException(e.getMessage());
+        }
+    }
+}
diff --git a/srcgen_platform/generate_android_src.sh b/srcgen_platform/generate_android_src.sh
new file mode 100755
index 0000000..6e5b444
--- /dev/null
+++ b/srcgen_platform/generate_android_src.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [[ -z "${ANDROID_BUILD_TOP}" ]]; then
+    echo "Missing environment variables. Did you run build/envsetup.sh and lunch?" >&2
+    exit 1
+fi
+
+PROJECT_DIR=external/bouncycastle
+
+PACKAGE_TRANSFORMATIONS="\
+    org.bouncycastle:com.android.internal.org.bouncycastle \
+"
+
+MODULE_DIRS="\
+    bcprov \
+"
+DEFAULT_CONSTRUCTORS_FILE=${BOUNCY_CASTLE_DIR}/srcgen/default-constructors.txt
+
+REPACKAGED_DIR="${ANDROID_BUILD_TOP}/${PROJECT_DIR}/repackaged_platform"
+
+SOURCE_DIRS="\
+    src/main/java \
+"
+
+SRCGEN_DIR=${PROJECT_DIR}/srcgen_platform
+
+# Repackage the project's source.
+source ${ANDROID_BUILD_TOP}/tools/currysrc/scripts/repackage-common.sh
+
+# Remove some unused source files:
+rm -fr ${REPACKAGED_DIR}/bcprov/src/main/java/com/android/org/bouncycastle/asn1/ocsp/
+