Reconcile with gingerbread-release gingerbread-mr4-release honeycomb-LTE-release

Change-Id: I320527540fdce2e199519850517b765fee6724e5
diff --git a/NOTICE b/NOTICE
index 9c07f83..d2e4437 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,22 +1,16 @@
-<html>
-<body bgcolor=#ffffff>
+Copyright (c) 2000-2010 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
 
-Copyright (c) 2000-2009 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
-<p>
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
-and associated documentation files (the "Software"), to deal in the Software without restriction, 
-including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:
-<p>
+
 The above copyright notice and this permission notice shall be included in all copies or substantial
 portions of the Software.
-<p>
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-</body>
-</html>
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.android b/README.android
index 4e041ed..fe40d40 100644
--- a/README.android
+++ b/README.android
@@ -12,13 +12,14 @@
 
 1) Retrieve the appropriate version of the Bouncy Castle source from
    www.bouncycastle.org/latest_releases.html (in bcprov-jdk*-*.tar.gz
-   file). Check the checksum (found at bouncycastle.org/checksums.html) with:
+   file). Check the checksum (found at http://bouncycastle.org/checksums.html) with:
 
      md5sum bcprov-jdk*-*.tar.gz
      sha1sum bcprov-jdk*-*.tar.gz
 
 2) Update the variables in bouncycastle.config and bouncycastle.version as appropriate.
    At the very least you will need to update the bouncycastle.version.
+   Similarly update ThirdPartyProject.prop.
 
 3) Run:
 
diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop
index 38a8176..fc91c28 100644
--- a/ThirdPartyProject.prop
+++ b/ThirdPartyProject.prop
@@ -1,7 +1,7 @@
 # Copyright 2010 Google Inc. All Rights Reserved.
 #Fri Jul 16 10:03:08 PDT 2010
-currentVersion=bcprov-jdk16-145
-version=bcprov-jdk16-145
+currentVersion=bcprov-jdk16-146
+version=bcprov-jdk16-146
 isNative=false
 feedurl=http\://www.bouncycastle.org/releasenotes.html
 name=bouncy_castle
diff --git a/bouncycastle.config b/bouncycastle.config
index d615ad2..bcc47ee 100644
--- a/bouncycastle.config
+++ b/bouncycastle.config
@@ -16,10 +16,10 @@
 org/bouncycastle/asn1/smime \
 org/bouncycastle/asn1/test \
 org/bouncycastle/asn1/tsp \
-org/bouncycastle/asn1/x500 \
 org/bouncycastle/asn1/x509/qualified \
 org/bouncycastle/asn1/x509/sigi \
 org/bouncycastle/bcpg \
+org/bouncycastle/cert \
 org/bouncycastle/cms \
 org/bouncycastle/crypto/agreement/kdf \
 org/bouncycastle/crypto/agreement/srp \
@@ -35,7 +35,8 @@
 org/bouncycastle/ocsp \
 org/bouncycastle/openpgp \
 org/bouncycastle/openssl/test \
-org/bouncycastle/sasn1 \
+org/bouncycastle/operator \
+org/bouncycastle/pkcs \
 org/bouncycastle/tsp \
 org/bouncycastle/util/encoders/test \
 org/bouncycastle/util/test \
@@ -46,6 +47,7 @@
 # files
 UNNEEDED_SOURCES+=" \
 org/bouncycastle/LICENSE.java \
+org/bouncycastle/asn1/ASN1Boolean.java \
 org/bouncycastle/asn1/ASN1Generator.java \
 org/bouncycastle/asn1/BERGenerator.java \
 org/bouncycastle/asn1/BERNull.java \
@@ -55,11 +57,13 @@
 org/bouncycastle/asn1/DERSequenceGenerator.java \
 org/bouncycastle/asn1/cms/Attribute.java \
 org/bouncycastle/asn1/cms/AttributeTable.java \
+org/bouncycastle/asn1/cms/Attributes.java \
 org/bouncycastle/asn1/cms/AuthEnvelopedData.java \
 org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java \
 org/bouncycastle/asn1/cms/AuthenticatedData.java \
 org/bouncycastle/asn1/cms/AuthenticatedDataParser.java \
 org/bouncycastle/asn1/cms/CMSAttributes.java \
+org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java \
 org/bouncycastle/asn1/cms/CompressedData.java \
 org/bouncycastle/asn1/cms/CompressedDataParser.java \
 org/bouncycastle/asn1/cms/ContentInfoParser.java \
@@ -68,12 +72,14 @@
 org/bouncycastle/asn1/cms/EncryptedData.java \
 org/bouncycastle/asn1/cms/EnvelopedData.java \
 org/bouncycastle/asn1/cms/EnvelopedDataParser.java \
+org/bouncycastle/asn1/cms/Evidence.java \
 org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java \
 org/bouncycastle/asn1/cms/KEKIdentifier.java \
 org/bouncycastle/asn1/cms/KEKRecipientInfo.java \
 org/bouncycastle/asn1/cms/KeyAgreeRecipientIdentifier.java \
 org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java \
 org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java \
+org/bouncycastle/asn1/cms/MetaData.java \
 org/bouncycastle/asn1/cms/OriginatorIdentifierOrKey.java \
 org/bouncycastle/asn1/cms/OriginatorInfo.java \
 org/bouncycastle/asn1/cms/OriginatorPublicKey.java \
@@ -89,6 +95,10 @@
 org/bouncycastle/asn1/cms/SignerIdentifier.java \
 org/bouncycastle/asn1/cms/SignerInfo.java \
 org/bouncycastle/asn1/cms/Time.java \
+org/bouncycastle/asn1/cms/TimeStampAndCRL.java \
+org/bouncycastle/asn1/cms/TimeStampTokenEvidence.java \
+org/bouncycastle/asn1/cms/TimeStampedData.java \
+org/bouncycastle/asn1/cms/TimeStampedDataParser.java \
 org/bouncycastle/asn1/cms/package.html \
 org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java \
 org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java \
@@ -222,21 +232,25 @@
 org/bouncycastle/crypto/io/package.html \
 org/bouncycastle/crypto/macs/BlockCipherMac.java \
 org/bouncycastle/crypto/macs/CFBBlockCipherMac.java \
+org/bouncycastle/crypto/macs/CMac.java \
 org/bouncycastle/crypto/macs/GOST28147Mac.java \
 org/bouncycastle/crypto/macs/ISO9797Alg3Mac.java \
 org/bouncycastle/crypto/macs/OldHMac.java \
 org/bouncycastle/crypto/macs/VMPCMac.java \
 org/bouncycastle/crypto/macs/package.html \
+org/bouncycastle/crypto/modes/EAXBlockCipher.java \
 org/bouncycastle/crypto/modes/OpenPGPCFBBlockCipher.java \
 org/bouncycastle/crypto/modes/PGPCFBBlockCipher.java \
 org/bouncycastle/crypto/modes/PaddedBlockCipher.java \
+org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java \
 org/bouncycastle/crypto/modes/gcm/BasicGCMMultiplier.java \
+org/bouncycastle/crypto/modes/gcm/GCMExponentiator.java \
+org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java \
 org/bouncycastle/crypto/modes/gcm/Tables64kGCMMultiplier.java \
 org/bouncycastle/crypto/modes/package.html \
 org/bouncycastle/crypto/package.html \
 org/bouncycastle/crypto/paddings/package.html \
 org/bouncycastle/crypto/params/CCMParameters.java \
-org/bouncycastle/math/ec/test \
 org/bouncycastle/crypto/params/ElGamalKeyGenerationParameters.java \
 org/bouncycastle/crypto/params/ElGamalKeyParameters.java \
 org/bouncycastle/crypto/params/ElGamalParameters.java \
@@ -275,15 +289,11 @@
 org/bouncycastle/crypto/util/package.html \
 org/bouncycastle/jce/ECGOST3410NamedCurveTable.java \
 org/bouncycastle/jce/ECKeyUtil.java \
-org/bouncycastle/jce/ECNamedCurveTable.java \
 org/bouncycastle/jce/ECPointUtil.java \
 org/bouncycastle/jce/MultiCertStoreParameters.java \
-org/bouncycastle/jce/PKCS7SignedData.java \
+org/bouncycastle/jce/PKCS12Util.java \
 org/bouncycastle/jce/X509KeyUsage.java \
 org/bouncycastle/jce/X509LDAPCertStoreParameters.java \
-org/bouncycastle/jce/X509V1CertificateGenerator.java \
-org/bouncycastle/jce/X509V2CRLGenerator.java \
-org/bouncycastle/jce/X509V3CertificateGenerator.java \
 org/bouncycastle/jce/exception/ExtCertificateEncodingException.java \
 org/bouncycastle/jce/exception/ExtIOException.java \
 org/bouncycastle/jce/interfaces/ElGamalKey.java \
@@ -331,19 +341,26 @@
 org/bouncycastle/jce/provider/X509StoreLDAPCertPairs.java \
 org/bouncycastle/jce/provider/X509StoreLDAPCerts.java \
 org/bouncycastle/jce/provider/symmetric/CAST5.java \
-org/bouncycastle/jce/provider/symmetric/CAST5Mappings.java \
+org/bouncycastle/jce/provider/symmetric/CAST6.java \
 org/bouncycastle/jce/provider/symmetric/Camellia.java \
-org/bouncycastle/jce/provider/symmetric/CamelliaMappings.java \
 org/bouncycastle/jce/provider/symmetric/Grain128.java \
-org/bouncycastle/jce/provider/symmetric/Grain128Mappings.java \
 org/bouncycastle/jce/provider/symmetric/Grainv1.java \
-org/bouncycastle/jce/provider/symmetric/Grainv1Mappings.java \
+org/bouncycastle/jce/provider/symmetric/HC128.java \
+org/bouncycastle/jce/provider/symmetric/HC256.java \
 org/bouncycastle/jce/provider/symmetric/IDEA.java \
-org/bouncycastle/jce/provider/symmetric/IDEAMappings.java \
 org/bouncycastle/jce/provider/symmetric/Noekeon.java \
-org/bouncycastle/jce/provider/symmetric/NoekeonMappings.java \
+org/bouncycastle/jce/provider/symmetric/RC5.java \
+org/bouncycastle/jce/provider/symmetric/RC6.java \
+org/bouncycastle/jce/provider/symmetric/Rijndael.java \
 org/bouncycastle/jce/provider/symmetric/SEED.java \
-org/bouncycastle/jce/provider/symmetric/SEEDMappings.java \
+org/bouncycastle/jce/provider/symmetric/Salsa20.java \
+org/bouncycastle/jce/provider/symmetric/Serpent.java \
+org/bouncycastle/jce/provider/symmetric/Skipjack.java \
+org/bouncycastle/jce/provider/symmetric/TEA.java \
+org/bouncycastle/jce/provider/symmetric/Twofish.java \
+org/bouncycastle/jce/provider/symmetric/VMPC.java \
+org/bouncycastle/jce/provider/symmetric/VMPCKSA3.java \
+org/bouncycastle/jce/provider/symmetric/XTEA.java \
 org/bouncycastle/jce/spec/ElGamalGenParameterSpec.java \
 org/bouncycastle/jce/spec/ElGamalKeySpec.java \
 org/bouncycastle/jce/spec/ElGamalParameterSpec.java \
@@ -360,15 +377,9 @@
 org/bouncycastle/jce/spec/MQVPublicKeySpec.java \
 org/bouncycastle/jce/spec/package.html \
 org/bouncycastle/math/ec/ReferenceMultiplier.java \
-org/bouncycastle/math/ec/WNafMultiplier.java \
-org/bouncycastle/math/ec/WNafPreCompInfo.java \
-org/bouncycastle/math/ec/WTauNafMultiplier.java \
-org/bouncycastle/math/ec/WTauNafPreCompInfo.java \
 org/bouncycastle/math/ec/package.html \
-org/bouncycastle/openssl/PEMException.java \
-org/bouncycastle/openssl/PEMReader.java \
-org/bouncycastle/openssl/PasswordException.java \
-org/bouncycastle/openssl/PasswordFinder.java \
+org/bouncycastle/math/ec/test \
+org/bouncycastle/openssl/PKCS8Generator.java \
 org/bouncycastle/openssl/package.html \
 org/bouncycastle/util/AllTests.java \
 org/bouncycastle/util/CollectionStore.java \
@@ -382,6 +393,9 @@
 org/bouncycastle/util/encoders/UrlBase64.java \
 org/bouncycastle/util/encoders/UrlBase64Encoder.java \
 org/bouncycastle/util/encoders/package.html \
+org/bouncycastle/util/io/TeeInputStream.java \
+org/bouncycastle/util/io/TeeOutputStream.java \
+org/bouncycastle/util/io/pem/AllTests.java \
 org/bouncycastle/x509/CertPathReviewerException.java \
 org/bouncycastle/x509/CertPathReviewerMessages_de.properties \
 org/bouncycastle/x509/NoSuchParserException.java \
diff --git a/bouncycastle.version b/bouncycastle.version
index 4f5851f..281f7f5 100644
--- a/bouncycastle.version
+++ b/bouncycastle.version
@@ -1,2 +1,2 @@
 BOUNCYCASTLE_JDK=16
-BOUNCYCASTLE_VERSION=145
+BOUNCYCASTLE_VERSION=146
diff --git a/import_bouncycastle.sh b/import_bouncycastle.sh
index 2271dc0..297efef 100755
--- a/import_bouncycastle.sh
+++ b/import_bouncycastle.sh
@@ -104,7 +104,7 @@
 
   cd $BOUNCYCASTLE_DIR
 
-  cp -f LICENSE.html ../NOTICE
+  sed 's/<p>/& <BR>/g' LICENSE.html | html2text -width 102 -nobs -ascii > ../NOTICE
   touch ../MODULE_LICENSE_BSD_LIKE
 
   cd ..
diff --git a/patches/README b/patches/README
index e586dd5..d56a5d8 100644
--- a/patches/README
+++ b/patches/README
@@ -12,18 +12,14 @@
 - MD2
 - RC2
 
-Other performance (both speed and memory) changes:
+Other performance (both speed and memory) and correctness changes:
 - singleton DERNull (BouncyCastle now does this but we make constructor private to be sure)
 - similarly made DERBoolean constructor private and moved to DERBoolean.{getInstance,TRUE,FALSE}
+- removed use of Boolean constructor
 - DERPrintableString interns its internal String values
 - DERObjectIdentifier interns its internal String indentifer value
 - changed uses of 'new Integer' to 'Integer.valueOf'
-- Added X509NameElementList to reduce small Vector allocation for X509Name key/value operations
-- Replaced X509Extensions hash/vector with new OrderedTable instance to cut down on memory allocation
-- PKCS12BagAttributeCarrier also uses OrderedTable to cut down on memory allocation
 - X509CertificateObject.getEncoded caches its result
-- Added IndexedPKIXParameters for faster cert lookup in CertPathValidatorUtilities.findTrustAnchor
-- Added ASN1Collection for use as new parent for ASN1Collection and ASN1Set to reduce small Vector allocation
 - removed references to SecretKeyFactory.PBE/PKCS5 SecretKeyFactory.PBE/PKCS12
 - OpenSSLDigest uses NativeCrypto JNI API
 - KeyStoreSpis made more tolerant of non-existant and null aliases
@@ -36,5 +32,8 @@
 - Added DSA support to JDKKeyManager.engineGetKeySpec
 
 Other security changes:
-- blacklist fraudulent Comodo certificates in PKIXCertPathValidatorSpi
-- blacklist compromised DigiNotar Root CA by public key to block cross-signed intermediates
+- Blacklist fraudulent Comodo certificates in PKIXCertPathValidatorSpi
+- Blacklist compromised DigiNotar Root CA by public key to block cross-signed intermediates
+
+Other changes:
+- Log entry and exit to DHParametersHelper.generateSafePrimes which has long, unpredictable runtime
diff --git a/patches/android.patch b/patches/android.patch
index 3ad2f08..452ec68 100644
--- a/patches/android.patch
+++ b/patches/android.patch
@@ -1,322 +1,20 @@
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Collection.java bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Collection.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Collection.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Collection.java	2011-09-03 18:25:17.000000000 +0000
-@@ -0,0 +1,298 @@
-+package org.bouncycastle.asn1;
-+
-+import java.io.ByteArrayOutputStream;
-+import java.io.IOException;
-+import java.util.Enumeration;
-+import java.util.ConcurrentModificationException;
-+
-+// BEGIN android-note
-+/*
-+ * This is a new class that was synthesized from ASN1Sequence and
-+ * ASN1Set, but with extra smarts about efficiently storing its
-+ * elements.
-+ */
-+// END android-note
-+
-+/**
-+ * Base class for collection-like <code>DERObject</code>s. Instances
-+ * of this class will keep up to four elements directly, resorting to
-+ * an external collection only if more elements than that need to be
-+ * stored.
-+ */
-+public abstract class ASN1Collection
-+    extends ASN1Object
-+{
-+    /** &gt;= 0; size of the collection */
-+    private int size;
-+
-+    /** null-ok; element #0 */
-+    private DEREncodable obj0;
-+
-+    /** null-ok; element #1 */
-+    private DEREncodable obj1;
-+
-+    /** null-ok; element #2 */
-+    private DEREncodable obj2;
-+
-+    /** null-ok; element #3 */
-+    private DEREncodable obj3;
-+
-+    /** null-ok; elements #4 and higher */
-+    private DEREncodable[] rest;
-+
-+    /**
-+     * Returns the object at the postion indicated by index.
-+     *
-+     * @param index the index (starting at zero) of the object
-+     * @return the object at the postion indicated by index
-+     */
-+    public DEREncodable getObjectAt(int index) {
-+        if ((index < 0) || (index >= size)) {
-+            throw new IndexOutOfBoundsException(Integer.toString(index));
-+        }
-+                    
-+        switch (index) {
-+            case 0: return obj0;
-+            case 1: return obj1;
-+            case 2: return obj2;
-+            case 3: return obj3;
-+            default: return rest[index - 4];
-+        }
-+    }
-+
-+    /**
-+     * Returns the number of objects in this instance.
-+     *
-+     * @return the number of objects in this instance
-+     */
-+    public int size() {
-+        return size;
-+    }
-+
-+    /** {@inheritDoc} */
-+    public final int hashCode() {
-+        Enumeration e = this.getObjects();
-+        int hashCode = 0;
-+
-+        while (e.hasMoreElements()) {
-+            Object o = e.nextElement();
-+            
-+            if (o != null) {
-+                hashCode ^= o.hashCode();
-+            }
-+        }
-+
-+        return hashCode;
-+    }
-+
-+    /**
-+     * Adds a new element to this instance.
-+     * 
-+     * @param obj non-null; the instance to add
-+     */
-+    protected void addObject(DEREncodable obj) {
-+        if (obj == null) {
-+            throw new NullPointerException("obj == null");
-+        }
-+
-+        int sz = size;
-+        
-+        switch (sz) {
-+            case 0: obj0 = obj; break;
-+            case 1: obj1 = obj; break;
-+            case 2: obj2 = obj; break;
-+            case 3: obj3 = obj; break;
-+            case 4: {
-+                // Initial allocation of rest.
-+                rest = new DEREncodable[5];
-+                rest[0] = obj;
-+                break;
-+            }
-+            default: {
-+                int index = sz - 4;
-+                if (index >= rest.length) {
-+                    // Grow rest.
-+                    DEREncodable[] newRest = new DEREncodable[index * 2 + 10];
-+                    System.arraycopy(rest, 0, newRest, 0, rest.length);
-+                    rest = newRest;
-+                }
-+                rest[index] = obj;
-+                break;
-+            }
-+        }
-+
-+        size++;
-+    }
-+
-+    /**
-+     * Sets the element at a given index (used by {@link #sort}).
-+     * 
-+     * @param obj non-null; the object to set
-+     * @param index &gt;= 0; the index
-+     */
-+    private void setObjectAt(DEREncodable obj, int index) {
-+        switch (index) {
-+            case 0: obj0 = obj; break;
-+            case 1: obj1 = obj; break;
-+            case 2: obj2 = obj; break;
-+            case 3: obj3 = obj; break;
-+            default: {
-+                rest[index - 4] = obj;
-+                break;
-+            }
-+        }
-+    }
-+
-+    /**
-+     * Encodes this instance to the given stream.
-+     * 
-+     * @param out non-null; stream to encode to
-+     */
-+    /*package*/ abstract void encode(DEROutputStream out) throws IOException;
-+
-+    /**
-+     * Gets an enumeration of all the objects in this collection.
-+     * 
-+     * @return non-null; the enumeration
-+     */
-+    public Enumeration getObjects() {
-+        return new ASN1CollectionEnumeration();
-+    }
-+
-+    /**
-+     * Associated enumeration class.
-+     */
-+    private class ASN1CollectionEnumeration implements Enumeration {
-+        /** original size; used for modification detection */
-+        private final int origSize = size;
-+
-+        /** &gt;= 0; current cursor */
-+        private int at = 0;
-+
-+        /** {@inheritDoc} */
-+        public boolean hasMoreElements() {
-+            if (size != origSize) {
-+                throw new ConcurrentModificationException();
-+            }
-+
-+            return at < origSize;
-+        }
-+
-+        /** {@inheritDoc} */
-+        public Object nextElement() {
-+            if (size != origSize) {
-+                throw new ConcurrentModificationException();
-+            }
-+
-+            switch (at++) {
-+                case 0: return obj0;
-+                case 1: return obj1;
-+                case 2: return obj2;
-+                case 3: return obj3;
-+                default: return rest[at - 5];
-+            }
-+        }
-+    }
-+
-+    /**
-+     * Sorts the elements in this instance.
-+     */
-+    protected void sort() {
-+        if (size <= 1) {
-+            return;
-+        }
-+
-+        boolean swapped = true;
-+
-+        // TODO: This is bubble sort. Probably not the best choice.
-+        while (swapped) {
-+            int index = 0;
-+            byte[] a = getEncoded(getObjectAt(0));
-+                
-+            swapped = false;
-+                
-+            while (index != size - 1) {
-+                int nextIndex = index + 1;
-+                byte[] b = getEncoded(getObjectAt(nextIndex));
-+
-+                if (lessThanOrEqual(a, b)) {
-+                    a = b;
-+                } else {
-+                    DEREncodable o = getObjectAt(index);
-+                    
-+                    setObjectAt(getObjectAt(nextIndex), index);
-+                    setObjectAt(o, nextIndex);
-+
-+                    swapped = true;
-+                }
-+
-+                index++;
-+            }
-+        }
-+    }
-+    
-+    /**
-+     * Returns true if a <= b (arrays are assumed padded with zeros).
-+     */
-+    private static boolean lessThanOrEqual(byte[] a, byte[] b) {
-+        if (a.length <= b.length) {
-+            for (int i = 0; i != a.length; i++) {
-+                int l = a[i] & 0xff;
-+                int r = b[i] & 0xff;
-+                 
-+                if (r > l) {
-+                    return true;
-+                } else if (l > r) {
-+                    return false;
-+                }
-+            }
-+
-+            return true;
-+        } else {
-+            for (int i = 0; i != b.length; i++) {
-+                 int l = a[i] & 0xff;
-+                 int r = b[i] & 0xff;
-+                 
-+                 if (r > l) {
-+                     return true;
-+                 } else if (l > r) {
-+                     return false;
-+                 }
-+             }
-+
-+             return false;
-+         }
-+    }
-+
-+    /**
-+     * Gets the encoded form of an object.
-+     * 
-+     * @param obj non-null; object to encode
-+     * @return non-null; the encoded form
-+     */
-+    private static byte[] getEncoded(DEREncodable obj) {
-+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-+        ASN1OutputStream aOut = new ASN1OutputStream(bOut);
-+
-+        try {
-+            aOut.writeObject(obj);
-+        } catch (IOException e) {
-+            throw new IllegalArgumentException(
-+                    "cannot encode object added to collection");
-+        }
-+
-+        return bOut.toByteArray();
-+    }
-+
-+    /** {@inheritDoc} */
-+    public final String toString() {
-+        StringBuilder sb = new StringBuilder();
-+        sb.append('[');
-+        for (int i = 0; i < size; i++) {
-+            if (i != 0) sb.append(", ");
-+            sb.append(getObjectAt(i));
-+        }
-+        sb.append(']');
-+        return sb.toString();
-+    }
-+}
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1InputStream.java bcprov-jdk16-145/org/bouncycastle/asn1/ASN1InputStream.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1InputStream.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1InputStream.java	2011-09-03 18:25:17.000000000 +0000
-@@ -348,7 +348,9 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/ASN1InputStream.java bcprov-jdk16-146/org/bouncycastle/asn1/ASN1InputStream.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/ASN1InputStream.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/ASN1InputStream.java	2011-09-08 21:28:50.000000000 +0000
+@@ -363,7 +363,9 @@
              case BMP_STRING:
                  return new DERBMPString(bytes);
              case BOOLEAN:
--                return new DERBoolean(bytes);
+-                return new ASN1Boolean(bytes);
 +                // BEGIN android-changed
 +                return DERBoolean.getInstance(bytes);
 +                // END android-changed
              case ENUMERATED:
-                 return new DEREnumerated(bytes);
+                 return new ASN1Enumerated(bytes);
              case GENERALIZED_TIME:
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Null.java bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Null.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Null.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Null.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/ASN1Null.java bcprov-jdk16-146/org/bouncycastle/asn1/ASN1Null.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/ASN1Null.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/ASN1Null.java	2011-09-08 21:28:50.000000000 +0000
 @@ -8,9 +8,11 @@
  public abstract class ASN1Null
      extends ASN1Object
@@ -330,522 +28,9 @@
  
      public int hashCode()
      {
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Sequence.java bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Sequence.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Sequence.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Sequence.java	2011-09-03 18:25:17.000000000 +0000
-@@ -2,12 +2,20 @@
- 
- import java.io.IOException;
- import java.util.Enumeration;
--import java.util.Vector;
-+// BEGIN android-removed
-+// import java.util.Vector;
-+// END android-removed
-+
-+// BEGIN android-note
-+// Changed inheritence of class.
-+// END android-note
- 
- public abstract class ASN1Sequence
--    extends ASN1Object
-+    extends ASN1Collection
- {
--    private Vector seq = new Vector();
-+    // BEGIN android-removed
-+    // private Vector seq = new Vector();
-+    // END android-removed
- 
-     /**
-      * return an ASN1Sequence from the given object.
-@@ -85,10 +93,12 @@
-         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
-     }
- 
--    public Enumeration getObjects()
--    {
--        return seq.elements();
--    }
-+    // BEGIN android-removed
-+    // public Enumeration getObjects()
-+    // {
-+    //     return seq.elements();
-+    // }
-+    // END android-removed
- 
-     public ASN1SequenceParser parser()
-     {
-@@ -127,45 +137,47 @@
-         };
-     }
- 
--    /**
--     * 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 DEREncodable getObjectAt(
--        int index)
--    {
--        return (DEREncodable)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 = e.nextElement();
--            hashCode *= 17;
--            if (o != null)
--            {
--                hashCode ^= o.hashCode();
--            }
--        }
--
--        return hashCode;
--    }
-+    // BEGIN android-removed
-+    // /**
-+    //  * 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 DEREncodable getObjectAt(
-+    //     int index)
-+    // {
-+    //     return (DEREncodable)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 = e.nextElement();
-+    //         hashCode *= 17;
-+    //         if (o != null)
-+    //         {
-+    //             hashCode ^= o.hashCode();
-+    //         }
-+    //     }
-+    //
-+    //     return hashCode;
-+    // }
-+    // END android-removed
- 
-     boolean asn1Equals(
-         DERObject  o)
-@@ -201,17 +213,19 @@
-         return true;
-     }
- 
--    protected void addObject(
--        DEREncodable obj)
--    {
--        seq.addElement(obj);
--    }
--
--    abstract void encode(DEROutputStream out)
--        throws IOException;
--
--    public String toString() 
--    {
--      return seq.toString();
--    }
-+    // BEGIN android-removed
-+    //protected void addObject(
-+    //    DEREncodable obj)
-+    //{
-+    //    seq.addElement(obj);
-+    //}
-+
-+    //abstract void encode(DEROutputStream out)
-+    //    throws IOException;
-+
-+    //public String toString() 
-+    //{
-+    //  return seq.toString();
-+    //}
-+    // END android-removed
- }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Set.java bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Set.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/ASN1Set.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/ASN1Set.java	2011-09-03 18:25:17.000000000 +0000
-@@ -3,12 +3,20 @@
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.util.Enumeration;
--import java.util.Vector;
-+// BEGIN android-removed
-+// import java.util.Vector;
-+// END android-removed
-+
-+// BEGIN android-note
-+// Changed inheritence of class.
-+// END android-note
- 
- abstract public class ASN1Set
--    extends ASN1Object
-+    extends ASN1Collection
- {
--    protected Vector set = new Vector();
-+    // BEGIN android-removed
-+    // protected Vector set = new Vector();
-+    // END android-removed
- 
-     /**
-      * return an ASN1Set from the given object.
-@@ -104,32 +112,34 @@
-     {
-     }
- 
--    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 DEREncodable getObjectAt(
--        int index)
--    {
--        return (DEREncodable)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();
--    }
-+    // BEGIN android-removed
-+    // 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 DEREncodable getObjectAt(
-+    //     int index)
-+    // {
-+    //     return (DEREncodable)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();
-+    // }
-+    // END android-removed
- 
-     public ASN1SetParser parser()
-     {
-@@ -168,23 +178,25 @@
-         };
-     }
- 
--    public int hashCode()
--    {
--        Enumeration             e = this.getObjects();
--        int                     hashCode = size();
--
--        while (e.hasMoreElements())
--        {
--            Object o = e.nextElement();
--            hashCode *= 17;
--            if (o != null)
--            {
--                hashCode ^= o.hashCode();
--            }
--        }
--
--        return hashCode;
--    }
-+    // BEGIN android-removed
-+    // public int hashCode()
-+    // {
-+    //     Enumeration             e = this.getObjects();
-+    //     int                     hashCode = size();
-+    //
-+    //     while (e.hasMoreElements())
-+    //     {
-+    //         Object o = e.nextElement();
-+    //         hashCode *= 17;
-+    //         if (o != null)
-+    //         {
-+    //             hashCode ^= o.hashCode();
-+    //         }
-+    //     }
-+    //
-+    //     return hashCode;
-+    // }
-+    // END android-removed
- 
-     boolean asn1Equals(
-         DERObject  o)
-@@ -220,52 +232,54 @@
-         return true;
-     }
- 
--    /**
--     * return true if a <= b (arrays are assumed padded with zeros).
--     */
--    private boolean lessThanOrEqual(
--         byte[] a,
--         byte[] b)
--    {
--         if (a.length <= b.length)
--         {
--             for (int i = 0; i != a.length; i++)
--             {
--                 int    l = a[i] & 0xff;
--                 int    r = b[i] & 0xff;
--                 
--                 if (r > l)
--                 {
--                     return true;
--                 }
--                 else if (l > r)
--                 {
--                     return false;
--                 }
--             }
--
--             return true;
--         }
--         else
--         {
--             for (int i = 0; i != b.length; i++)
--             {
--                 int    l = a[i] & 0xff;
--                 int    r = b[i] & 0xff;
--                 
--                 if (r > l)
--                 {
--                     return true;
--                 }
--                 else if (l > r)
--                 {
--                     return false;
--                 }
--             }
--
--             return false;
--         }
--    }
-+    // BEGIN android-removed
-+    // /**
-+    //  * return true if a <= b (arrays are assumed padded with zeros).
-+    //  */
-+    // private boolean lessThanOrEqual(
-+    //      byte[] a,
-+    //      byte[] b)
-+    // {
-+    //      if (a.length <= b.length)
-+    //      {
-+    //          for (int i = 0; i != a.length; i++)
-+    //          {
-+    //              int    l = a[i] & 0xff;
-+    //              int    r = b[i] & 0xff;
-+    //
-+    //              if (r > l)
-+    //              {
-+    //                  return true;
-+    //              }
-+    //              else if (l > r)
-+    //              {
-+    //                  return false;
-+    //              }
-+    //          }
-+    //
-+    //          return true;
-+    //      }
-+    //      else
-+    //      {
-+    //          for (int i = 0; i != b.length; i++)
-+    //          {
-+    //              int    l = a[i] & 0xff;
-+    //              int    r = b[i] & 0xff;
-+    //
-+    //              if (r > l)
-+    //              {
-+    //                  return true;
-+    //              }
-+    //              else if (l > r)
-+    //              {
-+    //                  return false;
-+    //              }
-+    //          }
-+    //
-+    //          return false;
-+    //      }
-+    // }
-+    // END android-removed
- 
-     private byte[] getEncoded(
-         DEREncodable obj)
-@@ -285,59 +299,61 @@
-         return bOut.toByteArray();
-     }
- 
--    protected void sort()
--    {
--        if (set.size() > 1)
--        {
--            boolean    swapped = true;
--            int        lastSwap = set.size() - 1;
--
--            while (swapped)
--            {
--                int    index = 0;
--                int    swapIndex = 0;
--                byte[] a = getEncoded((DEREncodable)set.elementAt(0));
--                
--                swapped = false;
--
--                while (index != lastSwap)
--                {
--                    byte[] b = getEncoded((DEREncodable)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;
--            }
--        }
--    }
--
--    protected void addObject(
--        DEREncodable obj)
--    {
--        set.addElement(obj);
--    }
--
--    abstract void encode(DEROutputStream out)
--            throws IOException;
--
--    public String toString() 
--    {
--      return set.toString();
--    }
-+    // BEGIN android-removed
-+    // protected void sort()
-+    // {
-+    //     if (set.size() > 1)
-+    //     {
-+    //         boolean    swapped = true;
-+    //         int        lastSwap = set.size() - 1;
-+    //
-+    //         while (swapped)
-+    //         {
-+    //             int    index = 0;
-+    //             int    swapIndex = 0;
-+    //             byte[] a = getEncoded((DEREncodable)set.elementAt(0));
-+    //
-+    //             swapped = false;
-+    //
-+    //             while (index != lastSwap)
-+    //             {
-+    //                 byte[] b = getEncoded((DEREncodable)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;
-+    //         }
-+    //     }
-+    // }
-+    //
-+    // protected void addObject(
-+    //     DEREncodable obj)
-+    // {
-+    //     set.addElement(obj);
-+    // }
-+    //
-+    // abstract void encode(DEROutputStream out)
-+    //         throws IOException;
-+    //
-+    // public String toString() 
-+    // {
-+    //   return set.toString();
-+    // }
-+    // END android-removed
- }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERBoolean.java bcprov-jdk16-145/org/bouncycastle/asn1/DERBoolean.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERBoolean.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/DERBoolean.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERBoolean.java bcprov-jdk16-146/org/bouncycastle/asn1/DERBoolean.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERBoolean.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/DERBoolean.java	2011-09-08 21:28:50.000000000 +0000
 @@ -5,7 +5,9 @@
  public class DERBoolean
      extends ASN1Object
@@ -857,18 +42,7 @@
  
      public static final DERBoolean FALSE = new DERBoolean(false);
      public static final DERBoolean TRUE  = new DERBoolean(true);
-@@ -25,7 +27,9 @@
- 
-         if (obj instanceof ASN1OctetString)
-         {
--            return new DERBoolean(((ASN1OctetString)obj).getOctets());
-+            // BEGIN android-changed
-+            return getInstance(((ASN1OctetString)obj).getOctets());
-+            // END android-changed
-         }
- 
-         if (obj instanceof ASN1TaggedObject)
-@@ -45,6 +49,17 @@
+@@ -35,6 +37,17 @@
          return (value ? TRUE : FALSE);
      }
  
@@ -886,64 +60,51 @@
      /**
       * return a Boolean from a tagged object.
       *
-@@ -60,18 +75,22 @@
-     {
-         return getInstance(obj.getObject());
+@@ -56,23 +69,29 @@
+         }
+         else
+         {
+-            return new DERBoolean(((ASN1OctetString)o).getOctets());
++            // BEGIN android-changed
++            return getInstance(((ASN1OctetString)o).getOctets());
++            // END android-changed
+         }
      }
--    
+     
 -    public DERBoolean(
 -        byte[]       value)
 -    {
+-        if (value.length != 1)
+-        {
+-            throw new IllegalArgumentException("byte value should have 1 byte in it");
+-        }
+-        
 -        this.value = value[0];
 -    }
++    // BEGIN android-removed
++    // public DERBoolean(
++    //     byte[]       value)
++    // {
++    //     if (value.length != 1)
++    //     {
++    //         throw new IllegalArgumentException("byte value should have 1 byte in it");
++    //     }
++    //
++    //     this.value = value[0];
++    // }
++    // END android-removed
  
 -    public DERBoolean(
-+    // BEGIN android-removed
-+    //private DERBoolean(
-+    //    byte[]       value)
-+    //{
-+    //    this.value = value[0];
-+    //}
-+    // END android-removed
-+
 +    // BEGIN android-changed
-+    private DERBoolean(
++    protected DERBoolean(
          boolean     value)
++    // END android-changed
      {
          this.value = (value) ? (byte)0xff : (byte)0;
      }
-+    // END android-changed
- 
-     public boolean isTrue()
-     {
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERInputStream.java bcprov-jdk16-145/org/bouncycastle/asn1/DERInputStream.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERInputStream.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/DERInputStream.java	2011-09-03 18:25:17.000000000 +0000
-@@ -144,7 +144,9 @@
-                 return new DERConstructedSet(v);
-             }
-         case BOOLEAN:
--            return new DERBoolean(bytes);
-+            // BEGIN android-changed
-+            return DERBoolean.getInstance(bytes);
-+            // BEGIN android-changed
-         case INTEGER:
-             return new DERInteger(bytes);
-         case ENUMERATED:
-@@ -195,7 +197,9 @@
-                 {
-                     if ((tag & CONSTRUCTED) == 0)
-                     {
--                        return new DERTaggedObject(false, tag & 0x1f, new DERNull());
-+                        // BEGIN android-changed
-+                        return new DERTaggedObject(false, tag & 0x1f, DERNull.INSTANCE);
-+                        // END android-changed
-                     }
-                     else
-                     {
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERNull.java bcprov-jdk16-145/org/bouncycastle/asn1/DERNull.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERNull.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/DERNull.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERNull.java bcprov-jdk16-146/org/bouncycastle/asn1/DERNull.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERNull.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/DERNull.java	2011-09-08 21:28:50.000000000 +0000
 @@ -10,9 +10,13 @@
  {
      public static final DERNull INSTANCE = new DERNull();
@@ -960,10 +121,10 @@
      {
      }
  
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERObjectIdentifier.java bcprov-jdk16-145/org/bouncycastle/asn1/DERObjectIdentifier.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERObjectIdentifier.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/DERObjectIdentifier.java	2011-09-03 18:25:17.000000000 +0000
-@@ -111,7 +111,13 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERObjectIdentifier.java bcprov-jdk16-146/org/bouncycastle/asn1/DERObjectIdentifier.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERObjectIdentifier.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/DERObjectIdentifier.java	2011-09-08 21:28:50.000000000 +0000
+@@ -110,7 +110,13 @@
              }
          }
  
@@ -978,7 +139,7 @@
      }
  
      public DERObjectIdentifier(
-@@ -122,7 +128,13 @@
+@@ -121,7 +127,13 @@
              throw new IllegalArgumentException("string " + identifier + " not an OID");
          }
  
@@ -993,9 +154,9 @@
      }
  
      public String getId()
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERPrintableString.java bcprov-jdk16-145/org/bouncycastle/asn1/DERPrintableString.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/DERPrintableString.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/DERPrintableString.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERPrintableString.java bcprov-jdk16-146/org/bouncycastle/asn1/DERPrintableString.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/DERPrintableString.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/DERPrintableString.java	2011-09-08 21:28:50.000000000 +0000
 @@ -9,7 +9,9 @@
      extends ASN1Object
      implements DERString
@@ -1007,7 +168,7 @@
  
      /**
       * return a printable string from the passed in object.
-@@ -66,7 +68,9 @@
+@@ -65,7 +67,9 @@
              cs[i] = (char)(string[i] & 0xff);
          }
  
@@ -1018,7 +179,7 @@
      }
  
      /**
-@@ -95,7 +99,9 @@
+@@ -94,7 +98,9 @@
              throw new IllegalArgumentException("string contains illegal characters");
          }
  
@@ -1029,294 +190,23 @@
      }
  
      public String getString()
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/OrderedTable.java bcprov-jdk16-145/org/bouncycastle/asn1/OrderedTable.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/OrderedTable.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/OrderedTable.java	2011-09-03 18:25:17.000000000 +0000
-@@ -0,0 +1,281 @@
-+package org.bouncycastle.asn1;
-+
-+import java.util.Enumeration;
-+import java.util.ConcurrentModificationException;
-+
-+// BEGIN android-note
-+/*
-+ * This is a new class that was synthesized from the observed
-+ * requirement for a lookup table that preserves order. Since in
-+ * practice the element count is typically very low, we just use a
-+ * flat list rather than doing any hashing / bucketing.
-+ */
-+// END android-note
-+
-+/**
-+ * Ordered lookup table. Instances of this class will keep up to four
-+ * key-value pairs directly, resorting to an external collection only
-+ * if more elements than that need to be stored.
-+ */
-+public final class OrderedTable {
-+    /** null-ok; key #0 */
-+    private DERObjectIdentifier key0;
-+    
-+    /** null-ok; key #1 */
-+    private DERObjectIdentifier key1;
-+
-+    /** null-ok; key #2 */
-+    private DERObjectIdentifier key2;
-+
-+    /** null-ok; key #3 */
-+    private DERObjectIdentifier key3;
-+    
-+    /** null-ok; value #0 */
-+    private Object value0;
-+    
-+    /** null-ok; value #1 */
-+    private Object value1;
-+
-+    /** null-ok; value #2 */
-+    private Object value2;
-+
-+    /** null-ok; value #3 */
-+    private Object value3;
-+    
-+    /**
-+     * null-ok; array of additional keys and values, alternating
-+     * key then value, etc. 
-+     */
-+    private Object[] rest;
-+
-+    /** &gt;= 0; number of elements in the list */
-+    private int size;
-+
-+    // Note: Default public constructor.
-+
-+    /**
-+     * Adds an element assuming no duplicate key.
-+     * 
-+     * @see #put
-+     * 
-+     * @param key non-null; the key
-+     * @param value non-null; the value
-+     */
-+    public void add(DERObjectIdentifier key, Object value) {
-+        if (key == null) {
-+            throw new NullPointerException("key == null");
-+        }
-+
-+        if (value == null) {
-+            throw new NullPointerException("value == null");
-+        }
-+
-+        int sz = size;
-+
-+        switch (sz) {
-+            case 0: {
-+                key0 = key;
-+                value0 = value;
-+                break;
-+            }
-+            case 1: {
-+                key1 = key;
-+                value1 = value;
-+                break;
-+            }
-+            case 2: {
-+                key2 = key;
-+                value2 = value;
-+                break;
-+            }
-+            case 3: {
-+                key3 = key;
-+                value3 = value;
-+                break;
-+            }
-+            case 4: {
-+                // Do initial allocation of rest.
-+                rest = new Object[10];
-+                rest[0] = key;
-+                rest[1] = value;
-+                break;
-+            }
-+            default: {
-+                int index = (sz - 4) * 2;
-+                int index1 = index + 1;
-+                if (index1 >= rest.length) {
-+                    // Grow rest.
-+                    Object[] newRest = new Object[index1 * 2 + 10];
-+                    System.arraycopy(rest, 0, newRest, 0, rest.length);
-+                    rest = newRest;
-+                }
-+                rest[index] = key;
-+                rest[index1] = value;
-+                break;
-+            }
-+        }
-+        
-+        size = sz + 1;
-+    }
-+
-+    /**
-+     * Gets the number of elements in this instance.
-+     */
-+    public int size() {
-+        return size;
-+    }
-+
-+    /**
-+     * Look up the given key, returning the associated value if found.
-+     * 
-+     * @param key non-null; the key to look up
-+     * @return null-ok; the associated value
-+     */
-+    public Object get(DERObjectIdentifier key) {
-+        int keyHash = key.hashCode();
-+        int sz = size;
-+
-+        for (int i = 0; i < size; i++) {
-+            DERObjectIdentifier probe = getKey(i);
-+            if ((probe.hashCode() == keyHash) &&
-+                    probe.equals(key)) {
-+                return getValue(i);
-+            }
-+        }
-+
-+        return null;
-+    }
-+    
-+    /**
-+     * Replace a key if present, otherwise add
-+     * 
-+     * @see #add
-+     * 
-+     * @param key non-null; the key
-+     * @param value non-null; the value
-+     */
-+    public void put(DERObjectIdentifier key, Object value) {
-+        if (key == null) {
-+            throw new NullPointerException("key == null");
-+        }
-+
-+        if (value == null) {
-+            throw new NullPointerException("value == null");
-+        }
-+
-+        int keyHash = key.hashCode();
-+        int sz = size;
-+
-+        for (int i = 0; i < size; i++) {
-+            DERObjectIdentifier probe = getKey(i);
-+            if ((probe.hashCode() == keyHash) &&
-+                    probe.equals(key)) {
-+                setValue(i, value);
-+                return;
-+            }
-+        }
-+
-+        add(key, value);
-+    }
-+    
-+    /**
-+     * Gets the nth key.
-+     * 
-+     * @param n index
-+     * @return non-null; the nth key
-+     */
-+    public DERObjectIdentifier getKey(int n) {
-+        if ((n < 0) || (n >= size)) {
-+            throw new IndexOutOfBoundsException(Integer.toString(n));
-+        }
-+
-+        switch (n) {
-+            case 0: return key0;
-+            case 1: return key1;
-+            case 2: return key2;
-+            case 3: return key3;
-+            default: return (DERObjectIdentifier) rest[(n - 4) * 2];
-+        }
-+    }
-+
-+    /**
-+     * Gets the nth value.
-+     * 
-+     * @param n index
-+     * @return non-null; the nth value
-+     */
-+    public Object getValue(int n) {
-+        if ((n < 0) || (n >= size)) {
-+            throw new IndexOutOfBoundsException(Integer.toString(n));
-+        }
-+
-+        switch (n) {
-+            case 0: return value0;
-+            case 1: return value1;
-+            case 2: return value2;
-+            case 3: return value3;
-+            default: return rest[((n - 4) * 2) + 1];
-+        }
-+    }
-+
-+    /**
-+     * Sets the nth value.
-+     * 
-+     * @param n index
-+     * @param value non-null object
-+     */
-+    public void setValue(int n, Object value) {
-+        if ((n < 0) || (n >= size)) {
-+            throw new IndexOutOfBoundsException(Integer.toString(n));
-+        }
-+        if (value == null) {
-+            throw new NullPointerException("value == null");
-+        }
-+
-+        switch (n) {
-+            case 0: value0 = value; return;
-+            case 1: value1 = value; return;
-+            case 2: value2 = value; return;
-+            case 3: value3 = value; return;
-+            default: rest[((n - 4) * 2) + 1] = value; return;
-+        }
-+    }
-+
-+    /**
-+     * Gets an enumeration of the keys, in order.
-+     * 
-+     * @return non-null; an enumeration of the keys
-+     */
-+    public Enumeration getKeys() {
-+        return new KeyEnumeration();
-+    }
-+
-+    /**
-+     * Associated enumeration class.
-+     */
-+    private class KeyEnumeration implements Enumeration {
-+        /** original size; used for modification detection */
-+        private final int origSize = size;
-+
-+        /** &gt;= 0; current cursor */
-+        private int at = 0;
-+
-+        /** {@inheritDoc} */
-+        public boolean hasMoreElements() {
-+            if (size != origSize) {
-+                throw new ConcurrentModificationException();
-+            }
-+
-+            return at < origSize;
-+        }
-+
-+        /** {@inheritDoc} */
-+        public Object nextElement() {
-+            if (size != origSize) {
-+                throw new ConcurrentModificationException();
-+            }
-+
-+            return getKey(at++);
-+        }
-+    }
-+}
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/cms/ContentInfo.java bcprov-jdk16-146/org/bouncycastle/asn1/cms/ContentInfo.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/cms/ContentInfo.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/cms/ContentInfo.java	2011-09-08 21:28:50.000000000 +0000
+@@ -12,7 +12,9 @@
+ 
+ public class ContentInfo
+     extends ASN1Encodable
+-    implements CMSObjectIdentifiers
++    // BEGIN android-removed
++    // implements CMSObjectIdentifiers
++    // END android-removed
+ {
+     private ASN1ObjectIdentifier contentType;
+     private DEREncodable        content;
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java	2011-09-08 21:28:50.000000000 +0000
 @@ -37,10 +37,13 @@
      public static EncryptedPrivateKeyInfo getInstance(
          Object  obj)
@@ -1332,36 +222,67 @@
          else if (obj instanceof ASN1Sequence)
          { 
              return new EncryptedPrivateKeyInfo((ASN1Sequence)obj);
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2011-09-03 18:25:17.000000000 +0000
-@@ -10,7 +10,10 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2011-09-08 21:28:50.000000000 +0000
+@@ -10,8 +10,10 @@
      //
-     static final String                 pkcs_1                    = "1.2.840.113549.1.1";
-     static final DERObjectIdentifier    rsaEncryption             = new DERObjectIdentifier(pkcs_1 + ".1");
--    static final DERObjectIdentifier    md2WithRSAEncryption      = new DERObjectIdentifier(pkcs_1 + ".2");
+     static final ASN1ObjectIdentifier    pkcs_1                    = new ASN1ObjectIdentifier("1.2.840.113549.1.1");
+     static final ASN1ObjectIdentifier    rsaEncryption             = pkcs_1.branch("1");
+-    static final ASN1ObjectIdentifier    md2WithRSAEncryption      = pkcs_1.branch("2");
+-    static final ASN1ObjectIdentifier    md4WithRSAEncryption      = pkcs_1.branch("3");
 +    // BEGIN android-removed
-+    // Dropping MD2
-+    // static final DERObjectIdentifier    md2WithRSAEncryption      = new DERObjectIdentifier(pkcs_1 + ".2");
++    // static final ASN1ObjectIdentifier    md2WithRSAEncryption      = pkcs_1.branch("2");
++    // static final ASN1ObjectIdentifier    md4WithRSAEncryption      = pkcs_1.branch("3");
 +    // END android-removed
-     static final DERObjectIdentifier    md4WithRSAEncryption      = new DERObjectIdentifier(pkcs_1 + ".3");
-     static final DERObjectIdentifier    md5WithRSAEncryption      = new DERObjectIdentifier(pkcs_1 + ".4");
-     static final DERObjectIdentifier    sha1WithRSAEncryption     = new DERObjectIdentifier(pkcs_1 + ".5");
-@@ -65,7 +68,10 @@
+     static final ASN1ObjectIdentifier    md5WithRSAEncryption      = pkcs_1.branch("4");
+     static final ASN1ObjectIdentifier    sha1WithRSAEncryption     = pkcs_1.branch("5");
+     static final ASN1ObjectIdentifier    srsaOAEPEncryptionSET     = pkcs_1.branch("6");
+@@ -22,7 +24,9 @@
+     static final ASN1ObjectIdentifier    sha256WithRSAEncryption   = pkcs_1.branch("11");
+     static final ASN1ObjectIdentifier    sha384WithRSAEncryption   = pkcs_1.branch("12");
+     static final ASN1ObjectIdentifier    sha512WithRSAEncryption   = pkcs_1.branch("13");
+-    static final ASN1ObjectIdentifier    sha224WithRSAEncryption   = pkcs_1.branch("14");
++    // BEGIN android-removed
++    // static final ASN1ObjectIdentifier    sha224WithRSAEncryption   = pkcs_1.branch("14");
++    // END android-removed
+ 
+     //
+     // pkcs-3 OBJECT IDENTIFIER ::= {
+@@ -65,13 +69,17 @@
      // md2 OBJECT IDENTIFIER ::=
      //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2}
      //
--    static final DERObjectIdentifier    md2                     = new DERObjectIdentifier(digestAlgorithm + ".2");
+-    static final ASN1ObjectIdentifier    md2                    = digestAlgorithm.branch("2");
 +    // BEGIN android-removed
-+    // Dropping MD2
-+    // static final DERObjectIdentifier    md2                     = new DERObjectIdentifier(digestAlgorithm + ".2");
++    // static final ASN1ObjectIdentifier    md2                    = digestAlgorithm.branch("2");
 +    // END android-removed
  
      //
      // md4 OBJECT IDENTIFIER ::=
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java	2011-09-03 18:25:17.000000000 +0000
+     //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4}
+     //
+-    static final ASN1ObjectIdentifier    md4 = digestAlgorithm.branch("4");
++    // BEGIN android-removed
++    // static final ASN1ObjectIdentifier    md4 = digestAlgorithm.branch("4");
++    // END android-removed
+ 
+     //
+     // md5 OBJECT IDENTIFIER ::=
+@@ -80,7 +88,9 @@
+     static final ASN1ObjectIdentifier    md5                     = digestAlgorithm.branch("5");
+ 
+     static final ASN1ObjectIdentifier    id_hmacWithSHA1         = digestAlgorithm.branch("7");
+-    static final ASN1ObjectIdentifier    id_hmacWithSHA224       = digestAlgorithm.branch("8");
++    // BEGIN android-removed
++    // static final ASN1ObjectIdentifier    id_hmacWithSHA224       = digestAlgorithm.branch("8");
++    // END android-removed
+     static final ASN1ObjectIdentifier    id_hmacWithSHA256       = digestAlgorithm.branch("9");
+     static final ASN1ObjectIdentifier    id_hmacWithSHA384       = digestAlgorithm.branch("10");
+     static final ASN1ObjectIdentifier    id_hmacWithSHA512       = digestAlgorithm.branch("11");
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java	2011-09-08 21:28:50.000000000 +0000
 @@ -19,7 +19,9 @@
      private AlgorithmIdentifier maskGenAlgorithm;
      private AlgorithmIdentifier pSourceAlgorithm;
@@ -1373,9 +294,9 @@
      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]));
      
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java	2011-09-08 21:28:50.000000000 +0000
 @@ -20,7 +20,9 @@
      private DERInteger          saltLength;
      private DERInteger          trailerField;
@@ -1387,10 +308,10 @@
      public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);
      public final static DERInteger          DEFAULT_SALT_LENGTH = new DERInteger(20);
      public final static DERInteger          DEFAULT_TRAILER_FIELD = new DERInteger(1);
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/util/ASN1Dump.java bcprov-jdk16-145/org/bouncycastle/asn1/util/ASN1Dump.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/util/ASN1Dump.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/util/ASN1Dump.java	2011-09-03 18:25:17.000000000 +0000
-@@ -90,7 +90,9 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/util/ASN1Dump.java bcprov-jdk16-146/org/bouncycastle/asn1/util/ASN1Dump.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/util/ASN1Dump.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/util/ASN1Dump.java	2011-09-08 21:28:50.000000000 +0000
+@@ -79,7 +79,9 @@
              {
                  Object  o = e.nextElement();
  
@@ -1401,9 +322,9 @@
                  {
                      buf.append(tab);
                      buf.append("NULL");
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/AttCertIssuer.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/AttCertIssuer.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/AttCertIssuer.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/AttCertIssuer.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/AttCertIssuer.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/AttCertIssuer.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/AttCertIssuer.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/AttCertIssuer.java	2011-09-08 21:28:50.000000000 +0000
 @@ -45,7 +45,7 @@
          ASN1TaggedObject obj,
          boolean          explicit)
@@ -1413,9 +334,9 @@
      }
  
      /**
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/BasicConstraints.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/BasicConstraints.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/BasicConstraints.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/BasicConstraints.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/BasicConstraints.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/BasicConstraints.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/BasicConstraints.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/BasicConstraints.java	2011-09-08 21:28:50.000000000 +0000
 @@ -14,7 +14,9 @@
  public class BasicConstraints
      extends ASN1Encodable
@@ -1460,9 +381,9 @@
          this.pathLenConstraint = new DERInteger(pathLenConstraint);
      }
  
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java	2011-09-08 21:28:50.000000000 +0000
 @@ -96,11 +96,15 @@
          }
          if (onlyContainsUserCerts)
@@ -1499,156 +420,10 @@
          }
  
          seq = new DERSequence(vec);
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509Extensions.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509Extensions.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509Extensions.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509Extensions.java	2011-09-03 18:25:17.000000000 +0000
-@@ -9,6 +9,9 @@
- import org.bouncycastle.asn1.DERObject;
- import org.bouncycastle.asn1.DERObjectIdentifier;
- import org.bouncycastle.asn1.DERSequence;
-+// BEGIN android-added
-+import org.bouncycastle.asn1.OrderedTable;
-+// END android-added
- 
- import java.util.Enumeration;
- import java.util.Hashtable;
-@@ -172,8 +175,9 @@
-      */
-     public static final DERObjectIdentifier TargetInformation = new DERObjectIdentifier("2.5.29.55");
-     
--    private Hashtable               extensions = new Hashtable();
--    private Vector                  ordering = new Vector();
-+    // BEGIN android-changed
-+    private OrderedTable table = new OrderedTable();
-+    // END android-changed
- 
-     public static X509Extensions getInstance(
-         ASN1TaggedObject obj,
-@@ -217,20 +221,26 @@
-         {
-             ASN1Sequence            s = ASN1Sequence.getInstance(e.nextElement());
- 
--            if (s.size() == 3)
-+            // BEGIN android-changed
-+            int sSize = s.size();
-+            DERObjectIdentifier key = (DERObjectIdentifier) s.getObjectAt(0);
-+            Object value;
-+            
-+            if (sSize == 3)
-             {
--                extensions.put(s.getObjectAt(0), new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2))));
-+                value = new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2)));
-             }
--            else if (s.size() == 2)
-+            else if (sSize == 2)
-             {
--                extensions.put(s.getObjectAt(0), new X509Extension(false, ASN1OctetString.getInstance(s.getObjectAt(1))));
-+                value = new X509Extension(false, ASN1OctetString.getInstance(s.getObjectAt(1)));
-             }
-             else
-             {
--                throw new IllegalArgumentException("Bad sequence size: " + s.size());
-+                throw new IllegalArgumentException("Bad sequence size: " + sSize);
-             }
- 
--            ordering.addElement(s.getObjectAt(0));
-+            table.add(key, value);
-+            // END android-changed
-         }
-     }
- 
-@@ -265,20 +275,14 @@
-             e = ordering.elements();
-         }
- 
--        while (e.hasMoreElements())
--        {
--            this.ordering.addElement(e.nextElement()); 
--        }
--
--        e = this.ordering.elements();
--
-+        // BEGIN android-changed
-         while (e.hasMoreElements())
-         {
-             DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
-             X509Extension           ext = (X509Extension)extensions.get(oid);
--
--            this.extensions.put(oid, ext);
-+            table.add(oid, ext);
-         }
-+        // END android-changed
-     }
- 
-     /**
-@@ -293,23 +297,18 @@
-     {
-         Enumeration e = objectIDs.elements();
- 
--        while (e.hasMoreElements())
--        {
--            this.ordering.addElement(e.nextElement()); 
--        }
--
-+        // BEGIN android-changed
-         int count = 0;
-         
--        e = this.ordering.elements();
--
-         while (e.hasMoreElements())
-         {
-             DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
-             X509Extension           ext = (X509Extension)values.elementAt(count);
- 
--            this.extensions.put(oid, ext);
-+            table.add(oid, ext);
-             count++;
-         }
-+        // END android-changed
-     }
-     
-     /**
-@@ -317,7 +316,9 @@
-      */
-     public Enumeration oids()
-     {
--        return ordering.elements();
-+        // BEGIN android-changed
-+        return table.getKeys();
-+        // END android-changed
-     }
- 
-     /**
-@@ -329,7 +330,9 @@
-     public X509Extension getExtension(
-         DERObjectIdentifier oid)
-     {
--        return (X509Extension)extensions.get(oid);
-+        // BEGIN android-changed
-+        return (X509Extension)table.get(oid);
-+        // END android-changed
-     }
- 
-     /**
-@@ -345,19 +348,23 @@
-     public DERObject toASN1Object()
-     {
-         ASN1EncodableVector     vec = new ASN1EncodableVector();
--        Enumeration             e = ordering.elements();
-+        // BEGIN android-changed
-+        int                     size = table.size();
- 
--        while (e.hasMoreElements())
-+        for (int i = 0; i < size; i++)
-         {
--            DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
--            X509Extension           ext = (X509Extension)extensions.get(oid);
-+            DERObjectIdentifier     oid = table.getKey(i);
-+            X509Extension           ext = (X509Extension)table.getValue(i);
-+            // END android-changed
-             ASN1EncodableVector     v = new ASN1EncodableVector();
- 
-             v.add(oid);
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509Extensions.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509Extensions.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509Extensions.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509Extensions.java	2011-09-08 21:28:50.000000000 +0000
+@@ -400,7 +400,9 @@
  
              if (ext.isCritical())
              {
@@ -1659,714 +434,47 @@
              }
  
              v.add(ext.getValue());
-@@ -371,18 +378,24 @@
-     public boolean equivalent(
-         X509Extensions other)
-     {
--        if (extensions.size() != other.extensions.size())
-+        // BEGIN android-changed
-+        if (table.size() != other.table.size())
-+        // END android-changed
-         {
-             return false;
-         }
- 
--        Enumeration     e1 = extensions.keys();
-+        // BEGIN android-changed
-+        Enumeration     e1 = table.getKeys();
-+        // END android-changed
- 
-         while (e1.hasMoreElements())
-         {
--            Object  key = e1.nextElement();
-+            // BEGIN android-changed
-+            DERObjectIdentifier  key = (DERObjectIdentifier)e1.nextElement();
- 
--            if (!extensions.get(key).equals(other.extensions.get(key)))
-+            if (!table.get(key).equals(other.table.get(key)))
-+            // END android-changed
-             {
-                 return false;
-             }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509Name.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509Name.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509Name.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509Name.java	2011-09-03 18:25:17.000000000 +0000
-@@ -247,8 +247,10 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509Name.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509Name.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509Name.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509Name.java	2011-09-08 21:28:50.000000000 +0000
+@@ -249,8 +249,10 @@
       */
      public static final Hashtable SymbolLookUp = DefaultLookUp;
  
 -    private static final Boolean TRUE = new Boolean(true); // for J2ME compatibility
 -    private static final Boolean FALSE = new Boolean(false);
-+    // BEGIN android-removed
-+    //private static final Boolean TRUE = new Boolean(true); // for J2ME compatibility
-+    //private static final Boolean FALSE = new Boolean(false);
-+    // END android-removed
++    // BEGIN android-changed
++    private static final Boolean TRUE = Boolean.TRUE;
++    private static final Boolean FALSE = Boolean.FALSE;
++    // END android-changed
  
      static
      {
-@@ -340,9 +342,9 @@
-     }
- 
-     private X509NameEntryConverter  converter = null;
--    private Vector                  ordering = new Vector();
--    private Vector                  values = new Vector();
--    private Vector                  added = new Vector();
-+    // BEGIN android-changed
-+    private X509NameElementList     elems = new X509NameElementList();
-+    // END android-changed
- 
-     private ASN1Sequence            seq;
- 
-@@ -403,26 +405,30 @@
-                        throw new IllegalArgumentException("badly sized pair");
-                    }
- 
--                   ordering.addElement(DERObjectIdentifier.getInstance(s.getObjectAt(0)));
-+                   // BEGIN android-changed
-+                   DERObjectIdentifier key = DERObjectIdentifier.getInstance(s.getObjectAt(0));
-                    
-                    DEREncodable value = s.getObjectAt(1);
-+                   String valueStr;
-                    if (value instanceof DERString && !(value instanceof DERUniversalString))
+@@ -432,7 +434,9 @@
                     {
-                        String v = ((DERString)value).getString();
-                        if (v.length() > 0 && v.charAt(0) == '#')
-                        {
--                           values.addElement("\\" + v);
-+                           valueStr = "\\" + v;
-                        }
-                        else
-                        {
--                           values.addElement(v);
-+                           valueStr = v;
-                        }
-                    }
-                    else
-                    {
--                       values.addElement("#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded())));
-+                       valueStr = "#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded()));
+                        values.addElement("#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded())));
                     }
 -                   added.addElement((i != 0) ? TRUE : FALSE);  // to allow earlier JDK compatibility
-+                   boolean added = (i != 0);  // to allow earlier JDK compatibility
-+                   elems.add(key, valueStr, added);
++                   // BEGIN android-changed
++                   added.addElement(Boolean.valueOf(i != 0));
 +                   // END android-changed
              }
          }
      }
-@@ -476,14 +482,23 @@
-         Hashtable                attributes,
-         X509NameEntryConverter   converter)
-     {
-+        // BEGIN android-changed
-+        DERObjectIdentifier problem = null;
-         this.converter = converter;
- 
-         if (ordering != null)
-         {
-             for (int i = 0; i != ordering.size(); i++)
-             {
--                this.ordering.addElement(ordering.elementAt(i));
--                this.added.addElement(FALSE);
-+                DERObjectIdentifier key =
-+                    (DERObjectIdentifier) ordering.elementAt(i);
-+                String value = (String) attributes.get(key);
-+                if (value == null)
-+                {
-+                    problem = key;
-+                    break;
-+                }
-+                elems.add(key, value);
-             }
-         }
-         else
-@@ -492,22 +507,23 @@
- 
-             while (e.hasMoreElements())
-             {
--                this.ordering.addElement(e.nextElement());
--                this.added.addElement(FALSE);
-+                DERObjectIdentifier key =
-+                    (DERObjectIdentifier) e.nextElement();
-+                String value = (String) attributes.get(key);
-+                if (value == null)
-+                {
-+                    problem = key;
-+                    break;
-+                }
-+                elems.add(key, value);
-             }
-         }
- 
--        for (int i = 0; i != this.ordering.size(); i++)
-+        if (problem != null)
-         {
--            DERObjectIdentifier     oid = (DERObjectIdentifier)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
-+            throw new IllegalArgumentException("No attribute for object id - " + problem.getId() + " - passed to distinguished name");
-         }
-+        // END android-changed
-     }
- 
-     /**
-@@ -540,9 +556,10 @@
- 
-         for (int i = 0; i < oids.size(); i++)
-         {
--            this.ordering.addElement(oids.elementAt(i));
--            this.values.addElement(values.elementAt(i));
--            this.added.addElement(FALSE);
-+            // BEGIN android-changed
-+            elems.add((DERObjectIdentifier) oids.elementAt(i),
-+                    (String) values.elementAt(i));
-+            // END android-changed
-         }
-     }
- 
-@@ -679,7 +696,7 @@
+@@ -689,7 +693,9 @@
  
              if (index == -1)
              {
 -                throw new IllegalArgumentException("badly formated directory string");
++                // BEGIN android-changed
 +                throw new IllegalArgumentException("badly formatted directory string");
++                // END android-changed
              }
  
              String              name = token.substring(0, index);
-@@ -691,9 +708,9 @@
-                 X509NameTokenizer   vTok = new X509NameTokenizer(value, '+');
-                 String  v = vTok.nextToken();
- 
--                this.ordering.addElement(oid);
--                this.values.addElement(v);
--                this.added.addElement(FALSE);
-+                // BEGIN android-changed
-+                this.elems.add(oid, v);
-+                // END android-changed
- 
-                 while (vTok.hasMoreTokens())
-                 {
-@@ -702,48 +719,24 @@
- 
-                     String  nm = sv.substring(0, ndx);
-                     String  vl = sv.substring(ndx + 1);
--                    this.ordering.addElement(decodeOID(nm, lookUp));
--                    this.values.addElement(vl);
--                    this.added.addElement(TRUE);
-+                    // BEGIN android-changed
-+                    this.elems.add(decodeOID(nm, lookUp), vl, true);
-+                    // END android-changed
-                 }
-             }
-             else
-             {
--                this.ordering.addElement(oid);
--                this.values.addElement(value);
--                this.added.addElement(FALSE);
-+                // BEGIN android-changed
-+                this.elems.add(oid, value);
-+                // END android-changed
-             }
-         }
- 
-         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;
-+            // BEGIN android-changed
-+            this.elems = this.elems.reverse();
-+            // END android-changed
-         }
-     }
- 
-@@ -752,14 +745,17 @@
-      */
-     public Vector getOIDs()
-     {
-+        // BEGIN android-changed
-         Vector  v = new Vector();
-+        int     size = elems.size();
- 
--        for (int i = 0; i != ordering.size(); i++)
-+        for (int i = 0; i < size; i++)
-         {
--            v.addElement(ordering.elementAt(i));
-+            v.addElement(elems.getKey(i));
-         }
- 
-         return v;
-+        // END android-changed
-     }
- 
-     /**
-@@ -769,11 +765,14 @@
-     public Vector getValues()
-     {
-         Vector  v = new Vector();
-+        // BEGIN android-changed
-+        int     size = elems.size();
- 
--        for (int i = 0; i != values.size(); i++)
-+        for (int i = 0; i != size; i++)
-         {
--            v.addElement(values.elementAt(i));
-+            v.addElement(elems.getValue(i));
-         }
-+        // END android-changed
- 
-         return v;
-     }
-@@ -786,12 +785,14 @@
-         DERObjectIdentifier oid)
-     {
-         Vector  v = new Vector();
-+        int     size = elems.size();
-+        // BEGIN android-changed
- 
--        for (int i = 0; i != values.size(); i++)
-+        for (int i = 0; i != size; i++)
-         {
--            if (ordering.elementAt(i).equals(oid))
-+            if (elems.getKey(i).equals(oid))
-             {
--                String val = (String)values.elementAt(i);
-+                String val = elems.getValue(i);
- 
-                 if (val.length() > 2 && val.charAt(0) == '\\' && val.charAt(1) == '#')
-                 {
-@@ -803,6 +804,7 @@
-                 }
-             }
-         }
-+        // END android-changed
- 
-         return v;
-     }
-@@ -814,20 +816,23 @@
-             ASN1EncodableVector  vec = new ASN1EncodableVector();
-             ASN1EncodableVector  sVec = new ASN1EncodableVector();
-             DERObjectIdentifier  lstOid = null;
-+            // BEGIN android-changed
-+            int                  size = elems.size();
-             
--            for (int i = 0; i != ordering.size(); i++)
-+            for (int i = 0; i != size; i++)
-             {
-                 ASN1EncodableVector     v = new ASN1EncodableVector();
--                DERObjectIdentifier     oid = (DERObjectIdentifier)ordering.elementAt(i);
-+                DERObjectIdentifier     oid = elems.getKey(i);
- 
-                 v.add(oid);
- 
--                String  str = (String)values.elementAt(i);
-+                String  str = elems.getValue(i);
- 
-                 v.add(converter.getConvertedValue(oid, str));
-  
-                 if (lstOid == null 
--                    || ((Boolean)this.added.elementAt(i)).booleanValue())
-+                    || this.elems.getAdded(i))
-+                // END android-changed
-                 {
-                     sVec.add(new DERSequence(v));
-                 }
-@@ -845,6 +850,7 @@
-             vec.add(new DERSet(sVec));
-             
-             seq = new DERSequence(vec);
-+            // END android-changed
-         }
- 
-         return seq;
-@@ -889,22 +895,28 @@
-             return false;
-         }
- 
--        int      orderingSize = ordering.size();
-+        // BEGIN android-changed
-+        int      orderingSize = elems.size();
- 
--        if (orderingSize != other.ordering.size())
-+        if (orderingSize != other.elems.size())
-+        // END android-changed
-         {
-             return false;
-         }
- 
-         for (int i = 0; i < orderingSize; i++)
-         {
--            DERObjectIdentifier  oid = (DERObjectIdentifier)ordering.elementAt(i);
--            DERObjectIdentifier  oOid = (DERObjectIdentifier)other.ordering.elementAt(i);
-+            // BEGIN android-changed
-+            DERObjectIdentifier  oid = elems.getKey(i);
-+            DERObjectIdentifier  oOid = other.elems.getKey(i);
-+            // END android-changed
- 
-             if (oid.equals(oOid))
-             {
--                String value = (String)values.elementAt(i);
--                String oValue = (String)other.values.elementAt(i);
-+                // BEGIN android-changed
-+                String value = elems.getValue(i);
-+                String oValue = other.elems.getValue(i);
-+                // END android-changed
- 
-                 if (!equivalentStrings(value, oValue))
-                 {
-@@ -930,9 +942,9 @@
-         isHashCodeCalculated = true;
- 
-         // this needs to be order independent, like equals
--        for (int i = 0; i != ordering.size(); i += 1)
-+        for (int i = 0; i != elems.size(); i += 1)
-         {
--            String value = (String)values.elementAt(i);
-+            String value = (String)elems.getValue(i);
- 
-             value = canonicalize(value);
-             value = stripInternalSpaces(value);
-@@ -976,9 +988,11 @@
-             return false;
-         }
- 
--        int      orderingSize = ordering.size();
-+        // BEGIN android-changed
-+        int      orderingSize = elems.size();
- 
--        if (orderingSize != other.ordering.size())
-+        if (orderingSize != other.elems.size())
-+            // END android-changed
-         {
-             return false;
-         }
-@@ -986,7 +1000,9 @@
-         boolean[] indexes = new boolean[orderingSize];
-         int       start, end, delta;
- 
--        if (ordering.elementAt(0).equals(other.ordering.elementAt(0)))   // guess forward
-+        // BEGIN android-changed
-+        if (elems.getKey(0).equals(other.elems.getKey(0)))   // guess forward
-+        // END android-changed
-         {
-             start = 0;
-             end = orderingSize;
-@@ -1002,8 +1018,10 @@
-         for (int i = start; i != end; i += delta)
-         {
-             boolean              found = false;
--            DERObjectIdentifier  oid = (DERObjectIdentifier)ordering.elementAt(i);
--            String               value = (String)values.elementAt(i);
-+            // BEGIN android-changed
-+            DERObjectIdentifier  oid = elems.getKey(i);
-+            String               value = elems.getValue(i);
-+            // END android-changed
- 
-             for (int j = 0; j < orderingSize; j++)
-             {
-@@ -1012,11 +1030,15 @@
-                     continue;
-                 }
- 
--                DERObjectIdentifier oOid = (DERObjectIdentifier)other.ordering.elementAt(j);
-+                // BEGIN android-changed
-+                DERObjectIdentifier oOid = other.elems.getKey(j);
-+                // END android-changed
- 
-                 if (oid.equals(oOid))
-                 {
--                    String oValue = (String)other.values.elementAt(j);
-+                    // BEGIN android-changed
-+                    String oValue = other.elems.getValue(j);
-+                    // END android-changed
- 
-                     if (equivalentStrings(value, oValue))
-                     {
-@@ -1181,28 +1203,36 @@
- 
-         StringBuffer ava = null;
- 
--        for (int i = 0; i < ordering.size(); i++)
-+        // BEGIN android-changed
-+        for (int i = 0; i < elems.size(); i++)
-+        // END android-changed
-         {
--            if (((Boolean)added.elementAt(i)).booleanValue())
-+            if (elems.getAdded(i))
-             {
-                 ava.append('+');
-                 appendValue(ava, oidSymbols,
--                    (DERObjectIdentifier)ordering.elementAt(i),
--                    (String)values.elementAt(i));
-+                    // BEGIN android-changed
-+                    elems.getKey(i),
-+                    elems.getValue(i));
-+                    // END android-changed
-             }
-             else
-             {
-                 ava = new StringBuffer();
-                 appendValue(ava, oidSymbols,
--                    (DERObjectIdentifier)ordering.elementAt(i),
--                    (String)values.elementAt(i));
-+                    // BEGIN android-changed
-+                    elems.getKey(i),
-+                    elems.getValue(i));
-+                    // END android-changed
-                 components.addElement(ava);
-             }
-         }
- 
-         if (reverse)
-         {
--            for (int i = components.size() - 1; i >= 0; i--)
-+            // BEGIN android-changed
-+            for (int i = elems.size() - 1; i >= 0; i--)
-+            // END android-changed
-             {
-                 if (first)
-                 {
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509NameElementList.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509NameElementList.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509NameElementList.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509NameElementList.java	2011-09-03 18:25:17.000000000 +0000
-@@ -0,0 +1,206 @@
-+package org.bouncycastle.asn1.x509;
-+
-+import java.util.ArrayList;
-+import java.util.BitSet;
-+import org.bouncycastle.asn1.DERObjectIdentifier;
-+
-+// BEGIN android-note
-+// This class was extracted from X509Name as a way to keep the element
-+// list in a more controlled fashion.
-+// END android-note
-+
-+/**
-+ * List of elements of an X509 name. Each element has a key, a value, and
-+ * an "added" flag.
-+ */
-+public class X509NameElementList {
-+    /** null-ok; key #0 */
-+    private DERObjectIdentifier key0;
-+    
-+    /** null-ok; key #1 */
-+    private DERObjectIdentifier key1;
-+
-+    /** null-ok; key #2 */
-+    private DERObjectIdentifier key2;
-+
-+    /** null-ok; key #3 */
-+    private DERObjectIdentifier key3;
-+    
-+    /** null-ok; value #0 */
-+    private String value0;
-+    
-+    /** null-ok; value #1 */
-+    private String value1;
-+
-+    /** null-ok; value #2 */
-+    private String value2;
-+
-+    /** null-ok; value #3 */
-+    private String value3;
-+    
-+    /**
-+     * null-ok; array of additional keys and values, alternating
-+     * key then value, etc. 
-+     */
-+    private ArrayList<Object> rest;
-+
-+    /** bit vector for all the "added" bits */
-+    private BitSet added = new BitSet();
-+
-+    /** &gt;= 0; number of elements in the list */
-+    private int size;
-+
-+    // Note: Default public constructor.
-+    
-+    /**
-+     * Adds an element. The "added" flag is set to false for the element.
-+     * 
-+     * @param key non-null; the key
-+     * @param value non-null; the value
-+     */
-+    public void add(DERObjectIdentifier key, String value) {
-+        add(key, value, false);
-+    }
-+
-+    /**
-+     * Adds an element.
-+     * 
-+     * @param key non-null; the key
-+     * @param value non-null; the value
-+     * @param added the added bit
-+     */
-+    public void add(DERObjectIdentifier key, String value, boolean added) {
-+        if (key == null) {
-+            throw new NullPointerException("key == null");
-+        }
-+
-+        if (value == null) {
-+            throw new NullPointerException("value == null");
-+        }
-+
-+        int sz = size;
-+
-+        switch (sz) {
-+            case 0: {
-+                key0 = key;
-+                value0 = value;
-+                break;
-+            }
-+            case 1: {
-+                key1 = key;
-+                value1 = value;
-+                break;
-+            }
-+            case 2: {
-+                key2 = key;
-+                value2 = value;
-+                break;
-+            }
-+            case 3: {
-+                key3 = key;
-+                value3 = value;
-+                break;
-+            }
-+            case 4: {
-+                // Do initial allocation of rest.
-+                rest = new ArrayList<Object>();
-+                // Fall through...
-+            }
-+            default: {
-+                rest.add(key);
-+                rest.add(value);
-+                break;
-+            }
-+        }
-+
-+        if (added) {
-+            this.added.set(sz);
-+        }
-+        
-+        size = sz + 1;
-+    }
-+
-+    /**
-+     * Sets the "added" flag on the most recently added element.
-+     */
-+    public void setLastAddedFlag() {
-+        added.set(size - 1);
-+    }
-+
-+    /**
-+     * Gets the number of elements in this instance.
-+     */
-+    public int size() {
-+        return size;
-+    }
-+    
-+    /**
-+     * Gets the nth key.
-+     * 
-+     * @param n index
-+     * @return non-null; the nth key
-+     */
-+    public DERObjectIdentifier getKey(int n) {
-+        if ((n < 0) || (n >= size)) {
-+            throw new IndexOutOfBoundsException(Integer.toString(n));
-+        }
-+
-+        switch (n) {
-+            case 0: return key0;
-+            case 1: return key1;
-+            case 2: return key2;
-+            case 3: return key3;
-+            default: return (DERObjectIdentifier) rest.get((n - 4) * 2);
-+        }
-+    }
-+
-+    /**
-+     * Gets the nth value.
-+     * 
-+     * @param n index
-+     * @return non-null; the nth value
-+     */
-+    public String getValue(int n) {
-+        if ((n < 0) || (n >= size)) {
-+            throw new IndexOutOfBoundsException(Integer.toString(n));
-+        }
-+
-+        switch (n) {
-+            case 0: return value0;
-+            case 1: return value1;
-+            case 2: return value2;
-+            case 3: return value3;
-+            default: return (String) rest.get(((n - 4) * 2) + 1);
-+        }
-+    }
-+
-+    /**
-+     * Gets the nth added flag bit.
-+     * 
-+     * @param n index
-+     * @return the nth added flag bit
-+     */
-+    public boolean getAdded(int n) {
-+        if ((n < 0) || (n >= size)) {
-+            throw new IndexOutOfBoundsException(Integer.toString(n));
-+        }
-+
-+        return added.get(n);
-+    }
-+
-+    /**
-+     * Constructs and returns a new instance which consists of the
-+     * elements of this one in reverse order
-+     * 
-+     * @return non-null; the reversed instance
-+     */
-+    public X509NameElementList reverse() {
-+        X509NameElementList result = new X509NameElementList();
-+            
-+        for (int i = size - 1; i >= 0; i--) {
-+            result.add(getKey(i), getValue(i), getAdded(i));
-+        }
-+
-+        return result;
-+    }
-+}
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509NameTokenizer.java
---- bcprov-jdk16-145.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509NameTokenizer.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2011-09-08 21:28:50.000000000 +0000
 @@ -58,6 +58,17 @@
                  }
                  else
@@ -2392,9 +500,9 @@
 -}
 +}
 \ No newline at end of file
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/PBEParametersGenerator.java bcprov-jdk16-145/org/bouncycastle/crypto/PBEParametersGenerator.java
---- bcprov-jdk16-145.orig/org/bouncycastle/crypto/PBEParametersGenerator.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/PBEParametersGenerator.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/PBEParametersGenerator.java bcprov-jdk16-146/org/bouncycastle/crypto/PBEParametersGenerator.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/crypto/PBEParametersGenerator.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/crypto/PBEParametersGenerator.java	2011-09-08 21:28:49.000000000 +0000
 @@ -136,7 +136,8 @@
      public static byte[] PKCS12PasswordToBytes(
          char[]  password)
@@ -2412,9 +520,9 @@
 +        // END android-changed
      }
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java bcprov-jdk16-145/org/bouncycastle/crypto/digests/OpenSSLDigest.java
---- bcprov-jdk16-145.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/digests/OpenSSLDigest.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java bcprov-jdk16-146/org/bouncycastle/crypto/digests/OpenSSLDigest.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java	1970-01-01 00:00:00.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/crypto/digests/OpenSSLDigest.java	2011-09-08 21:28:49.000000000 +0000
 @@ -0,0 +1,159 @@
 +/*
 + * Copyright (C) 2008 The Android Open Source Project
@@ -2575,9 +683,9 @@
 +        public SHA512() { super("SHA-512", EVP_MD, SIZE, BLOCK_SIZE); }
 +    }
 +}
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/engines/RC2Engine.java bcprov-jdk16-145/org/bouncycastle/crypto/engines/RC2Engine.java
---- bcprov-jdk16-145.orig/org/bouncycastle/crypto/engines/RC2Engine.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/engines/RC2Engine.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/engines/RC2Engine.java bcprov-jdk16-146/org/bouncycastle/crypto/engines/RC2Engine.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/crypto/engines/RC2Engine.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/crypto/engines/RC2Engine.java	2011-09-08 21:28:49.000000000 +0000
 @@ -313,4 +313,4 @@
          out[outOff + 6] = (byte)x76;
          out[outOff + 7] = (byte)(x76 >> 8);
@@ -2585,9 +693,62 @@
 -}
 +}
 \ No newline at end of file
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/macs/HMac.java bcprov-jdk16-145/org/bouncycastle/crypto/macs/HMac.java
---- bcprov-jdk16-145.orig/org/bouncycastle/crypto/macs/HMac.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/macs/HMac.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/generators/DHParametersHelper.java bcprov-jdk16-146/org/bouncycastle/crypto/generators/DHParametersHelper.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/crypto/generators/DHParametersHelper.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/crypto/generators/DHParametersHelper.java	2011-09-08 21:28:49.000000000 +0000
+@@ -3,10 +3,17 @@
+ import java.math.BigInteger;
+ import java.security.SecureRandom;
+ 
++// BEGIN android-added
++import java.util.logging.Logger;
++// END android-added
+ import org.bouncycastle.util.BigIntegers;
+ 
+ class DHParametersHelper
+ {
++    // BEGIN android-added
++    private static final Logger logger = Logger.getLogger(DHParametersHelper.class.getName());
++    // END android-added
++
+     private static final BigInteger ONE = BigInteger.valueOf(1);
+     private static final BigInteger TWO = BigInteger.valueOf(2);
+ 
+@@ -17,11 +24,19 @@
+      */
+     static BigInteger[] generateSafePrimes(int size, int certainty, SecureRandom random)
+     {
++        // BEGIN android-added
++        logger.info("Generating safe primes. This may take a long time.");
++        long start = System.currentTimeMillis();
++        int tries = 0;
++        // END android-added
+         BigInteger p, q;
+         int qLength = size - 1;
+ 
+         for (;;)
+         {
++            // BEGIN android-added
++            tries++;
++            // END android-added
+             q = new BigInteger(qLength, 2, random);
+ 
+             // p <- 2q + 1
+@@ -32,6 +47,11 @@
+                 break;
+             }
+         }
++        // BEGIN android-added
++        long end = System.currentTimeMillis();
++        long duration = end - start;
++        logger.info("Generated safe primes: " + tries + " tries took " + duration + "ms");
++        // END android-added
+ 
+         return new BigInteger[] { p, q };
+     }
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/macs/HMac.java bcprov-jdk16-146/org/bouncycastle/crypto/macs/HMac.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/crypto/macs/HMac.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/crypto/macs/HMac.java	2011-09-08 21:28:49.000000000 +0000
 @@ -32,23 +32,23 @@
      {
          blockLengths = new Hashtable();
@@ -2627,9 +788,9 @@
      }
      
      private static int getByteLength(
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java bcprov-jdk16-145/org/bouncycastle/crypto/signers/RSADigestSigner.java
---- bcprov-jdk16-145.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/signers/RSADigestSigner.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java bcprov-jdk16-146/org/bouncycastle/crypto/signers/RSADigestSigner.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/crypto/signers/RSADigestSigner.java	2011-09-08 21:28:49.000000000 +0000
 @@ -46,8 +46,10 @@
          oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384);
          oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
@@ -2643,10 +804,10 @@
          oidMap.put("MD5", PKCSObjectIdentifiers.md5);
      }
  
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java bcprov-jdk16-145/org/bouncycastle/crypto/util/PrivateKeyFactory.java
---- bcprov-jdk16-145.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2011-09-03 18:25:17.000000000 +0000
-@@ -8,7 +8,9 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java bcprov-jdk16-146/org/bouncycastle/crypto/util/PrivateKeyFactory.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2011-09-08 21:28:49.000000000 +0000
+@@ -12,7 +12,9 @@
  import org.bouncycastle.asn1.DERObject;
  import org.bouncycastle.asn1.DERObjectIdentifier;
  import org.bouncycastle.asn1.nist.NISTNamedCurves;
@@ -2657,7 +818,7 @@
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
  import org.bouncycastle.asn1.pkcs.DHParameter;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-@@ -16,7 +18,9 @@
+@@ -20,7 +22,9 @@
  import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
  import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
  import org.bouncycastle.asn1.sec.SECNamedCurves;
@@ -2668,7 +829,7 @@
  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  import org.bouncycastle.asn1.x509.DSAParameter;
  import org.bouncycastle.asn1.x9.X962NamedCurves;
-@@ -30,8 +34,10 @@
+@@ -34,8 +38,10 @@
  import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
  import org.bouncycastle.crypto.params.ECDomainParameters;
  import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
@@ -2680,69 +841,42 @@
 +// END android-removed
  import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
  
- import java.io.IOException;
-@@ -113,52 +119,56 @@
+ /**
+@@ -103,15 +109,17 @@
  
              return new DHPrivateKeyParameters(derX.getValue(), dhParams);
          }
 -        else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
 -        {
--            ElGamalParameter    params = new ElGamalParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
--            DERInteger          derX = (DERInteger)keyInfo.getPrivateKey();
+-            ElGamalParameter params = new ElGamalParameter(
+-                (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+-            DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
 -
--            return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(params.getP(), params.getG()));
+-            return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(
+-                params.getP(), params.getG()));
 -        }
 +        // BEGIN android-removed
 +        // else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
 +        // {
-+        //     ElGamalParameter    params = new ElGamalParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-+        //     DERInteger          derX = (DERInteger)keyInfo.getPrivateKey();
++        //     ElGamalParameter params = new ElGamalParameter(
++        //         (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
++        //     DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
 +        //
-+        //     return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(params.getP(), params.getG()));
++        //     return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(
++        //         params.getP(), params.getG()));
 +        // }
 +        // END android-removed
          else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa))
          {
              DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
-             DEREncodable de = keyInfo.getAlgorithmId().getParameters();
--
-+        
-             DSAParameters parameters = null;
-             if (de != null)
-             {
-                 DSAParameter params = DSAParameter.getInstance(de.getDERObject());
-                 parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
-             }
--
-+        
-             return new DSAPrivateKeyParameters(derX.getValue(), parameters);
-         }
-         else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
-         {
-             X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
-             ECDomainParameters  dParams = null;
--            
-+        
-             if (params.isNamedCurve())
-             {
-                 DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
-                 X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
--
-+        
-                 if (ecP == null)
-                 {
-                     ecP = SECNamedCurves.getByOID(oid);
--
-+        
-                     if (ecP == null)
+@@ -145,10 +153,12 @@
                      {
                          ecP = NISTNamedCurves.getByOID(oid);
--
+ 
 -                        if (ecP == null)
 -                        {
 -                            ecP = TeleTrusTNamedCurves.getByOID(oid);
 -                        }
-+        
 +                        // BEGIN android-removed
 +                        // if (ecP == null)
 +                        // {
@@ -2751,27 +885,11 @@
 +                        // END android-removed
                      }
                  }
--
-+        
-                 dParams = new ECDomainParameters(
-                                             ecP.getCurve(),
-                                             ecP.getG(),
-@@ -177,9 +187,9 @@
-                                             ecP.getH(),
-                                             ecP.getSeed());
-             }
--
-+        
-             ECPrivateKeyStructure   ec = new ECPrivateKeyStructure((ASN1Sequence)keyInfo.getPrivateKey());
--
-+        
-             return new ECPrivateKeyParameters(ec.getKey(), dParams);
-         }
-         else
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java bcprov-jdk16-145/org/bouncycastle/crypto/util/PublicKeyFactory.java
---- bcprov-jdk16-145.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/crypto/util/PublicKeyFactory.java	2011-09-03 18:25:17.000000000 +0000
-@@ -11,12 +11,16 @@
+ 
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java bcprov-jdk16-146/org/bouncycastle/crypto/util/PublicKeyFactory.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/crypto/util/PublicKeyFactory.java	2011-09-08 21:28:49.000000000 +0000
+@@ -15,12 +15,16 @@
  import org.bouncycastle.asn1.DERObjectIdentifier;
  import org.bouncycastle.asn1.DEROctetString;
  import org.bouncycastle.asn1.nist.NISTNamedCurves;
@@ -2790,7 +908,7 @@
  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  import org.bouncycastle.asn1.x509.DSAParameter;
  import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
-@@ -34,8 +38,10 @@
+@@ -42,8 +46,10 @@
  import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
  import org.bouncycastle.crypto.params.ECDomainParameters;
  import org.bouncycastle.crypto.params.ECPublicKeyParameters;
@@ -2802,56 +920,42 @@
 +// END android-removed
  import org.bouncycastle.crypto.params.RSAKeyParameters;
  
- import java.io.IOException;
-@@ -112,13 +118,15 @@
+ /**
+@@ -139,15 +145,17 @@
  
              return new DHPublicKeyParameters(derY.getValue(), dhParams);
          }
 -        else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
 -        {
--            ElGamalParameter    params = new ElGamalParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
--            DERInteger          derY = (DERInteger)keyInfo.getPublicKey();
+-            ElGamalParameter params = new ElGamalParameter(
+-                (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+-            DERInteger derY = (DERInteger)keyInfo.getPublicKey();
 -
--            return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(params.getP(), params.getG()));
+-            return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
+-                params.getP(), params.getG()));
 -        }
 +        // BEGIN android-removed
 +        // else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
 +        // {
-+        //     ElGamalParameter    params = new ElGamalParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-+        //     DERInteger          derY = (DERInteger)keyInfo.getPublicKey();
++        //     ElGamalParameter params = new ElGamalParameter(
++        //         (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
++        //     DERInteger derY = (DERInteger)keyInfo.getPublicKey();
 +        //
-+        //     return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(params.getP(), params.getG()));
++        //     return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
++        //         params.getP(), params.getG()));
 +        // }
 +        // END android-removed
          else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa)
-                  || algId.getObjectId().equals(OIWObjectIdentifiers.dsaWithSHA1))
+             || algId.getObjectId().equals(OIWObjectIdentifiers.dsaWithSHA1))
          {
-@@ -138,27 +146,29 @@
-         {
-             X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
-             ECDomainParameters  dParams = null;
--            
-+        
-             if (params.isNamedCurve())
-             {
-                 DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
-                 X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
--
-+        
-                 if (ecP == null)
-                 {
-                     ecP = SECNamedCurves.getByOID(oid);
--
-+        
-                     if (ecP == null)
+@@ -182,10 +190,12 @@
                      {
                          ecP = NISTNamedCurves.getByOID(oid);
--
+ 
 -                        if (ecP == null)
 -                        {
 -                            ecP = TeleTrusTNamedCurves.getByOID(oid);
 -                        }
-+        
 +                        // BEGIN android-removed
 +                        // if (ecP == null)
 +                        // {
@@ -2860,32 +964,75 @@
 +                        // END android-removed
                      }
                  }
--
-+        
-                 dParams = new ECDomainParameters(
-                                             ecP.getCurve(),
-                                             ecP.getG(),
-@@ -177,13 +187,13 @@
-                                             ecP.getH(),
-                                             ecP.getSeed());
+ 
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/ECNamedCurveTable.java bcprov-jdk16-146/org/bouncycastle/jce/ECNamedCurveTable.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/ECNamedCurveTable.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/ECNamedCurveTable.java	2011-09-08 21:28:49.000000000 +0000
+@@ -3,7 +3,9 @@
+ import org.bouncycastle.asn1.DERObjectIdentifier;
+ import org.bouncycastle.asn1.nist.NISTNamedCurves;
+ import org.bouncycastle.asn1.sec.SECNamedCurves;
+-import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
++// END android-removed
+ import org.bouncycastle.asn1.x9.X962NamedCurves;
+ import org.bouncycastle.asn1.x9.X9ECParameters;
+ import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+@@ -55,21 +57,23 @@
              }
--
-+        
-             DERBitString    bits = keyInfo.getPublicKeyData();
-             byte[]          data = bits.getBytes();
-             ASN1OctetString key = new DEROctetString(data);
--
-+        
-             X9ECPoint       derQ = new X9ECPoint(dParams.getCurve(), key);
--            
-+        
-             return new ECPublicKeyParameters(derQ.getPoint(), dParams);
          }
-         else
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java bcprov-jdk16-145/org/bouncycastle/jce/PKCS10CertificationRequest.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/PKCS10CertificationRequest.java	2011-09-03 18:25:17.000000000 +0000
-@@ -78,8 +78,11 @@
+ 
+-        if (ecP == null)
+-        {
+-            ecP = TeleTrusTNamedCurves.getByName(name);
+-            if (ecP == null)
+-            {
+-                try
+-                {
+-                    ecP = TeleTrusTNamedCurves.getByOID(new DERObjectIdentifier(name));
+-                }
+-                catch (IllegalArgumentException e)
+-                {
+-                    // ignore - not an oid
+-                }
+-            }
+-        }
++        // BEGIN android-removed
++        // if (ecP == null)
++        // {
++        //     ecP = TeleTrusTNamedCurves.getByName(name);
++        //     if (ecP == null)
++        //     {
++        //         try
++        //         {
++        //             ecP = TeleTrusTNamedCurves.getByOID(new DERObjectIdentifier(name));
++        //         }
++        //         catch (IllegalArgumentException e)
++        //         {
++        //             // ignore - not an oid
++        //         }
++        //     }
++        // }
++        // END android-removed
+ 
+         if (ecP == null)
+         {
+@@ -102,7 +106,9 @@
+         addEnumeration(v, X962NamedCurves.getNames());
+         addEnumeration(v, SECNamedCurves.getNames());
+         addEnumeration(v, NISTNamedCurves.getNames());
+-        addEnumeration(v, TeleTrusTNamedCurves.getNames());
++        // BEGIN android-removed
++        // addEnumeration(v, TeleTrusTNamedCurves.getNames());
++        // END android-removed
+ 
+         return v.elements();
+     }
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java bcprov-jdk16-146/org/bouncycastle/jce/PKCS10CertificationRequest.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/PKCS10CertificationRequest.java	2011-09-08 21:28:49.000000000 +0000
+@@ -80,15 +80,20 @@
  
      static
      {
@@ -2899,8 +1046,91 @@
          algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
          algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
          algorithms.put("RSAWITHMD5", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
-@@ -129,7 +132,10 @@
-         oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
+         algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+         algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+-        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+-        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
++        // BEGIN android-removed
++        // algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
++        // algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
++        // END android-removed
+         algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+         algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+         algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+@@ -96,57 +101,78 @@
+         algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+         algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+         algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+-        algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
++        // BEGIN android-removed
++        // algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
++        // END android-removed
+         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 DERObjectIdentifier("1.2.840.113549.1.1.5"));
+-        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);
++        // BEGIN android-removed
++        // 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
+         algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
+         algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
+-        algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
++        // BEGIN android-removed
++        // algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
++        // END android-removed
+         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);
++        // BEGIN android-removed
++        // algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
++        // END android-removed
+         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);
+-        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);
++        // BEGIN android-removed
++        // 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
+ 
+         //
+         // reverse mappings
+         //
+         oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
+-        oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
++        // BEGIN android-removed
++        // oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
++        // END android-removed
+         oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
+         oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
+         oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
+-        oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+-        oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
++        // BEGIN android-removed
++        // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
++        // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
++        // END android-removed
          
          oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
 -        oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
@@ -2910,8 +1140,49 @@
 +        // END android-removed
          oids.put(new DERObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
          oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
-         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
-@@ -168,19 +174,29 @@
+-        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
++        // BEGIN android-removed
++        // oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
++        // END android-removed
+         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");
++        // BEGIN android-removed
++        // oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
++        // END android-removed
+         oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
+         
+         //
+@@ -160,35 +186,53 @@
+         // The parameters field SHALL be NULL for RSA based signature algorithms.
+         //
+         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+-        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
++        // BEGIN android-removed
++        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
++        // END android-removed
+         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);
++        // BEGIN android-removed
++        // noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
++        // END android-removed
+         noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+ 
+         //
+         // RFC 4491
+         //
+-        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+-        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
++        // BEGIN android-removed
++        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
++        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
++        // END android-removed
          //
          // explicit params
          //
@@ -2922,12 +1193,16 @@
          params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
  
 -        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, new DERNull());
-+        // BEGIN android-changed
-+        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
-+        // END android-changed
-         params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
- 
+-        params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+-
 -        AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, new DERNull());
++        // BEGIN android-removed
++        // // BEGIN android-changed
++        // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
++        // // END android-changed
++        // params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
++        // END android-removed
++
 +        // BEGIN android-changed
 +        AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
 +        // END android-changed
@@ -2946,12 +1221,70 @@
          params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
      }
  
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java bcprov-jdk16-145/org/bouncycastle/jce/provider/BouncyCastleProvider.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2011-09-03 18:25:17.000000000 +0000
+@@ -594,10 +638,12 @@
+         {
+             return "SHA1";
+         }
+-        else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+-        {
+-            return "SHA224";
+-        }
++        // BEGIN android-removed
++        // else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
++        // {
++        //     return "SHA224";
++        // }
++        // END android-removed
+         else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+         {
+             return "SHA256";
+@@ -610,22 +656,24 @@
+         {
+             return "SHA512";
+         }
+-        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";
+-        }
++        // BEGIN android-removed
++        // 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
+         else
+         {
+             return digestAlgOID.getId();            
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java bcprov-jdk16-146/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2011-09-08 21:28:49.000000000 +0000
 @@ -45,7 +45,10 @@
  {
-     private static String info = "BouncyCastle Security Provider v1.45";
+     private static String info = "BouncyCastle Security Provider v1.46";
  
 -    public static String PROVIDER_NAME = "BC";
 +    // BEGIN android-changed
@@ -2961,21 +1294,24 @@
  
      /*
       * Configurable symmetric ciphers
-@@ -53,7 +56,12 @@
+@@ -53,8 +56,14 @@
      private static final String SYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jce.provider.symmetric.";
      private static final String[] SYMMETRIC_CIPHERS =
      {
--        "AES", "Camellia", "CAST5", "Grainv1", "Grain128", "IDEA", "Noekeon", "SEED"
+-        "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DESede", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
+-        "Noekeon", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
 +        // BEGIN android-removed
-+        // "AES", "Camellia", "CAST5", "Grainv1", "Grain128", "IDEA", "Noekeon", "SEED"
++        // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DESede", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
++        // "Noekeon", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
 +        // END android-removed
 +        // BEGIN android-added
-+        "AES",
++        "AES", "ARC4", "Blowfish", "DESede",
 +        // END android-added
++
      };
  
      /*
-@@ -89,26 +97,28 @@
+@@ -90,26 +99,28 @@
          loadAlgorithms(SYMMETRIC_CIPHER_PACKAGE, SYMMETRIC_CIPHERS);
          loadAlgorithms(ASYMMETRIC_CIPHER_PACKAGE, ASYMMETRIC_CIPHERS);
  
@@ -3024,7 +1360,7 @@
  
  
          //
-@@ -117,14 +127,24 @@
+@@ -118,14 +129,24 @@
          put("KeyStore.BKS", "org.bouncycastle.jce.provider.JDKKeyStore");
          put("KeyStore.BouncyCastle", "org.bouncycastle.jce.provider.JDKKeyStore$BouncyCastleStore");
          put("KeyStore.PKCS12", "org.bouncycastle.jce.provider.JDKPKCS12KeyStore$BCPKCS12KeyStore");
@@ -3057,7 +1393,7 @@
  
          put("Alg.Alias.KeyStore.UBER", "BouncyCastle");
          put("Alg.Alias.KeyStore.BOUNCYCASTLE", "BouncyCastle");
-@@ -141,44 +161,63 @@
+@@ -142,44 +163,63 @@
          //
          put("AlgorithmParameterGenerator.DH", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DH");
          put("AlgorithmParameterGenerator.DSA", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DSA");
@@ -3145,7 +1481,7 @@
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC2-CBC", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC4", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC2-CBC", "PKCS12PBE");
-@@ -192,7 +231,7 @@
+@@ -193,7 +233,7 @@
          put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.5", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.6", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWithSHAAnd3KeyTripleDES", "PKCS12PBE");
@@ -3154,7 +1490,7 @@
          put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
-@@ -202,22 +241,24 @@
+@@ -203,22 +243,24 @@
  
          put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_RSAES_OAEP, "OAEP");
          
@@ -3195,7 +1531,7 @@
          
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITAES-CBC-BC", "PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND192BITAES-CBC-BC", "PKCS12PBE");
-@@ -234,12 +275,14 @@
+@@ -235,12 +277,14 @@
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND128BITAES-CBC-BC","PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND192BITAES-CBC-BC","PKCS12PBE");
          put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND256BITAES-CBC-BC","PKCS12PBE");
@@ -3216,95 +1552,38 @@
          
          //
          // key agreement
-@@ -252,97 +295,129 @@
+@@ -252,71 +296,91 @@
+         // cipher engines
          //
          put("Cipher.DES", "org.bouncycastle.jce.provider.JCEBlockCipher$DES");
-         put("Cipher.DESEDE", "org.bouncycastle.jce.provider.JCEBlockCipher$DESede");
--        put("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JCEBlockCipher$DESedeCBC");
 -        put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.JCEBlockCipher$DESCBC");
-+        // BEGIN android-removed
-+        // put("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JCEBlockCipher$DESedeCBC");
-+        // put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.JCEBlockCipher$DESCBC");
-+        // END android-removed
-         put("Cipher.DESEDEWRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$DESEDEWrap");
--        put("Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "org.bouncycastle.jce.provider.WrapCipherSpi$DESEDEWrap");
--        put("Cipher.SKIPJACK", "org.bouncycastle.jce.provider.JCEBlockCipher$Skipjack");
-+        // BEGIN android-changed
-+        put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWRAP");
-+        // END android-changed
-+        // BEGIN android-removed
-+        // put("Cipher.SKIPJACK", "org.bouncycastle.jce.provider.JCEBlockCipher$Skipjack");
-+        // END android-removed
-         put("Cipher.BLOWFISH", "org.bouncycastle.jce.provider.JCEBlockCipher$Blowfish");
--        put("Cipher.1.3.6.1.4.1.3029.1.2", "org.bouncycastle.jce.provider.JCEBlockCipher$BlowfishCBC");
--        put("Cipher.TWOFISH", "org.bouncycastle.jce.provider.JCEBlockCipher$Twofish");
+-
 -        put("Cipher.RC2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2");
 -        put("Cipher.RC2WRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
 -        put("Cipher.1.2.840.113549.1.9.16.3.7", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
+-
+-        put("Cipher.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2CBC");
 +        // BEGIN android-removed
-+        // put("Cipher.1.3.6.1.4.1.3029.1.2", "org.bouncycastle.jce.provider.JCEBlockCipher$BlowfishCBC");
-+        // put("Cipher.TWOFISH", "org.bouncycastle.jce.provider.JCEBlockCipher$Twofish");
++        // put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.JCEBlockCipher$DESCBC");
++        //
 +        // put("Cipher.RC2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2");
 +        // put("Cipher.RC2WRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
 +        // put("Cipher.1.2.840.113549.1.9.16.3.7", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
-+        // END android-removed
-         put("Cipher.ARC4", "org.bouncycastle.jce.provider.JCEStreamCipher$RC4");
-         put("Alg.Alias.Cipher.1.2.840.113549.3.4", "ARC4");
-         put("Alg.Alias.Cipher.ARCFOUR", "ARC4");
-         put("Alg.Alias.Cipher.RC4", "ARC4");
--        put("Cipher.SALSA20", "org.bouncycastle.jce.provider.JCEStreamCipher$Salsa20");
--        put("Cipher.HC128", "org.bouncycastle.jce.provider.JCEStreamCipher$HC128");
--        put("Cipher.HC256", "org.bouncycastle.jce.provider.JCEStreamCipher$HC256");
--        put("Cipher.VMPC", "org.bouncycastle.jce.provider.JCEStreamCipher$VMPC");
--        put("Cipher.VMPC-KSA3", "org.bouncycastle.jce.provider.JCEStreamCipher$VMPCKSA3");
--        put("Cipher.RC5", "org.bouncycastle.jce.provider.JCEBlockCipher$RC5");
--        put("Cipher.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2CBC");
--        put("Alg.Alias.Cipher.RC5-32", "RC5");
--        put("Cipher.RC5-64", "org.bouncycastle.jce.provider.JCEBlockCipher$RC564");
--        put("Cipher.RC6", "org.bouncycastle.jce.provider.JCEBlockCipher$RC6");
--        put("Cipher.RIJNDAEL", "org.bouncycastle.jce.provider.JCEBlockCipher$Rijndael");
--        put("Cipher.DESEDERFC3211WRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$RFC3211DESedeWrap");
--        put("Cipher.SERPENT", "org.bouncycastle.jce.provider.JCEBlockCipher$Serpent");
--
--
--        put("Cipher.CAST6", "org.bouncycastle.jce.provider.JCEBlockCipher$CAST6");
-+        // BEGIN android-removed
-+        // put("Cipher.SALSA20", "org.bouncycastle.jce.provider.JCEStreamCipher$Salsa20");
-+        // put("Cipher.HC128", "org.bouncycastle.jce.provider.JCEStreamCipher$HC128");
-+        // put("Cipher.HC256", "org.bouncycastle.jce.provider.JCEStreamCipher$HC256");
-+        // put("Cipher.VMPC", "org.bouncycastle.jce.provider.JCEStreamCipher$VMPC");
-+        // put("Cipher.VMPC-KSA3", "org.bouncycastle.jce.provider.JCEStreamCipher$VMPCKSA3");
-+        // put("Cipher.RC5", "org.bouncycastle.jce.provider.JCEBlockCipher$RC5");
++        //
 +        // put("Cipher.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2CBC");
-+        // put("Alg.Alias.Cipher.RC5-32", "RC5");
-+        // put("Cipher.RC5-64", "org.bouncycastle.jce.provider.JCEBlockCipher$RC564");
-+        // put("Cipher.RC6", "org.bouncycastle.jce.provider.JCEBlockCipher$RC6");
-+        // put("Cipher.RIJNDAEL", "org.bouncycastle.jce.provider.JCEBlockCipher$Rijndael");
-+        // put("Cipher.DESEDERFC3211WRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$RFC3211DESedeWrap");
-+        // put("Cipher.SERPENT", "org.bouncycastle.jce.provider.JCEBlockCipher$Serpent");
 +        // END android-removed
-+
-+
-+        // BEGIN android-removed
-+        // put("Cipher.CAST6", "org.bouncycastle.jce.provider.JCEBlockCipher$CAST6");
-+        // END android-removed
+         
          put("Alg.Alias.Cipher.PBEWithSHAAnd3KeyTripleDES",  "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
          
 -        put("Cipher.GOST28147", "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147");
 -        put("Alg.Alias.Cipher.GOST", "GOST28147");
 -        put("Alg.Alias.Cipher.GOST-28147", "GOST28147");
 -        put("Cipher." + CryptoProObjectIdentifiers.gostR28147_cbc, "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147cbc");
--
--        put("Cipher.TEA", "org.bouncycastle.jce.provider.JCEBlockCipher$TEA");
--        put("Cipher.XTEA", "org.bouncycastle.jce.provider.JCEBlockCipher$XTEA");
 +        // BEGIN android-removed
 +        // put("Cipher.GOST28147", "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147");
 +        // put("Alg.Alias.Cipher.GOST", "GOST28147");
 +        // put("Alg.Alias.Cipher.GOST-28147", "GOST28147");
 +        // put("Cipher." + CryptoProObjectIdentifiers.gostR28147_cbc, "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147cbc");
-+        //
-+        // put("Cipher.TEA", "org.bouncycastle.jce.provider.JCEBlockCipher$TEA");
-+        // put("Cipher.XTEA", "org.bouncycastle.jce.provider.JCEBlockCipher$XTEA");
 +        // END android-removed
  
          put("Cipher.RSA", "org.bouncycastle.jce.provider.JCERSACipher$NoPadding");
@@ -3336,9 +1615,7 @@
 +        // put("Cipher.RSA/OAEP", "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
 +        // put("Cipher." + PKCSObjectIdentifiers.id_RSAES_OAEP, "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
 +        // put("Cipher.RSA/ISO9796-1", "org.bouncycastle.jce.provider.JCERSACipher$ISO9796d1Padding");
-+        // END android-removed
-+
-+        // BEGIN android-removed
++        //
 +        // put("Cipher.ECIES", "org.bouncycastle.jce.provider.JCEIESCipher$ECIES");
 +        // put("Cipher.BrokenECIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenECIES");
 +        // put("Cipher.IES", "org.bouncycastle.jce.provider.JCEIESCipher$IES");
@@ -3360,9 +1637,7 @@
 +        // put("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
 +        // put("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
 +        // put("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
-+        // END android-removed
-+        
-+        // BEGIN android-removed
++        //
 +        // put("Alg.Alias.Cipher.ELGAMAL/ECB/PKCS1PADDING", "ELGAMAL/PKCS1");
 +        // put("Alg.Alias.Cipher.ELGAMAL/NONE/PKCS1PADDING", "ELGAMAL/PKCS1");
 +        // put("Alg.Alias.Cipher.ELGAMAL/NONE/NOPADDING", "ELGAMAL");
@@ -3403,16 +1678,18 @@
 -        put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC2-CBC", "Cipher.PBEWITHSHAAND40BITRC2-CBC");
 -        put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC4", "Cipher.PBEWITHSHAAND128BITRC4");
 -        put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC4", "Cipher.PBEWITHSHAAND40BITRC4");
++        // BEGIN android-changed
 +        put("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
 +        put("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
 +        put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC2-CBC", "PBEWITHSHAAND128BITRC2-CBC");
 +        put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC");
 +        put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC4", "PBEWITHSHAAND128BITRC4");
 +        put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC4", "PBEWITHSHAAND40BITRC4");
++        // END android-changed
  
          put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
          put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
-@@ -350,7 +425,7 @@
+@@ -324,7 +388,7 @@
          put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
          put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
          put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
@@ -3421,86 +1698,37 @@
          put("Cipher.PBEWITHSHAAND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
          put("Cipher.PBEWITHSHAAND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
          put("Cipher.PBEWITHSHAAND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
-@@ -372,7 +447,9 @@
+@@ -346,10 +410,12 @@
          put("Cipher.PBEWITHMD5AND256BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
          
          put("Cipher.PBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndTwofish");
 -        put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish");
+-
+-        put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
+-        put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
 +        // BEGIN android-removed
 +        // put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish");
++        //
++        // put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
++        // put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
 +        // END android-removed
- 
-         put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.1", "PBEWITHSHAAND128BITRC4");
-         put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.2", "PBEWITHSHAAND40BITRC4");
-@@ -387,38 +464,49 @@
+         put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
+         put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDDES");
+         put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
+@@ -368,13 +434,15 @@
          put("KeyGenerator.DES", "org.bouncycastle.jce.provider.JCEKeyGenerator$DES");
          put("Alg.Alias.KeyGenerator." + OIWObjectIdentifiers.desCBC, "DES");
-         put("KeyGenerator.DESEDE", "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede");
--        put("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede3");
--        put("KeyGenerator.DESEDEWRAP", "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede");
--        put("KeyGenerator.SKIPJACK", "org.bouncycastle.jce.provider.JCEKeyGenerator$Skipjack");
-+        // BEGIN android-removed
-+        // put("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede3");
-+        // put("KeyGenerator.DESEDEWRAP", "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede");
-+        // put("KeyGenerator.SKIPJACK", "org.bouncycastle.jce.provider.JCEKeyGenerator$Skipjack");
-+        // END android-removed
-         put("KeyGenerator.BLOWFISH", "org.bouncycastle.jce.provider.JCEKeyGenerator$Blowfish");
-         put("Alg.Alias.KeyGenerator.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
--        put("KeyGenerator.TWOFISH", "org.bouncycastle.jce.provider.JCEKeyGenerator$Twofish");
+ 
 -        put("KeyGenerator.RC2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
 -        put("KeyGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
-+        // BEGIN android-removed
-+        // put("KeyGenerator.TWOFISH", "org.bouncycastle.jce.provider.JCEKeyGenerator$Twofish");
-+        // put("KeyGenerator.RC2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
-+        // put("KeyGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
-+        // END android-removed
-         put("KeyGenerator.RC4", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC4");
-         put("Alg.Alias.KeyGenerator.ARC4", "RC4");
--        put("Alg.Alias.KeyGenerator.1.2.840.113549.3.4", "RC4");
--        put("KeyGenerator.RC5", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC5");
--        put("Alg.Alias.KeyGenerator.RC5-32", "RC5");
--        put("KeyGenerator.RC5-64", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC564");
--        put("KeyGenerator.RC6", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC6");
--        put("KeyGenerator.RIJNDAEL", "org.bouncycastle.jce.provider.JCEKeyGenerator$Rijndael");
--
--        put("KeyGenerator.SERPENT", "org.bouncycastle.jce.provider.JCEKeyGenerator$Serpent");
--        put("KeyGenerator.SALSA20", "org.bouncycastle.jce.provider.JCEKeyGenerator$Salsa20");
--        put("KeyGenerator.HC128", "org.bouncycastle.jce.provider.JCEKeyGenerator$HC128");
--        put("KeyGenerator.HC256", "org.bouncycastle.jce.provider.JCEKeyGenerator$HC256");
--        put("KeyGenerator.VMPC", "org.bouncycastle.jce.provider.JCEKeyGenerator$VMPC");
--        put("KeyGenerator.VMPC-KSA3", "org.bouncycastle.jce.provider.JCEKeyGenerator$VMPCKSA3");
--
--        put("KeyGenerator.CAST6", "org.bouncycastle.jce.provider.JCEKeyGenerator$CAST6");
--        put("KeyGenerator.TEA", "org.bouncycastle.jce.provider.JCEKeyGenerator$TEA");
--        put("KeyGenerator.XTEA", "org.bouncycastle.jce.provider.JCEKeyGenerator$XTEA");
 -
 -        put("KeyGenerator.GOST28147", "org.bouncycastle.jce.provider.JCEKeyGenerator$GOST28147");
 -        put("Alg.Alias.KeyGenerator.GOST", "GOST28147");
 -        put("Alg.Alias.KeyGenerator.GOST-28147", "GOST28147");
 -        put("Alg.Alias.KeyGenerator." + CryptoProObjectIdentifiers.gostR28147_cbc, "GOST28147");
-+        // BEGIN android-added
-+        put("Alg.Alias.KeyGenerator.ARCFOUR", "RC4");
-+        // END android-added
 +        // BEGIN android-removed
-+        // put("Alg.Alias.KeyGenerator.1.2.840.113549.3.4", "RC4");
-+        // put("KeyGenerator.RC5", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC5");
-+        // put("Alg.Alias.KeyGenerator.RC5-32", "RC5");
-+        // put("KeyGenerator.RC5-64", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC564");
-+        // put("KeyGenerator.RC6", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC6");
-+        // put("KeyGenerator.RIJNDAEL", "org.bouncycastle.jce.provider.JCEKeyGenerator$Rijndael");
-+        //
-+        // put("KeyGenerator.SERPENT", "org.bouncycastle.jce.provider.JCEKeyGenerator$Serpent");
-+        // put("KeyGenerator.SALSA20", "org.bouncycastle.jce.provider.JCEKeyGenerator$Salsa20");
-+        // put("KeyGenerator.HC128", "org.bouncycastle.jce.provider.JCEKeyGenerator$HC128");
-+        // put("KeyGenerator.HC256", "org.bouncycastle.jce.provider.JCEKeyGenerator$HC256");
-+        // put("KeyGenerator.VMPC", "org.bouncycastle.jce.provider.JCEKeyGenerator$VMPC");
-+        // put("KeyGenerator.VMPC-KSA3", "org.bouncycastle.jce.provider.JCEKeyGenerator$VMPCKSA3");
-+        // END android-removed
-+
-+        // BEGIN android-removed
-+        // put("KeyGenerator.CAST6", "org.bouncycastle.jce.provider.JCEKeyGenerator$CAST6");
-+        // put("KeyGenerator.TEA", "org.bouncycastle.jce.provider.JCEKeyGenerator$TEA");
-+        // put("KeyGenerator.XTEA", "org.bouncycastle.jce.provider.JCEKeyGenerator$XTEA");
++        // put("KeyGenerator.RC2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
++        // put("KeyGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
 +        //
 +        // put("KeyGenerator.GOST28147", "org.bouncycastle.jce.provider.JCEKeyGenerator$GOST28147");
 +        // put("Alg.Alias.KeyGenerator.GOST", "GOST28147");
@@ -3510,7 +1738,7 @@
  
          //
          // key pair generators.
-@@ -426,14 +514,18 @@
+@@ -382,14 +450,18 @@
          put("KeyPairGenerator.RSA", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$RSA");
          put("KeyPairGenerator.DH", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$DH");
          put("KeyPairGenerator.DSA", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$DSA");
@@ -3533,7 +1761,7 @@
  
          //
          // key factories
-@@ -441,20 +533,24 @@
+@@ -397,20 +469,24 @@
          put("KeyFactory.RSA", "org.bouncycastle.jce.provider.JDKKeyFactory$RSA");
          put("KeyFactory.DH", "org.bouncycastle.jce.provider.JDKKeyFactory$DH");
          put("KeyFactory.DSA", "org.bouncycastle.jce.provider.JDKKeyFactory$DSA");
@@ -3566,51 +1794,50 @@
  
          //
          // Algorithm parameters
-@@ -462,16 +558,22 @@
+@@ -418,24 +494,34 @@
          put("AlgorithmParameters.DES", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
          put("Alg.Alias.AlgorithmParameters." + OIWObjectIdentifiers.desCBC, "DES");
          put("AlgorithmParameters.DESEDE", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
 -        put("AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
 -        put("AlgorithmParameters.RC2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
 -        put("AlgorithmParameters.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
--        put("AlgorithmParameters.RC5", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
--        put("AlgorithmParameters.RC6", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
 +        // BEGIN android-changed
 +        put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
 +        // END android-changed
 +        // BEGIN android-removed
 +        // put("AlgorithmParameters.RC2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
 +        // put("AlgorithmParameters.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
-+        // put("AlgorithmParameters.RC5", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-+        // put("AlgorithmParameters.RC6", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
 +        // END android-removed
-         put("AlgorithmParameters.BLOWFISH", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-         put("Alg.Alias.AlgorithmParameters.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
--        put("AlgorithmParameters.TWOFISH", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
--        put("AlgorithmParameters.SKIPJACK", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
--        put("AlgorithmParameters.RIJNDAEL", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-+        // BEGIN android-removed
-+        // put("AlgorithmParameters.TWOFISH", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-+        // put("AlgorithmParameters.SKIPJACK", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-+        // put("AlgorithmParameters.RIJNDAEL", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-+        // END android-removed
- 
          
          //
-@@ -479,8 +581,10 @@
+         // secret key factories.
          //
          put("SecretKeyFactory.DES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$DES");
-         put("SecretKeyFactory.DESEDE", "org.bouncycastle.jce.provider.JCESecretKeyFactory$DESede");
 -        put("SecretKeyFactory.PBEWITHMD2ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndDES");
--        put("SecretKeyFactory.PBEWITHMD2ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndRC2");
+-
+-        put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
+-        put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
 +        // BEGIN android-removed
 +        // put("SecretKeyFactory.PBEWITHMD2ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndDES");
++        // END android-removed
++
++        // BEGIN android-removed
++        // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
++        // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
++        // END android-removed
+         put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
+         put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDDES");
+         put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
+         put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
+ 
+-        put("SecretKeyFactory.PBEWITHMD2ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndRC2");
++        // BEGIN android-removed
 +        // put("SecretKeyFactory.PBEWITHMD2ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndRC2");
 +        // END android-removed
          put("SecretKeyFactory.PBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5AndDES");
          put("SecretKeyFactory.PBEWITHMD5ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5AndRC2");
          put("SecretKeyFactory.PBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA1AndDES");
-@@ -492,31 +596,41 @@
+@@ -447,31 +533,41 @@
          put("SecretKeyFactory.PBEWITHSHAAND128BITRC2-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd128BitRC2");
          put("SecretKeyFactory.PBEWITHSHAAND40BITRC2-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd40BitRC2");
          put("SecretKeyFactory.PBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAndTwofish");
@@ -3667,7 +1894,7 @@
          put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
          put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
          put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
-@@ -553,6 +667,10 @@
+@@ -508,6 +604,10 @@
          put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
          put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
          put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
@@ -3678,7 +1905,7 @@
  
          addMacAlgorithms();
  
-@@ -561,16 +679,23 @@
+@@ -516,16 +616,23 @@
          addSignatureAlgorithms();
  
      // Certification Path API
@@ -3709,7 +1936,7 @@
      }
  
      private void loadAlgorithms(String packageName, String[] names)
-@@ -631,68 +756,72 @@
+@@ -586,42 +693,46 @@
      //
      private void addMacAlgorithms()
      {
@@ -3718,49 +1945,23 @@
 -        put("Mac.DESMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$DESCFB8");
 -        put("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
 -
--        put("Mac.DESEDEMAC", "org.bouncycastle.jce.provider.JCEMac$DESede");
--        put("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
--        put("Mac.DESEDEMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$DESedeCFB8");
--        put("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
--        
 -        put("Mac.DESWITHISO9797", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
 -        put("Alg.Alias.Mac.DESISO9797MAC", "DESWITHISO9797");
--        
--        put("Mac.DESEDEMAC64", "org.bouncycastle.jce.provider.JCEMac$DESede64");
--        put("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
--
--        put("Mac.DESEDEMAC64WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.JCEMac$DESede64with7816d4");
--        put("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
--        put("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
--        put("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
 -
 -        put("Mac.ISO9797ALG3MAC", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
 -        put("Alg.Alias.Mac.ISO9797ALG3", "ISO9797ALG3MAC");
 -        put("Mac.ISO9797ALG3WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3with7816d4");
 -        put("Alg.Alias.Mac.ISO9797ALG3MACWITHISO7816-4PADDING", "ISO9797ALG3WITHISO7816-4PADDING");
 -
--        put("Mac.SKIPJACKMAC", "org.bouncycastle.jce.provider.JCEMac$Skipjack");
--        put("Alg.Alias.Mac.SKIPJACK", "SKIPJACKMAC");
--        put("Mac.SKIPJACKMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$SkipjackCFB8");
--        put("Alg.Alias.Mac.SKIPJACK/CFB8", "SKIPJACKMAC/CFB8");
--
 -        put("Mac.RC2MAC", "org.bouncycastle.jce.provider.JCEMac$RC2");
 -        put("Alg.Alias.Mac.RC2", "RC2MAC");
 -        put("Mac.RC2MAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$RC2CFB8");
 -        put("Alg.Alias.Mac.RC2/CFB8", "RC2MAC/CFB8");
 -
--        put("Mac.RC5MAC", "org.bouncycastle.jce.provider.JCEMac$RC5");
--        put("Alg.Alias.Mac.RC5", "RC5MAC");
--        put("Mac.RC5MAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$RC5CFB8");
--        put("Alg.Alias.Mac.RC5/CFB8", "RC5MAC/CFB8");
 -
 -        put("Mac.GOST28147MAC", "org.bouncycastle.jce.provider.JCEMac$GOST28147");
 -        put("Alg.Alias.Mac.GOST28147", "GOST28147MAC");
 -
--        put("Mac.VMPCMAC", "org.bouncycastle.jce.provider.JCEMac$VMPC");
--        put("Alg.Alias.Mac.VMPC", "VMPCMAC");
--        put("Alg.Alias.Mac.VMPC-MAC", "VMPCMAC");
--
 -        put("Mac.OLDHMACSHA384", "org.bouncycastle.jce.provider.JCEMac$OldSHA384");
 -
 -        put("Mac.OLDHMACSHA512", "org.bouncycastle.jce.provider.JCEMac$OldSHA512");
@@ -3773,49 +1974,23 @@
 +        // put("Mac.DESMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$DESCFB8");
 +        // put("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
 +        //
-+        // put("Mac.DESEDEMAC", "org.bouncycastle.jce.provider.JCEMac$DESede");
-+        // put("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
-+        // put("Mac.DESEDEMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$DESedeCFB8");
-+        // put("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
-+        //
 +        // put("Mac.DESWITHISO9797", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
 +        // put("Alg.Alias.Mac.DESISO9797MAC", "DESWITHISO9797");
 +        //
-+        // put("Mac.DESEDEMAC64", "org.bouncycastle.jce.provider.JCEMac$DESede64");
-+        // put("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
-+        //
-+        // put("Mac.DESEDEMAC64WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.JCEMac$DESede64with7816d4");
-+        // put("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-+        // put("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-+        // put("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-+        //
 +        // put("Mac.ISO9797ALG3MAC", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
 +        // put("Alg.Alias.Mac.ISO9797ALG3", "ISO9797ALG3MAC");
 +        // put("Mac.ISO9797ALG3WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3with7816d4");
 +        // put("Alg.Alias.Mac.ISO9797ALG3MACWITHISO7816-4PADDING", "ISO9797ALG3WITHISO7816-4PADDING");
 +        //
-+        // put("Mac.SKIPJACKMAC", "org.bouncycastle.jce.provider.JCEMac$Skipjack");
-+        // put("Alg.Alias.Mac.SKIPJACK", "SKIPJACKMAC");
-+        // put("Mac.SKIPJACKMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$SkipjackCFB8");
-+        // put("Alg.Alias.Mac.SKIPJACK/CFB8", "SKIPJACKMAC/CFB8");
-+        //
 +        // put("Mac.RC2MAC", "org.bouncycastle.jce.provider.JCEMac$RC2");
 +        // put("Alg.Alias.Mac.RC2", "RC2MAC");
 +        // put("Mac.RC2MAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$RC2CFB8");
 +        // put("Alg.Alias.Mac.RC2/CFB8", "RC2MAC/CFB8");
 +        //
-+        // put("Mac.RC5MAC", "org.bouncycastle.jce.provider.JCEMac$RC5");
-+        // put("Alg.Alias.Mac.RC5", "RC5MAC");
-+        // put("Mac.RC5MAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$RC5CFB8");
-+        // put("Alg.Alias.Mac.RC5/CFB8", "RC5MAC/CFB8");
 +        //
 +        // put("Mac.GOST28147MAC", "org.bouncycastle.jce.provider.JCEMac$GOST28147");
 +        // put("Alg.Alias.Mac.GOST28147", "GOST28147MAC");
 +        //
-+        // put("Mac.VMPCMAC", "org.bouncycastle.jce.provider.JCEMac$VMPC");
-+        // put("Alg.Alias.Mac.VMPC", "VMPCMAC");
-+        // put("Alg.Alias.Mac.VMPC-MAC", "VMPCMAC");
-+        //
 +        // put("Mac.OLDHMACSHA384", "org.bouncycastle.jce.provider.JCEMac$OldSHA384");
 +        //
 +        // put("Mac.OLDHMACSHA512", "org.bouncycastle.jce.provider.JCEMac$OldSHA512");
@@ -3838,7 +2013,7 @@
          addHMACAlgorithm("SHA256", "org.bouncycastle.jce.provider.JCEMac$SHA256", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA256");
          addHMACAlias("SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
          addHMACAlgorithm("SHA384", "org.bouncycastle.jce.provider.JCEMac$SHA384", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA384");
-@@ -700,16 +829,20 @@
+@@ -629,16 +740,20 @@
          addHMACAlgorithm("SHA512", "org.bouncycastle.jce.provider.JCEMac$SHA512", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA512");
          addHMACAlias("SHA512", PKCSObjectIdentifiers.id_hmacWithSHA512);
  
@@ -3866,7 +2041,7 @@
          put("Alg.Alias.Mac.1.3.14.3.2.26", "PBEWITHHMACSHA");
      }
  
-@@ -747,9 +880,11 @@
+@@ -676,9 +791,11 @@
          put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
          put("Alg.Alias.MessageDigest.SHA", "SHA-1");
          put("Alg.Alias.MessageDigest." + OIWObjectIdentifiers.idSHA1, "SHA-1");
@@ -3881,7 +2056,7 @@
          put("MessageDigest.SHA-256", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA256");
          put("Alg.Alias.MessageDigest.SHA256", "SHA-256");
          put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha256, "SHA-256");
-@@ -760,27 +895,31 @@
+@@ -689,27 +806,31 @@
          put("Alg.Alias.MessageDigest.SHA512", "SHA-512");
          put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512, "SHA-512");
          
@@ -3932,7 +2107,7 @@
      }
      
      //
-@@ -788,55 +927,70 @@
+@@ -717,55 +838,70 @@
      //
      private void addSignatureAlgorithms()
      {
@@ -4041,7 +2216,7 @@
  
          put("Alg.Alias.Signature.SHA256withRSAEncryption", "SHA256WithRSAEncryption");
          put("Alg.Alias.Signature.SHA384withRSAEncryption", "SHA384WithRSAEncryption");
-@@ -850,24 +1004,30 @@
+@@ -779,24 +915,30 @@
          put("Alg.Alias.Signature.SHA384WITHRSAENCRYPTION", "SHA384WithRSAEncryption");
          put("Alg.Alias.Signature.SHA512WITHRSAENCRYPTION", "SHA512WithRSAEncryption");
  
@@ -4084,7 +2259,7 @@
          put("Alg.Alias.Signature.SHA256WithRSA", "SHA256WithRSAEncryption");
          put("Alg.Alias.Signature.SHA256withRSA", "SHA256WithRSAEncryption");
          put("Alg.Alias.Signature.SHA384WithRSA", "SHA384WithRSAEncryption");
-@@ -877,92 +1037,110 @@
+@@ -806,92 +948,110 @@
          put("Alg.Alias.Signature.SHA1/RSA", "SHA1WithRSAEncryption");
          put("Alg.Alias.Signature.SHA-1/RSA", "SHA1WithRSAEncryption");
          put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1WithRSAEncryption");
@@ -4177,6 +2352,26 @@
 -        put("Alg.Alias.Signature.GOST3411WITHGOST3410", "GOST3410");
 -        put("Alg.Alias.Signature.GOST3411WithGOST3410", "GOST3410");
 -        put("Alg.Alias.Signature." + CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3410");
+-    }
+-
+-    private void addSignatureAlgorithm(
+-        String digest,
+-        String algorithm,
+-        String className,
+-        DERObjectIdentifier oid)
+-    {
+-        String mainName = digest + "WITH" + algorithm;
+-        String jdk11Variation1 = digest + "with" + algorithm;
+-        String jdk11Variation2 = digest + "With" + algorithm;
+-        String alias = digest + "/" + algorithm;
+-
+-        put("Signature." + mainName, className);
+-        put("Alg.Alias.Signature." + jdk11Variation1, mainName);
+-        put("Alg.Alias.Signature." + jdk11Variation2, mainName);
+-        put("Alg.Alias.Signature." + alias, mainName);
+-        put("Alg.Alias.Signature." + oid, mainName);
+-        put("Alg.Alias.Signature.OID." + oid, mainName);
+-    }
 +        // BEGIN android-removed
 +        // put("Alg.Alias.Signature.RIPEMD160WITHRSA", "RIPEMD160WithRSAEncryption");
 +        // put("Alg.Alias.Signature.RMD160WITHRSA", "RIPEMD160WithRSAEncryption");
@@ -4223,26 +2418,8 @@
 +        // put("Alg.Alias.Signature.GOST3411WithGOST3410", "GOST3410");
 +        // put("Alg.Alias.Signature." + CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3410");
 +        // END android-removed
-     }
- 
--    private void addSignatureAlgorithm(
--        String digest,
--        String algorithm,
--        String className,
--        DERObjectIdentifier oid)
--    {
--        String mainName = digest + "WITH" + algorithm;
--        String jdk11Variation1 = digest + "with" + algorithm;
--        String jdk11Variation2 = digest + "With" + algorithm;
--        String alias = digest + "/" + algorithm;
--
--        put("Signature." + mainName, className);
--        put("Alg.Alias.Signature." + jdk11Variation1, mainName);
--        put("Alg.Alias.Signature." + jdk11Variation2, mainName);
--        put("Alg.Alias.Signature." + alias, mainName);
--        put("Alg.Alias.Signature." + oid, mainName);
--        put("Alg.Alias.Signature.OID." + oid, mainName);
--    }
++    }
++
 +    // BEGIN android-removed
 +    // private void addSignatureAlgorithm(
 +    //     String digest,
@@ -4266,9 +2443,9 @@
  
      public void setParameter(String parameterName, Object parameter)
      {
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java bcprov-jdk16-145/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java bcprov-jdk16-146/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2011-09-08 21:28:49.000000000 +0000
 @@ -24,6 +24,7 @@
  import java.security.spec.DSAPublicKeySpec;
  import java.text.ParseException;
@@ -4277,18 +2454,7 @@
  import java.util.Collection;
  import java.util.Date;
  import java.util.Enumeration;
-@@ -35,6 +36,10 @@
- 
- import javax.security.auth.x500.X500Principal;
- 
-+// BEGIN android-added
-+import org.apache.harmony.xnet.provider.jsse.IndexedPKIXParameters;
-+
-+// END android-added
- import org.bouncycastle.asn1.ASN1InputStream;
- import org.bouncycastle.asn1.ASN1Object;
- import org.bouncycastle.asn1.ASN1OctetString;
-@@ -59,13 +64,17 @@
+@@ -59,13 +60,17 @@
  import org.bouncycastle.asn1.x509.PolicyInformation;
  import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
  import org.bouncycastle.asn1.x509.X509Extensions;
@@ -4308,119 +2474,7 @@
  import org.bouncycastle.x509.X509AttributeCertificate;
  import org.bouncycastle.x509.X509CRLStoreSelector;
  import org.bouncycastle.x509.X509CertStoreSelector;
-@@ -110,38 +119,38 @@
-         "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.
--     *
--     * @exception 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);
--    }
-+    // BEGIN android-removed
-+    // /**
-+    //  * 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.
-+    //  *
-+    //  * @exception 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);
-+    // }
-+    // END android-removed
-     
-+    // BEGIN android-changed
-     /**
-      * 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.
-+     * issuer of the given X509 certificate.
-      *
-      * @param cert the X509 certificate
--     * @param trustAnchors a Set of TrustAnchor's
--     * @param sigProvider the provider to use for signature verification
-+     * @param params used to find the trust anchors and signature provider
-      *
-      * @return the <code>TrustAnchor</code> object if found or
-      * <code>null</code> if not.
-@@ -152,10 +161,21 @@
-      */
-     protected static TrustAnchor findTrustAnchor(
-         X509Certificate cert,
--        Set             trustAnchors,
--        String          sigProvider) 
-+        PKIXParameters  params)
-             throws AnnotatedException
-+    // END android-changed
-     {
-+        // BEGIN android-changed
-+        // If we have a trust anchor index, use it.
-+        if (params instanceof IndexedPKIXParameters) {
-+            try {
-+                IndexedPKIXParameters indexed = (IndexedPKIXParameters) params;
-+                return indexed.findTrustAnchor(cert);
-+            } catch (CertPathValidatorException e) {
-+                throw new AnnotatedException(e.getMessage(), e);
-+            }
-+        }
-+        // END android-changed
-         TrustAnchor trust = null;
-         PublicKey trustPublicKey = null;
-         Exception invalidKeyEx = null;
-@@ -172,7 +192,9 @@
-             throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
-         }
- 
--        Iterator iter = trustAnchors.iterator();
-+        // BEGIN android-changed
-+        Iterator iter = params.getTrustAnchors().iterator();
-+        // END android-changed
-         while (iter.hasNext() && trust == null)
-         {
-             trust = (TrustAnchor) iter.next();
-@@ -216,7 +238,9 @@
-             {
-                 try
-                 {
--                    verifyX509Certificate(cert, trustPublicKey, sigProvider);
-+                    // BEGIN android-changed
-+                    verifyX509Certificate(cert, trustPublicKey, params.getSigProvider());
-+                    // END android-changed
-                 }
-                 catch (Exception ex)
-                 {
-@@ -248,7 +272,9 @@
+@@ -250,7 +255,9 @@
              {
                  // look for URI
                  List list = (List) it.next();
@@ -4431,7 +2485,7 @@
                  {
                      // found
                      String temp = (String) list.get(1);
-@@ -721,38 +747,40 @@
+@@ -660,38 +667,40 @@
          {
              try
              {
@@ -4459,13 +2513,13 @@
 -                    X509LDAPCertStoreParameters params = new X509LDAPCertStoreParameters.Builder(
 -                        url, base).build();
 -                    pkixParams.addAdditionalStore(X509Store.getInstance(
--                        "CERTIFICATE/LDAP", params, "BC"));
+-                        "CERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
 -                    pkixParams.addAdditionalStore(X509Store.getInstance(
--                        "CRL/LDAP", params, "BC"));
+-                        "CRL/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
 -                    pkixParams.addAdditionalStore(X509Store.getInstance(
--                        "ATTRIBUTECERTIFICATE/LDAP", params, "BC"));
+-                        "ATTRIBUTECERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
 -                    pkixParams.addAdditionalStore(X509Store.getInstance(
--                        "CERTIFICATEPAIR/LDAP", params, "BC"));
+-                        "CERTIFICATEPAIR/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
 -                }
 +                // BEGIN android-removed
 +                // if (location.startsWith("ldap://"))
@@ -4492,19 +2546,19 @@
 +                //     X509LDAPCertStoreParameters params = new X509LDAPCertStoreParameters.Builder(
 +                //         url, base).build();
 +                //     pkixParams.addAdditionalStore(X509Store.getInstance(
-+                //         "CERTIFICATE/LDAP", params, "BC"));
++                //         "CERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
 +                //     pkixParams.addAdditionalStore(X509Store.getInstance(
-+                //         "CRL/LDAP", params, "BC"));
++                //         "CRL/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
 +                //     pkixParams.addAdditionalStore(X509Store.getInstance(
-+                //         "ATTRIBUTECERTIFICATE/LDAP", params, "BC"));
++                //         "ATTRIBUTECERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
 +                //     pkixParams.addAdditionalStore(X509Store.getInstance(
-+                //         "CERTIFICATEPAIR/LDAP", params, "BC"));
++                //         "CERTIFICATEPAIR/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
 +                // }
 +                // END android-removed
              }
              catch (Exception e)
              {
-@@ -819,35 +847,37 @@
+@@ -758,35 +767,37 @@
          return certs;
      }
  
@@ -4571,19 +2625,24 @@
  
      protected static void addAdditionalStoresFromCRLDistributionPoint(
          CRLDistPoint crldp, ExtendedPKIXParameters pkixParams)
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEBlockCipher.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEBlockCipher.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEBlockCipher.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEBlockCipher.java	2011-09-03 18:25:17.000000000 +0000
-@@ -7,22 +7,31 @@
- import org.bouncycastle.crypto.InvalidCipherTextException;
- import org.bouncycastle.crypto.engines.AESFastEngine;
- import org.bouncycastle.crypto.engines.BlowfishEngine;
--import org.bouncycastle.crypto.engines.CAST5Engine;
--import org.bouncycastle.crypto.engines.CAST6Engine;
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEBlockCipher.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEBlockCipher.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEBlockCipher.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEBlockCipher.java	2011-09-08 21:28:49.000000000 +0000
+@@ -17,8 +17,10 @@
+ import javax.crypto.ShortBufferException;
+ import javax.crypto.spec.IvParameterSpec;
+ import javax.crypto.spec.PBEParameterSpec;
+-import javax.crypto.spec.RC2ParameterSpec;
+-import javax.crypto.spec.RC5ParameterSpec;
 +// BEGIN android-removed
-+// import org.bouncycastle.crypto.engines.CAST5Engine;
-+// import org.bouncycastle.crypto.engines.CAST6Engine;
++// import javax.crypto.spec.RC2ParameterSpec;
++// import javax.crypto.spec.RC5ParameterSpec;
 +// END android-removed
+ 
+ import org.bouncycastle.crypto.BlockCipher;
+ import org.bouncycastle.crypto.BufferedBlockCipher;
+@@ -28,7 +30,9 @@
+ import org.bouncycastle.crypto.engines.AESFastEngine;
  import org.bouncycastle.crypto.engines.DESEngine;
  import org.bouncycastle.crypto.engines.DESedeEngine;
 -import org.bouncycastle.crypto.engines.GOST28147Engine;
@@ -4591,34 +2650,16 @@
 +// import org.bouncycastle.crypto.engines.GOST28147Engine;
 +// END android-removed
  import org.bouncycastle.crypto.engines.RC2Engine;
--import org.bouncycastle.crypto.engines.RC532Engine;
--import org.bouncycastle.crypto.engines.RC564Engine;
--import org.bouncycastle.crypto.engines.RC6Engine;
--import org.bouncycastle.crypto.engines.RijndaelEngine;
--import org.bouncycastle.crypto.engines.SEEDEngine;
--import org.bouncycastle.crypto.engines.SerpentEngine;
--import org.bouncycastle.crypto.engines.SkipjackEngine;
--import org.bouncycastle.crypto.engines.TEAEngine;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.engines.RC532Engine;
-+// import org.bouncycastle.crypto.engines.RC564Engine;
-+// END android-removed
-+// import org.bouncycastle.crypto.engines.RC6Engine;
-+// import org.bouncycastle.crypto.engines.RijndaelEngine;
-+// import org.bouncycastle.crypto.engines.SEEDEngine;
-+// import org.bouncycastle.crypto.engines.SerpentEngine;
-+// import org.bouncycastle.crypto.engines.SkipjackEngine;
-+// import org.bouncycastle.crypto.engines.TEAEngine;
-+// END android-removed
  import org.bouncycastle.crypto.engines.TwofishEngine;
--import org.bouncycastle.crypto.engines.XTEAEngine;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.engines.XTEAEngine;
-+// END android-removed
  import org.bouncycastle.crypto.modes.AEADBlockCipher;
- import org.bouncycastle.crypto.modes.CBCBlockCipher;
+@@ -36,12 +40,16 @@
  import org.bouncycastle.crypto.modes.CCMBlockCipher;
-@@ -32,8 +41,10 @@
+ import org.bouncycastle.crypto.modes.CFBBlockCipher;
+ import org.bouncycastle.crypto.modes.CTSBlockCipher;
+-import org.bouncycastle.crypto.modes.EAXBlockCipher;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.modes.EAXBlockCipher;
++// END android-removed
  import org.bouncycastle.crypto.modes.GCMBlockCipher;
  import org.bouncycastle.crypto.modes.GOFBBlockCipher;
  import org.bouncycastle.crypto.modes.OFBBlockCipher;
@@ -4631,7 +2672,7 @@
  import org.bouncycastle.crypto.modes.SICBlockCipher;
  import org.bouncycastle.crypto.paddings.BlockCipherPadding;
  import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
-@@ -45,10 +56,12 @@
+@@ -53,10 +61,12 @@
  import org.bouncycastle.crypto.params.KeyParameter;
  import org.bouncycastle.crypto.params.ParametersWithIV;
  import org.bouncycastle.crypto.params.ParametersWithRandom;
@@ -4647,21 +2688,8 @@
 +// END android-removed
  import org.bouncycastle.util.Strings;
  
- import javax.crypto.BadPaddingException;
-@@ -59,8 +72,10 @@
- import javax.crypto.ShortBufferException;
- import javax.crypto.spec.IvParameterSpec;
- import javax.crypto.spec.PBEParameterSpec;
--import javax.crypto.spec.RC2ParameterSpec;
--import javax.crypto.spec.RC5ParameterSpec;
-+// BEGIN android-removed
-+// import javax.crypto.spec.RC2ParameterSpec;
-+// import javax.crypto.spec.RC5ParameterSpec;
-+// END android-removed
- import java.security.AlgorithmParameters;
- import java.security.InvalidAlgorithmParameterException;
- import java.security.InvalidKeyException;
-@@ -78,11 +93,15 @@
+ public class JCEBlockCipher extends WrapCipherSpi
+@@ -67,11 +77,15 @@
      //
      private Class[]                 availableSpecs =
                                      {
@@ -4680,7 +2708,7 @@
                                      };
   
      private BlockCipher             baseEngine;
-@@ -237,20 +256,22 @@
+@@ -226,20 +240,22 @@
                          new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
              }
          }
@@ -4717,7 +2745,26 @@
          else if (modeName.startsWith("SIC"))
          {
              ivLength = baseEngine.getBlockSize();
-@@ -376,13 +397,15 @@
+@@ -272,11 +288,13 @@
+             ivLength = baseEngine.getBlockSize();
+             cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
+         }
+-        else if (modeName.startsWith("EAX"))
+-        {
+-            ivLength = baseEngine.getBlockSize();
+-            cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
+-        }
++        // BEGIN android-removed
++        // else if (modeName.startsWith("EAX"))
++        // {
++        //     ivLength = baseEngine.getBlockSize();
++        //     cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
++        // }
++        // END android-removed
+         else if (modeName.startsWith("GCM"))
+         {
+             ivLength = baseEngine.getBlockSize();
+@@ -365,13 +383,15 @@
              throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
          }
          
@@ -4740,7 +2787,7 @@
  
          //
          // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
-@@ -448,63 +471,65 @@
+@@ -437,63 +457,65 @@
                  param = new KeyParameter(key.getEncoded());
              }
          }
@@ -4863,7 +2910,7 @@
          else
          {
              throw new InvalidAlgorithmParameterException("unknown parameter type.");
-@@ -708,10 +733,21 @@
+@@ -697,10 +719,21 @@
          int     inputLen,
          byte[]  output,
          int     outputOffset) 
@@ -4886,7 +2933,7 @@
          if (inputLen != 0)
          {
                  len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
-@@ -753,17 +789,19 @@
+@@ -742,62 +775,64 @@
          }
      }
  
@@ -4901,37 +2948,6 @@
 -            super(new CBCBlockCipher(new DESEngine()), 64);
 -        }
 -    }
-+    // BEGIN android-removed
-+    // /**
-+    //  * DESCBC
-+    //  */
-+    // static public class DESCBC
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public DESCBC()
-+    //     {
-+    //         super(new CBCBlockCipher(new DESEngine()), 64);
-+    //     }
-+    // }
-+    // END android-removed
- 
-     /**
-      * DESede
-@@ -777,52 +815,54 @@
-         }
-     }
- 
--    /**
--     * DESedeCBC
--     */
--    static public class DESedeCBC
--        extends JCEBlockCipher
--    {
--        public DESedeCBC()
--        {
--            super(new CBCBlockCipher(new DESedeEngine()), 64);
--        }
--    }
 -
 -    /**
 -     *  GOST28147
@@ -4953,97 +2969,6 @@
 -            super(new CBCBlockCipher(new GOST28147Engine()), 64);
 -        }
 -    }
-+    // BEGIN android-removed
-+    // /**
-+    //  * DESedeCBC
-+    //  */
-+    // static public class DESedeCBC
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public DESedeCBC()
-+    //     {
-+    //         super(new CBCBlockCipher(new DESedeEngine()), 64);
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  *  GOST28147
-+    //  */
-+    // static public class GOST28147
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public GOST28147()
-+    //     {
-+    //         super(new GOST28147Engine());
-+    //     }
-+    // }
-+    //    
-+    // static public class GOST28147cbc
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public GOST28147cbc()
-+    //     {
-+    //         super(new CBCBlockCipher(new GOST28147Engine()), 64);
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * SKIPJACK
-+    //  */
-+    // static public class Skipjack
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public Skipjack()
-+    //     {
-+    //         super(new SkipjackEngine());
-+    //     }
-+    // }
-+    // END android-removed
-     
-     /**
--     * SKIPJACK
--     */
--    static public class Skipjack
--        extends JCEBlockCipher
--    {
--        public Skipjack()
--        {
--            super(new SkipjackEngine());
--        }
--    }
--
--    /**
-      * Blowfish
-      */
-     static public class Blowfish
-@@ -833,236 +873,238 @@
-             super(new BlowfishEngine());
-         }
-     }
--
--    /**
--     * Blowfish CBC
--     */
--    static public class BlowfishCBC
--        extends JCEBlockCipher
--    {
--        public BlowfishCBC()
--        {
--            super(new CBCBlockCipher(new BlowfishEngine()), 64);
--        }
--    }
--
--    /**
--     * Twofish
--     */
--    static public class Twofish
--        extends JCEBlockCipher
--    {
--        public Twofish()
--        {
--            super(new TwofishEngine());
--        }
--    }
 -
 -    /**
 -     * RC2
@@ -5068,210 +2993,37 @@
 -            super(new CBCBlockCipher(new RC2Engine()), 64);
 -        }
 -    }
--
--    /**
--     * RC5
--     */
--    static public class RC5
--        extends JCEBlockCipher
--    {
--        public RC5()
--        {
--            super(new RC532Engine());
--        }
--    }
--
--    /**
--     * RC564
--     */
--    static public class RC564
--        extends JCEBlockCipher
--    {
--        public RC564()
--        {
--            super(new RC564Engine());
--        }
--    }
--
--    /**
--     * RC6
--     */
--    static public class RC6
--        extends JCEBlockCipher
--    {
--        public RC6()
--        {
--            super(new RC6Engine());
--        }
--    }
--
--    /**
--     * AES
--     */
--    static public class AES
--        extends JCEBlockCipher
--    {
--        public AES()
--        {
--            super(new AESFastEngine());
--        }
--    }
--
--    /**
--     * AESCBC
--     */
--    static public class AESCBC
--        extends JCEBlockCipher
--    {
--        public AESCBC()
--        {
--            super(new CBCBlockCipher(new AESFastEngine()), 128);
--        }
--    }
--
--    /**
--     * AESCFB
--     */
--    static public class AESCFB
--        extends JCEBlockCipher
--    {
--        public AESCFB()
--        {
--            super(new CFBBlockCipher(new AESFastEngine(), 128), 128);
--        }
--    }
--
--    /**
--     * AESOFB
--     */
--    static public class AESOFB
--        extends JCEBlockCipher
--    {
--        public AESOFB()
--        {
--            super(new OFBBlockCipher(new AESFastEngine(), 128), 128);
--        }
--    }
--
--    /**
--     * Rijndael
--     */
--    static public class Rijndael
--        extends JCEBlockCipher
--    {
--        public Rijndael()
--        {
--            super(new RijndaelEngine());
--        }
--    }
--
--    /**
--     * Serpent
--     */
--    static public class Serpent
--        extends JCEBlockCipher
--    {
--        public Serpent()
--        {
--            super(new SerpentEngine());
--        }
--    }
--
--
-     
--    /**
--     * CAST5
--     */
--    static public class CAST5
--        extends JCEBlockCipher
--    {
--        public CAST5()
--        {
--            super(new CAST5Engine());
--        }
--    }
--
--    /**
--     * CAST5 CBC
--     */
--    static public class CAST5CBC
--        extends JCEBlockCipher
--    {
--        public CAST5CBC()
--        {
--            super(new CBCBlockCipher(new CAST5Engine()), 64);
--        }
--    }
--
--    /**
--     * CAST6
--     */
--    static public class CAST6
--        extends JCEBlockCipher
--    {
--        public CAST6()
--        {
--            super(new CAST6Engine());
--        }
--    }
--
--    /**
--     * TEA
--     */
--    static public class TEA
--        extends JCEBlockCipher
--    {
--        public TEA()
--        {
--            super(new TEAEngine());
--        }
--    }
--
--    /**
--     * XTEA
--     */
--    static public class XTEA
--        extends JCEBlockCipher
--    {
--        public XTEA()
--        {
--            super(new XTEAEngine());
--        }
--    }
--
--    /**
--     * SEED
--     */
--    static public class SEED
--        extends JCEBlockCipher
--    {
--        public SEED()
--        {
--            super(new SEEDEngine());
--        }
--    }
 +    // BEGIN android-removed
 +    // /**
-+    //  * Blowfish CBC
++    //  * DESCBC
 +    //  */
-+    // static public class BlowfishCBC
++    // static public class DESCBC
 +    //     extends JCEBlockCipher
 +    // {
-+    //     public BlowfishCBC()
++    //     public DESCBC()
 +    //     {
-+    //         super(new CBCBlockCipher(new BlowfishEngine()), 64);
++    //         super(new CBCBlockCipher(new DESEngine()), 64);
 +    //     }
 +    // }
 +    //
 +    // /**
-+    //  * Twofish
++    //  *  GOST28147
 +    //  */
-+    // static public class Twofish
++    // static public class GOST28147
 +    //     extends JCEBlockCipher
 +    // {
-+    //     public Twofish()
++    //     public GOST28147()
 +    //     {
-+    //         super(new TwofishEngine());
++    //         super(new GOST28147Engine());
++    //     }
++    // }
++    //
++    // static public class GOST28147cbc
++    //     extends JCEBlockCipher
++    // {
++    //     public GOST28147cbc()
++    //     {
++    //         super(new CBCBlockCipher(new GOST28147Engine()), 64);
 +    //     }
 +    // }
 +    //
@@ -5298,193 +3050,11 @@
 +    //         super(new CBCBlockCipher(new RC2Engine()), 64);
 +    //     }
 +    // }
-+    //
-+    // /**
-+    //  * RC5
-+    //  */
-+    // static public class RC5
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public RC5()
-+    //     {
-+    //         super(new RC532Engine());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * RC564
-+    //  */
-+    // static public class RC564
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public RC564()
-+    //     {
-+    //         super(new RC564Engine());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * RC6
-+    //  */
-+    // static public class RC6
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public RC6()
-+    //     {
-+    //         super(new RC6Engine());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * AES
-+    //  */
-+    // static public class AES
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public AES()
-+    //     {
-+    //         super(new AESFastEngine());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * AESCBC
-+    //  */
-+    // static public class AESCBC
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public AESCBC()
-+    //     {
-+    //         super(new CBCBlockCipher(new AESFastEngine()), 128);
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * AESCFB
-+    //  */
-+    // static public class AESCFB
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public AESCFB()
-+    //     {
-+    //         super(new CFBBlockCipher(new AESFastEngine(), 128), 128);
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * AESOFB
-+    //  */
-+    // static public class AESOFB
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public AESOFB()
-+    //     {
-+    //         super(new OFBBlockCipher(new AESFastEngine(), 128), 128);
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * Rijndael
-+    //  */
-+    // static public class Rijndael
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public Rijndael()
-+    //     {
-+    //         super(new RijndaelEngine());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * Serpent
-+    //  */
-+    // static public class Serpent
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public Serpent()
-+    //     {
-+    //         super(new SerpentEngine());
-+    //     }
-+    // }
-+    //
-+    //
-+    //
-+    // /**
-+    //  * CAST5
-+    //  */
-+    // static public class CAST5
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public CAST5()
-+    //     {
-+    //         super(new CAST5Engine());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * CAST5 CBC
-+    //  */
-+    // static public class CAST5CBC
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public CAST5CBC()
-+    //     {
-+    //         super(new CBCBlockCipher(new CAST5Engine()), 64);
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * CAST6
-+    //  */
-+    // static public class CAST6
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public CAST6()
-+    //     {
-+    //         super(new CAST6Engine());
-+    //     }
-+    // }
-+    // 
-+    // /**
-+    //  * TEA
-+    //  */
-+    // static public class TEA
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public TEA()
-+    //     {
-+    //         super(new TEAEngine());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * XTEA
-+    //  */
-+    // static public class XTEA
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public XTEA()
-+    //     {
-+    //         super(new XTEAEngine());
-+    //     }
-+    // }
-+    // 
-+    // /**
-+    //  * SEED
-+    //  */
-+    // static public class SEED
-+    //     extends JCEBlockCipher
-+    // {
-+    //     public SEED()
-+    //     {
-+    //         super(new SEEDEngine());
-+    //     }
-+    // }
 +    // END android-removed
  
      /**
       * PBEWithMD5AndDES
-@@ -1087,7 +1129,7 @@
+@@ -822,7 +857,7 @@
              super(new CBCBlockCipher(new RC2Engine()));
          }
      }
@@ -5493,7 +3063,7 @@
      /**
       * PBEWithSHA1AndDES
       */
-@@ -1135,7 +1177,7 @@
+@@ -870,7 +905,7 @@
              super(new CBCBlockCipher(new DESedeEngine()));
          }
      }
@@ -5502,7 +3072,7 @@
      /**
       * PBEWithSHAAnd128BitRC2-CBC
       */
-@@ -1159,7 +1201,7 @@
+@@ -894,7 +929,7 @@
              super(new CBCBlockCipher(new RC2Engine()));
          }
      }
@@ -5511,7 +3081,7 @@
      /**
       * PBEWithSHAAndTwofish-CBC
       */
-@@ -1171,7 +1213,7 @@
+@@ -906,7 +941,7 @@
              super(new CBCBlockCipher(new TwofishEngine()));
          }
      }
@@ -5520,27 +3090,29 @@
      /**
       * PBEWithAES-CBC
       */
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java	2011-09-03 18:25:17.000000000 +0000
-@@ -37,9 +37,11 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java	2011-09-08 21:28:49.000000000 +0000
+@@ -36,10 +36,12 @@
  
      static
      {
 -        Integer i64 = new Integer(64);
 -        Integer i192 = new Integer(192);
 -        Integer i128 = new Integer(128);
+-        Integer i256 = new Integer(256);
 +        // BEGIN android-changed
 +        Integer i64 = Integer.valueOf(64);
 +        Integer i192 = Integer.valueOf(192);
 +        Integer i128 = Integer.valueOf(128);
++        Integer i256 = Integer.valueOf(256);
 +        // END android-changed
  
          algorithms.put("DES", i64);
          algorithms.put("DESEDE", i192);
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEDigestUtil.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEDigestUtil.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEDigestUtil.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEDigestUtil.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEDigestUtil.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEDigestUtil.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEDigestUtil.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEDigestUtil.java	2011-09-08 21:28:49.000000000 +0000
 @@ -12,7 +12,9 @@
  import org.bouncycastle.crypto.Digest;
  import org.bouncycastle.crypto.digests.MD5Digest;
@@ -5621,9 +3193,9 @@
              || (sha256.contains(digest1) && sha256.contains(digest2))
              || (sha384.contains(digest1) && sha384.contains(digest2))
              || (sha512.contains(digest1) && sha512.contains(digest2))
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEECPrivateKey.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEECPrivateKey.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2011-09-08 21:28:49.000000000 +0000
 @@ -20,7 +20,9 @@
  import org.bouncycastle.asn1.DERObject;
  import org.bouncycastle.asn1.DERObjectIdentifier;
@@ -5674,7 +3246,7 @@
              {
                  EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
  
-@@ -321,11 +325,13 @@
+@@ -324,11 +328,13 @@
              keyStructure = new ECPrivateKeyStructure(this.getS(), params);
          }
  
@@ -5693,9 +3265,9 @@
          {
  
              info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.getDERObject()), keyStructure.getDERObject());
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEECPublicKey.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEECPublicKey.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEECPublicKey.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEECPublicKey.java	2011-09-08 21:28:49.000000000 +0000
 @@ -20,8 +20,10 @@
  import org.bouncycastle.asn1.DERObjectIdentifier;
  import org.bouncycastle.asn1.DEROctetString;
@@ -5941,9 +3513,9 @@
          {
              if (ecSpec instanceof ECNamedCurveSpec)
              {
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEKeyGenerator.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEKeyGenerator.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEKeyGenerator.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEKeyGenerator.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEKeyGenerator.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEKeyGenerator.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEKeyGenerator.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEKeyGenerator.java	2011-09-08 21:28:49.000000000 +0000
 @@ -57,6 +57,11 @@
      {
          try
@@ -5956,80 +3528,10 @@
              engine.init(new KeyGenerationParameters(random, keySize));
              uninitialised = false;
          }
-@@ -145,30 +150,32 @@
+@@ -93,56 +98,60 @@
          }
      }
-     
--    /**
--     * generate a desEDE key in the a-b-c format.
--     */
--    public static class DESede3
--        extends JCEKeyGenerator
--    {
--        public DESede3()
--        {
--            super("DESede3", 192, new DESedeKeyGenerator());
--        }
--    }
--
--    /**
--     * SKIPJACK
--     */
--    public static class Skipjack
--        extends JCEKeyGenerator
--    {
--        public Skipjack()
--        {
--            super("SKIPJACK", 80, new CipherKeyGenerator());
--        }
--    }
--
-+    // BEGIN android-removed
-+    // /**
-+    //  * generate a desEDE key in the a-b-c format.
-+    //  */
-+    // public static class DESede3
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public DESede3()
-+    //     {
-+    //         super("DESede3", 192, new DESedeKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * SKIPJACK
-+    //  */
-+    // public static class Skipjack
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public Skipjack()
-+    //     {
-+    //         super("SKIPJACK", 80, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    // END android-removed
-+    
-     /**
-      * Blowfish
-      */
-@@ -180,31 +187,33 @@
-             super("Blowfish", 128, new CipherKeyGenerator());
-         }
-     }
--
--    /**
--     * Twofish
--     */
--    public static class Twofish
--        extends JCEKeyGenerator
--    {
--        public Twofish()
--        {
--            super("Twofish", 256, new CipherKeyGenerator());
--        }
--    }
--
+ 
 -    /**
 -     * RC2
 -     */
@@ -6042,77 +3544,6 @@
 -        }
 -    }
 -
-+    
-+    // BEGIN android-removed
-+    // /**
-+    //  * Twofish
-+    //  */
-+    // public static class Twofish
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public Twofish()
-+    //     {
-+    //         super("Twofish", 256, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * RC2
-+    //  */
-+    // public static class RC2
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public RC2()
-+    //     {
-+    //         super("RC2", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    // END android-removed
-+    
-     /**
-      * RC4
-      */
-@@ -216,203 +225,207 @@
-             super("RC4", 128, new CipherKeyGenerator());
-         }
-     }
--
--    /**
--     * RC5
--     */
--    public static class RC5
--        extends JCEKeyGenerator
--    {
--        public RC5()
--        {
--            super("RC5", 128, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * RC5
--     */
--    public static class RC564
--        extends JCEKeyGenerator
--    {
--        public RC564()
--        {
--            super("RC5-64", 256, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * RC6
--     */
--    public static class RC6
--        extends JCEKeyGenerator
--    {
--        public RC6()
--        {
--            super("RC6", 256, new CipherKeyGenerator());
--        }
--    }
--
 -    /**
 -     * GOST28147
 -     */
@@ -6124,64 +3555,16 @@
 -            super("GOST28147", 256, new CipherKeyGenerator());
 -        }
 -    }
-     
--    /**
--     * Rijndael
--     */
--    public static class Rijndael
--        extends JCEKeyGenerator
--    {
--        public Rijndael()
--        {
--            super("Rijndael", 192, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * Serpent
--     */
--    public static class Serpent
--        extends JCEKeyGenerator
--    {
--        public Serpent()
--        {
--            super("Serpent", 192, new CipherKeyGenerator());
--        }
--    }
 +    // BEGIN android-removed
 +    // /**
-+    //  * RC5
++    //  * RC2
 +    //  */
-+    // public static class RC5
++    // public static class RC2
 +    //     extends JCEKeyGenerator
 +    // {
-+    //     public RC5()
++    //     public RC2()
 +    //     {
-+    //         super("RC5", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * RC5
-+    //  */
-+    // public static class RC564
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public RC564()
-+    //     {
-+    //         super("RC5-64", 256, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * RC6
-+    //  */
-+    // public static class RC6
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public RC6()
-+    //     {
-+    //         super("RC6", 256, new CipherKeyGenerator());
++    //         super("RC2", 128, new CipherKeyGenerator());
 +    //     }
 +    // }
 +    //
@@ -6196,225 +3579,6 @@
 +    //         super("GOST28147", 256, new CipherKeyGenerator());
 +    //     }
 +    // }
-     
--
--
--    /**
--     * CAST6
--     */
--    public static class CAST6
--        extends JCEKeyGenerator
--    {
--        public CAST6()
--        {
--            super("CAST6", 256, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * TEA
--     */
--    public static class TEA
--        extends JCEKeyGenerator
--    {
--        public TEA()
--        {
--            super("TEA", 128, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * XTEA
--     */
--    public static class XTEA
--        extends JCEKeyGenerator
--    {
--        public XTEA()
--        {
--            super("XTEA", 128, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * Salsa20
--     */
--    public static class Salsa20
--        extends JCEKeyGenerator
--    {
--        public Salsa20()
--        {
--            super("Salsa20", 128, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * HC128
--     */
--    public static class HC128
--        extends JCEKeyGenerator
--    {
--        public HC128()
--        {
--            super("HC128", 128, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * HC256
--     */
--    public static class HC256
--        extends JCEKeyGenerator
--    {
--        public HC256()
--        {
--            super("HC256", 256, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * VMPC
--     */
--    public static class VMPC
--        extends JCEKeyGenerator
--    {
--        public VMPC()
--        {
--            super("VMPC", 128, new CipherKeyGenerator());
--        }
--    }
--
--    /**
--     * VMPC-KSA3
--     */
--    public static class VMPCKSA3
--        extends JCEKeyGenerator
--    {
--        public VMPCKSA3()
--        {
--            super("VMPC-KSA3", 128, new CipherKeyGenerator());
--        }
--    }
-+    // /**
-+    //  * Rijndael
-+    //  */
-+    // public static class Rijndael
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public Rijndael()
-+    //     {
-+    //         super("Rijndael", 192, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * Serpent
-+    //  */
-+    // public static class Serpent
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public Serpent()
-+    //     {
-+    //         super("Serpent", 192, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    //
-+    //
-+    // /**
-+    //  * CAST6
-+    //  */
-+    // public static class CAST6
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public CAST6()
-+    //     {
-+    //         super("CAST6", 256, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * TEA
-+    //  */
-+    // public static class TEA
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public TEA()
-+    //     {
-+    //         super("TEA", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * XTEA
-+    //  */
-+    // public static class XTEA
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public XTEA()
-+    //     {
-+    //         super("XTEA", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * Salsa20
-+    //  */
-+    // public static class Salsa20
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public Salsa20()
-+    //     {
-+    //         super("Salsa20", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * HC128
-+    //  */
-+    // public static class HC128
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public HC128()
-+    //     {
-+    //         super("HC128", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * HC256
-+    //  */
-+    // public static class HC256
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public HC256()
-+    //     {
-+    //         super("HC256", 256, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * VMPC
-+    //  */
-+    // public static class VMPC
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public VMPC()
-+    //     {
-+    //         super("VMPC", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * VMPC-KSA3
-+    //  */
-+    // public static class VMPCKSA3
-+    //     extends JCEKeyGenerator
-+    // {
-+    //     public VMPCKSA3()
-+    //     {
-+    //         super("VMPC-KSA3", 128, new CipherKeyGenerator());
-+    //     }
-+    // }
 +    // END android-removed
  
      // HMAC Related secret keys..
@@ -6472,7 +3636,7 @@
  
      /**
       * MD5HMAC
-@@ -427,29 +440,29 @@
+@@ -157,29 +166,29 @@
      }
  
  
@@ -6525,7 +3689,7 @@
  
  
      /**
-@@ -464,17 +477,19 @@
+@@ -194,17 +203,19 @@
          }
      }
  
@@ -6556,7 +3720,7 @@
      
      /**
       * HMACSHA256
-@@ -512,15 +527,17 @@
+@@ -242,15 +253,17 @@
          }
      }
      
@@ -6585,10 +3749,10 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEMac.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEMac.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEMac.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEMac.java	2011-09-03 18:25:17.000000000 +0000
-@@ -2,29 +2,43 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEMac.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEMac.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEMac.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEMac.java	2011-09-08 21:28:49.000000000 +0000
+@@ -11,25 +11,39 @@
  
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.Mac;
@@ -6618,14 +3782,9 @@
 +// import org.bouncycastle.crypto.digests.TigerDigest;
 +// END android-removed
  import org.bouncycastle.crypto.engines.DESEngine;
- import org.bouncycastle.crypto.engines.DESedeEngine;
 -import org.bouncycastle.crypto.engines.RC2Engine;
--import org.bouncycastle.crypto.engines.RC532Engine;
--import org.bouncycastle.crypto.engines.SkipjackEngine;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.engines.RC2Engine;
-+// import org.bouncycastle.crypto.engines.RC532Engine;
-+// import org.bouncycastle.crypto.engines.SkipjackEngine;
 +// END android-removed
  import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
 -import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
@@ -6637,16 +3796,14 @@
  import org.bouncycastle.crypto.macs.HMac;
 -import org.bouncycastle.crypto.macs.ISO9797Alg3Mac;
 -import org.bouncycastle.crypto.macs.OldHMac;
--import org.bouncycastle.crypto.macs.VMPCMac;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.macs.ISO9797Alg3Mac;
 +// import org.bouncycastle.crypto.macs.OldHMac;
-+// import org.bouncycastle.crypto.macs.VMPCMac;
 +// END android-removed
  import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
  import org.bouncycastle.crypto.params.KeyParameter;
  import org.bouncycastle.crypto.params.ParametersWithIV;
-@@ -146,224 +160,226 @@
+@@ -143,115 +157,117 @@
       * the classes that extend directly off us.
       */
  
@@ -6663,30 +3820,6 @@
 -    }
 -
 -    /**
--     * DESede
--     */
--    public static class DESede
--        extends JCEMac
--    {
--        public DESede()
--        {
--            super(new CBCBlockCipherMac(new DESedeEngine()));
--        }
--    }
--
--    /**
--     * SKIPJACK
--     */
--    public static class Skipjack
--        extends JCEMac
--    {
--        public Skipjack()
--        {
--            super(new CBCBlockCipherMac(new SkipjackEngine()));
--        }
--    }
--
--    /**
 -     * RC2
 -     */
 -    public static class RC2
@@ -6699,18 +3832,6 @@
 -    }
 -
 -    /**
--     * RC5
--     */
--    public static class RC5
--        extends JCEMac
--    {
--        public RC5()
--        {
--            super(new CBCBlockCipherMac(new RC532Engine()));
--        }
--    }
--
--    /**
 -     * GOST28147
 -     */
 -    public static class GOST28147
@@ -6722,17 +3843,7 @@
 -        }
 -    }
 -
--    /**
--     * VMPC
--     */
--    public static class VMPC
--        extends JCEMac
--    {
--        public VMPC()
--        {
--            super(new VMPCMac());
--        }
--    }
+-    
 -
 -    /**
 -     * DES
@@ -6747,30 +3858,6 @@
 -    }
 -
 -    /**
--     * DESede
--     */
--    public static class DESedeCFB8
--        extends JCEMac
--    {
--        public DESedeCFB8()
--        {
--            super(new CFBBlockCipherMac(new DESedeEngine()));
--        }
--    }
--
--    /**
--     * SKIPJACK
--     */
--    public static class SkipjackCFB8
--        extends JCEMac
--    {
--        public SkipjackCFB8()
--        {
--            super(new CFBBlockCipherMac(new SkipjackEngine()));
--        }
--    }
--
--    /**
 -     * RC2CFB8
 -     */
 -    public static class RC2CFB8
@@ -6783,17 +3870,52 @@
 -    }
 -
 -    /**
--     * RC5CFB8
+-     * DES9797Alg3with7816-4Padding
 -     */
--    public static class RC5CFB8
+-    public static class DES9797Alg3with7816d4
 -        extends JCEMac
 -    {
--        public RC5CFB8()
+-        public DES9797Alg3with7816d4()
 -        {
--            super(new CFBBlockCipherMac(new RC532Engine()));
+-            super(new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()));
 -        }
 -    }
--    
+-
+-    /**
+-     * DES9797Alg3
+-     */
+-    public static class DES9797Alg3
+-        extends JCEMac
+-    {
+-        public DES9797Alg3()
+-        {
+-            super(new ISO9797Alg3Mac(new DESEngine()));
+-        }
+-    }
+-
+-    /**
+-     * MD2 HMac
+-     */
+-    public static class MD2
+-        extends JCEMac
+-    {
+-        public MD2()
+-        {
+-            super(new HMac(new MD2Digest()));
+-        }
+-    }
+-
+-    /**
+-     * MD4 HMac
+-     */
+-    public static class MD4
+-        extends JCEMac
+-    {
+-        public MD4()
+-        {
+-            super(new HMac(new MD4Digest()));
+-        }
+-    }
 +    // BEGIN android-removed
 +    // /**
 +    //  * DES
@@ -6808,30 +3930,6 @@
 +    // }
 +    //
 +    // /**
-+    //  * DESede
-+    //  */
-+    // public static class DESede
-+    //     extends JCEMac
-+    // {
-+    //     public DESede()
-+    //     {
-+    //         super(new CBCBlockCipherMac(new DESedeEngine()));
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * SKIPJACK
-+    //  */
-+    // public static class Skipjack
-+    //     extends JCEMac
-+    // {
-+    //     public Skipjack()
-+    //     {
-+    //         super(new CBCBlockCipherMac(new SkipjackEngine()));
-+    //     }
-+    // }
-+    //
-+    // /**
 +    //  * RC2
 +    //  */
 +    // public static class RC2
@@ -6844,18 +3942,6 @@
 +    // }
 +    //
 +    // /**
-+    //  * RC5
-+    //  */
-+    // public static class RC5
-+    //     extends JCEMac
-+    // {
-+    //     public RC5()
-+    //     {
-+    //         super(new CBCBlockCipherMac(new RC532Engine()));
-+    //     }
-+    // }
-+    //
-+    // /**
 +    //  * GOST28147
 +    //  */
 +    // public static class GOST28147
@@ -6867,17 +3953,7 @@
 +    //     }
 +    // }
 +    //
-+    // /**
-+    //  * VMPC
-+    //  */
-+    // public static class VMPC
-+    //     extends JCEMac
-+    // {
-+    //     public VMPC()
-+    //     {
-+    //         super(new VMPCMac());
-+    //     }
-+    // }
++    //
 +    //
 +    // /**
 +    //  * DES
@@ -6892,30 +3968,6 @@
 +    // }
 +    //
 +    // /**
-+    //  * DESede
-+    //  */
-+    // public static class DESedeCFB8
-+    //     extends JCEMac
-+    // {
-+    //     public DESedeCFB8()
-+    //     {
-+    //         super(new CFBBlockCipherMac(new DESedeEngine()));
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * SKIPJACK
-+    //  */
-+    // public static class SkipjackCFB8
-+    //     extends JCEMac
-+    // {
-+    //     public SkipjackCFB8()
-+    //     {
-+    //         super(new CFBBlockCipherMac(new SkipjackEngine()));
-+    //     }
-+    // }
-+    //
-+    // /**
 +    //  * RC2CFB8
 +    //  */
 +    // public static class RC2CFB8
@@ -6928,43 +3980,6 @@
 +    // }
 +    //
 +    // /**
-+    //  * RC5CFB8
-+    //  */
-+    // public static class RC5CFB8
-+    //     extends JCEMac
-+    // {
-+    //     public RC5CFB8()
-+    //     {
-+    //         super(new CFBBlockCipherMac(new RC532Engine()));
-+    //     }
-+    // }
-+    //
-+    //
-+    // /**
-+    //  * DESede64
-+    //  */
-+    // public static class DESede64
-+    //     extends JCEMac
-+    // {
-+    //     public DESede64()
-+    //     {
-+    //         super(new CBCBlockCipherMac(new DESedeEngine(), 64));
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * DESede64with7816-4Padding
-+    //  */
-+    // public static class DESede64with7816d4
-+    //     extends JCEMac
-+    // {
-+    //     public DESede64with7816d4()
-+    //     {
-+    //         super(new CBCBlockCipherMac(new DESedeEngine(), 64, new ISO7816d4Padding()));
-+    //     }
-+    // }
-+    //
-+    // /**
 +    //  * DES9797Alg3with7816-4Padding
 +    //  */
 +    // public static class DES9797Alg3with7816d4
@@ -7012,84 +4027,10 @@
 +    //     }
 +    // }
 +    // END android-removed
-     
+ 
      /**
--     * DESede64
--     */
--    public static class DESede64
--        extends JCEMac
--    {
--        public DESede64()
--        {
--            super(new CBCBlockCipherMac(new DESedeEngine(), 64));
--        }
--    }
--
--    /**
--     * DESede64with7816-4Padding
--     */
--    public static class DESede64with7816d4
--        extends JCEMac
--    {
--        public DESede64with7816d4()
--        {
--            super(new CBCBlockCipherMac(new DESedeEngine(), 64, new ISO7816d4Padding()));
--        }
--    }
--
--    /**
--     * DES9797Alg3with7816-4Padding
--     */
--    public static class DES9797Alg3with7816d4
--        extends JCEMac
--    {
--        public DES9797Alg3with7816d4()
--        {
--            super(new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()));
--        }
--    }
--
--    /**
--     * DES9797Alg3
--     */
--    public static class DES9797Alg3
--        extends JCEMac
--    {
--        public DES9797Alg3()
--        {
--            super(new ISO9797Alg3Mac(new DESEngine()));
--        }
--    }
--
--    /**
--     * MD2 HMac
--     */
--    public static class MD2
--        extends JCEMac
--    {
--        public MD2()
--        {
--            super(new HMac(new MD2Digest()));
--        }
--    }
--
--    /**
--     * MD4 HMac
--     */
--    public static class MD4
--        extends JCEMac
--    {
--        public MD4()
--        {
--            super(new HMac(new MD4Digest()));
--        }
--    }
--
--    /**
       * MD5 HMac
-      */
-     public static class MD5
-@@ -374,7 +390,7 @@
+@@ -264,7 +280,7 @@
              super(new HMac(new MD5Digest()));
          }
      }
@@ -7098,7 +4039,7 @@
      /**
       * SHA1 HMac
       */
-@@ -386,18 +402,20 @@
+@@ -276,18 +292,20 @@
              super(new HMac(new SHA1Digest()));
          }
      }
@@ -7131,7 +4072,7 @@
      
      /**
       * SHA-256 HMac
-@@ -410,7 +428,7 @@
+@@ -300,7 +318,7 @@
              super(new HMac(new SHA256Digest()));
          }
      }
@@ -7140,7 +4081,7 @@
      /**
       * SHA-384 HMac
       */
-@@ -422,15 +440,17 @@
+@@ -312,15 +330,17 @@
              super(new HMac(new SHA384Digest()));
          }
      }
@@ -7167,7 +4108,7 @@
      
      /**
       * SHA-512 HMac
-@@ -443,73 +463,75 @@
+@@ -333,73 +353,75 @@
              super(new HMac(new SHA512Digest()));
          }
      }
@@ -7307,7 +4248,7 @@
      /**
       * PBEWithHmacSHA
       */
-@@ -521,16 +543,18 @@
+@@ -411,16 +433,18 @@
              super(new HMac(new SHA1Digest()), PKCS12, SHA1, 160);
          }
      }
@@ -7338,10 +4279,10 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSACipher.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSACipher.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSACipher.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSACipher.java	2011-09-03 18:25:17.000000000 +0000
-@@ -534,48 +534,50 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSACipher.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSACipher.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSACipher.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSACipher.java	2011-09-08 21:28:49.000000000 +0000
+@@ -535,48 +535,50 @@
          }
      }
  
@@ -7436,9 +4377,9 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java	2011-09-08 21:28:49.000000000 +0000
 @@ -125,7 +125,9 @@
       */
      public byte[] getEncoded()
@@ -7450,9 +4391,9 @@
  
          return info.getDEREncoded();
      }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPrivateKey.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPrivateKey.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPrivateKey.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPrivateKey.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPrivateKey.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPrivateKey.java	2011-09-08 21:28:49.000000000 +0000
 @@ -77,7 +77,9 @@
  
      public byte[] getEncoded()
@@ -7464,9 +4405,9 @@
  
          return info.getDEREncoded();
      }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPublicKey.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPublicKey.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCERSAPublicKey.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCERSAPublicKey.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPublicKey.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPublicKey.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCERSAPublicKey.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCERSAPublicKey.java	2011-09-08 21:28:49.000000000 +0000
 @@ -90,7 +90,9 @@
  
      public byte[] getEncoded()
@@ -7478,13 +4419,13 @@
  
          return info.getDEREncoded();
      }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCESecretKeyFactory.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCESecretKeyFactory.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCESecretKeyFactory.java	2011-09-03 18:25:17.000000000 +0000
-@@ -321,29 +321,31 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCESecretKeyFactory.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCESecretKeyFactory.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCESecretKeyFactory.java	2011-09-08 21:28:49.000000000 +0000
+@@ -250,29 +250,31 @@
          }
      }
-     
+ 
 -    /**
 -     * PBEWithMD2AndDES
 -     */
@@ -7536,7 +4477,7 @@
  
     /**
      * PBEWithMD5AndDES
-@@ -477,17 +479,19 @@
+@@ -406,17 +408,19 @@
         }
     }
     
@@ -7567,7 +4508,7 @@
  
     /**
      * PBEWithHmacSHA
-@@ -501,17 +505,19 @@
+@@ -430,17 +434,19 @@
         }
     }
  
@@ -7598,7 +4539,7 @@
     
     /**
      * PBEWithSHA1And128BitAES-BC
-@@ -620,4 +626,56 @@
+@@ -549,4 +555,56 @@
             super("PBEWithMD5And256BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 256, 128);
         }
     }
@@ -7655,42 +4596,10 @@
 +    }
 +    // END android-added
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEStreamCipher.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JCEStreamCipher.java	2011-09-03 18:25:17.000000000 +0000
-@@ -5,17 +5,21 @@
- import org.bouncycastle.crypto.DataLengthException;
- import org.bouncycastle.crypto.StreamBlockCipher;
- import org.bouncycastle.crypto.StreamCipher;
--import org.bouncycastle.crypto.engines.BlowfishEngine;
--import org.bouncycastle.crypto.engines.DESEngine;
--import org.bouncycastle.crypto.engines.DESedeEngine;
--import org.bouncycastle.crypto.engines.HC128Engine;
--import org.bouncycastle.crypto.engines.HC256Engine;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.engines.BlowfishEngine;
-+// import org.bouncycastle.crypto.engines.DESEngine;
-+// import org.bouncycastle.crypto.engines.DESedeEngine;
-+// import org.bouncycastle.crypto.engines.HC128Engine;
-+// import org.bouncycastle.crypto.engines.HC256Engine;
-+// END android-removed
- import org.bouncycastle.crypto.engines.RC4Engine;
--import org.bouncycastle.crypto.engines.Salsa20Engine;
--import org.bouncycastle.crypto.engines.SkipjackEngine;
--import org.bouncycastle.crypto.engines.TwofishEngine;
--import org.bouncycastle.crypto.engines.VMPCEngine;
--import org.bouncycastle.crypto.engines.VMPCKSA3Engine;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.engines.Salsa20Engine;
-+// import org.bouncycastle.crypto.engines.SkipjackEngine;
-+// import org.bouncycastle.crypto.engines.TwofishEngine;
-+// import org.bouncycastle.crypto.engines.VMPCEngine;
-+// import org.bouncycastle.crypto.engines.VMPCKSA3Engine;
-+// END android-removed
- import org.bouncycastle.crypto.modes.CFBBlockCipher;
- import org.bouncycastle.crypto.modes.OFBBlockCipher;
- import org.bouncycastle.crypto.params.KeyParameter;
-@@ -27,8 +31,10 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEStreamCipher.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JCEStreamCipher.java	2011-09-08 21:28:49.000000000 +0000
+@@ -13,20 +13,26 @@
  import javax.crypto.ShortBufferException;
  import javax.crypto.spec.IvParameterSpec;
  import javax.crypto.spec.PBEParameterSpec;
@@ -7700,10 +4609,31 @@
 +// import javax.crypto.spec.RC2ParameterSpec;
 +// import javax.crypto.spec.RC5ParameterSpec;
 +// END android-removed
- import java.security.AlgorithmParameters;
- import java.security.InvalidAlgorithmParameterException;
- import java.security.InvalidKeyException;
-@@ -44,8 +50,10 @@
+ 
+ import org.bouncycastle.crypto.BlockCipher;
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.DataLengthException;
+ import org.bouncycastle.crypto.StreamBlockCipher;
+ import org.bouncycastle.crypto.StreamCipher;
+-import org.bouncycastle.crypto.engines.BlowfishEngine;
+-import org.bouncycastle.crypto.engines.DESEngine;
+-import org.bouncycastle.crypto.engines.DESedeEngine;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.engines.BlowfishEngine;
++// import org.bouncycastle.crypto.engines.DESEngine;
++// import org.bouncycastle.crypto.engines.DESedeEngine;
++// END android-removed
+ import org.bouncycastle.crypto.engines.RC4Engine;
+-import org.bouncycastle.crypto.engines.SkipjackEngine;
+-import org.bouncycastle.crypto.engines.TwofishEngine;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.engines.SkipjackEngine;
++// import org.bouncycastle.crypto.engines.TwofishEngine;
++// END android-removed
+ import org.bouncycastle.crypto.modes.CFBBlockCipher;
+ import org.bouncycastle.crypto.modes.OFBBlockCipher;
+ import org.bouncycastle.crypto.params.KeyParameter;
+@@ -40,8 +46,10 @@
      //
      private Class[]                 availableSpecs =
                                      {
@@ -7716,7 +4646,7 @@
                                          IvParameterSpec.class,
                                          PBEParameterSpec.class
                                      };
-@@ -374,125 +382,127 @@
+@@ -370,125 +378,127 @@
       * The ciphers that inherit from us.
       */
  
@@ -7962,8 +4892,8 @@
 +    // END android-removed
  
      /**
-      * RC4
-@@ -517,7 +527,7 @@
+      * PBEWithSHAAnd128BitRC4
+@@ -501,7 +511,7 @@
              super(new RC4Engine(), 0);
          }
      }
@@ -7972,137 +4902,17 @@
      /**
       * PBEWithSHAAnd40BitRC4
       */
-@@ -529,64 +539,66 @@
-             super(new RC4Engine(), 0);
-         }
-     }
--
--    /**
--     * Salsa20
--     */
--    static public class Salsa20
--        extends JCEStreamCipher
--    {
--        public Salsa20()
--        {
--            super(new Salsa20Engine(), 8);
--        }
--    }
--
--    /**
--     * HC-128
--     */
--    static public class HC128
--        extends JCEStreamCipher
--    {
--        public HC128()
--        {
--            super(new HC128Engine(), 16);
--        }
--    }
--
--    /**
--     * HC-256
--     */
--    static public class HC256
--        extends JCEStreamCipher
--    {
--        public HC256()
--        {
--            super(new HC256Engine(), 32);
--        }
--    }
--
--    /**
--     * VMPC
--     */
--    static public class VMPC
--        extends JCEStreamCipher
--    {
--        public VMPC()
--        {
--            super(new VMPCEngine(), 16);
--        }
--    }
--
--    /**
--     * VMPC-KSA3
--     */
--    static public class VMPCKSA3
--        extends JCEStreamCipher
--    {
--        public VMPCKSA3()
--        {
--            super(new VMPCKSA3Engine(), 16);
--        }
--    }
-+    
-+    // BEGIN android-removed
-+    // /**
-+    //  * Salsa20
-+    //  */
-+    // static public class Salsa20
-+    //     extends JCEStreamCipher
-+    // {
-+    //     public Salsa20()
-+    //     {
-+    //         super(new Salsa20Engine(), 8);
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * HC-128
-+    //  */
-+    // static public class HC128
-+    //     extends JCEStreamCipher
-+    // {
-+    //     public HC128()
-+    //     {
-+    //         super(new HC128Engine(), 16);
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * HC-256
-+    //  */
-+    // static public class HC256
-+    //     extends JCEStreamCipher
-+    // {
-+    //     public HC256()
-+    //     {
-+    //         super(new HC256Engine(), 32);
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * VMPC
-+    //  */
-+    // static public class VMPC
-+    //     extends JCEStreamCipher
-+    // {
-+    //     public VMPC()
-+    //     {
-+    //         super(new VMPCEngine(), 16);
-+    //     }
-+    // }
-+    //
-+    // /**
-+    //  * VMPC-KSA3
-+    //  */
-+    // static public class VMPCKSA3
-+    //     extends JCEStreamCipher
-+    // {
-+    //     public VMPCKSA3()
-+    //     {
-+    //         super(new VMPCKSA3Engine(), 16);
-+    //     }
-+    // }
-+    // END android-removed
- }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java	2011-09-03 18:25:17.000000000 +0000
-@@ -2,19 +2,25 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java	2011-09-08 21:28:49.000000000 +0000
+@@ -11,18 +11,24 @@
+ import javax.crypto.spec.DHGenParameterSpec;
+ import javax.crypto.spec.DHParameterSpec;
+ import javax.crypto.spec.IvParameterSpec;
+-import javax.crypto.spec.RC2ParameterSpec;
++// BEGIN android-removed
++// import javax.crypto.spec.RC2ParameterSpec;
++// END android-removed
  
  import org.bouncycastle.crypto.generators.DHParametersGenerator;
  import org.bouncycastle.crypto.generators.DSAParametersGenerator;
@@ -8125,17 +4935,9 @@
 +// import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
 +// END android-removed
  
- import javax.crypto.spec.DHGenParameterSpec;
- import javax.crypto.spec.DHParameterSpec;
- import javax.crypto.spec.IvParameterSpec;
--import javax.crypto.spec.RC2ParameterSpec;
-+// BEGIN android-removed
-+// import javax.crypto.spec.RC2ParameterSpec;
-+// END android-removed
- import java.security.AlgorithmParameterGeneratorSpi;
- import java.security.AlgorithmParameters;
- import java.security.InvalidAlgorithmParameterException;
-@@ -144,196 +150,198 @@
+ public abstract class JDKAlgorithmParameterGenerator
+     extends AlgorithmParameterGeneratorSpi
+@@ -145,196 +151,198 @@
          }
      }
  
@@ -8169,7 +4971,7 @@
 -            
 -            try
 -            {
--                params = AlgorithmParameters.getInstance("GOST3410", "BC");
+-                params = AlgorithmParameters.getInstance("GOST3410", BouncyCastleProvider.PROVIDER_NAME);
 -                params.init(new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(p.getP(), p.getQ(), p.getA())));
 -            }
 -            catch (Exception e)
@@ -8221,7 +5023,7 @@
 -
 -            try
 -            {
--                params = AlgorithmParameters.getInstance("ElGamal", "BC");
+-                params = AlgorithmParameters.getInstance("ElGamal", BouncyCastleProvider.PROVIDER_NAME);
 -                params.init(new DHParameterSpec(p.getP(), p.getG(), l));
 -            }
 -            catch (Exception e)
@@ -8259,7 +5061,7 @@
 -
 -            try
 -            {
--                params = AlgorithmParameters.getInstance("DES", "BC");
+-                params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
 -                params.init(new IvParameterSpec(iv));
 -            }
 -            catch (Exception e)
@@ -8307,7 +5109,7 @@
 -
 -                try
 -                {
--                    params = AlgorithmParameters.getInstance("RC2", "BC");
+-                    params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
 -                    params.init(new IvParameterSpec(iv));
 -                }
 -                catch (Exception e)
@@ -8319,7 +5121,7 @@
 -            {
 -                try
 -                {
--                    params = AlgorithmParameters.getInstance("RC2", "BC");
+-                    params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
 -                    params.init(spec);
 -                }
 -                catch (Exception e)
@@ -8331,204 +5133,204 @@
 -            return params;
 -        }
 -    }
-+   // BEGIN android-removed
-+   // public static class GOST3410
-+   //     extends JDKAlgorithmParameterGenerator
-+   // {
-+   //     protected void engineInit(
-+   //             AlgorithmParameterSpec  genParamSpec,
-+   //             SecureRandom            random)
-+   //     throws InvalidAlgorithmParameterException
-+   //     {
-+   //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for GOST3410 parameter generation.");
-+   //     }
-+   //       
-+   //     protected AlgorithmParameters engineGenerateParameters()
-+   //     {
-+   //         GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator();
-+   //           
-+   //         if (random != null)
-+   //         {
-+   //             pGen.init(strength, 2, random);
-+   //         }
-+   //         else
-+   //         {
-+   //             pGen.init(strength, 2, new SecureRandom());
-+   //         }
-+   //           
-+   //         GOST3410Parameters p = pGen.generateParameters();
-+   //           
-+   //         AlgorithmParameters params;
-+   //           
-+   //         try
-+   //         {
-+   //             params = AlgorithmParameters.getInstance("GOST3410", "BC");
-+   //             params.init(new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(p.getP(), p.getQ(), p.getA())));
-+   //         }
-+   //         catch (Exception e)
-+   //         {
-+   //             throw new RuntimeException(e.getMessage());
-+   //         }
-+   //           
-+   //         return params;
-+   //     }
-+   // }
-+   //   
-+   // public static class ElGamal
-+   //     extends JDKAlgorithmParameterGenerator
-+   // {
-+   //     private int l = 0;
-+   //       
-+   //     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()
-+   //     {
-+   //         ElGamalParametersGenerator pGen = new ElGamalParametersGenerator();
-+   //
-+   //         if (random != null)
-+   //         {
-+   //             pGen.init(strength, 20, random);
-+   //         }
-+   //         else
-+   //         {
-+   //             pGen.init(strength, 20, new SecureRandom());
-+   //         }
-+   //
-+   //         ElGamalParameters p = pGen.generateParameters();
-+   //
-+   //         AlgorithmParameters params;
-+   //
-+   //         try
-+   //         {
-+   //             params = AlgorithmParameters.getInstance("ElGamal", "BC");
-+   //             params.init(new DHParameterSpec(p.getP(), p.getG(), l));
-+   //         }
-+   //         catch (Exception e)
-+   //         {
-+   //             throw new RuntimeException(e.getMessage());
-+   //         }
-+   //
-+   //         return params;
-+   //     }
-+   // }
-+   //
-+   //  public static class DES
-+   //      extends JDKAlgorithmParameterGenerator
-+   //  {
-+   //      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 = new SecureRandom();
-+   //          }
-+   //
-+   //          random.nextBytes(iv);
-+   //
-+   //          AlgorithmParameters params;
-+   //
-+   //          try
-+   //          {
-+   //              params = AlgorithmParameters.getInstance("DES", "BC");
-+   //              params.init(new IvParameterSpec(iv));
-+   //          }
-+   //          catch (Exception e)
-+   //          {
-+   //              throw new RuntimeException(e.getMessage());
-+   //          }
-+   //
-+   //          return params;
-+   //      }
-+   //  }
-+   //
-+   //  public static class RC2
-+   //      extends JDKAlgorithmParameterGenerator
-+   //  {
-+   //      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 = new SecureRandom();
-+   //              }
-+   //
-+   //              random.nextBytes(iv);
-+   //
-+   //              try
-+   //              {
-+   //                  params = AlgorithmParameters.getInstance("RC2", "BC");
-+   //                  params.init(new IvParameterSpec(iv));
-+   //              }
-+   //              catch (Exception e)
-+   //              {
-+   //                  throw new RuntimeException(e.getMessage());
-+   //              }
-+   //          }
-+   //          else
-+   //          {
-+   //              try
-+   //              {
-+   //                  params = AlgorithmParameters.getInstance("RC2", "BC");
-+   //                  params.init(spec);
-+   //              }
-+   //              catch (Exception e)
-+   //              {
-+   //                  throw new RuntimeException(e.getMessage());
-+   //              }
-+   //          }
-+   //
-+   //          return params;
-+   //      }
-+   //  }
-+   // END android-removed
++    // BEGIN android-removed
++    // public static class GOST3410
++    //     extends JDKAlgorithmParameterGenerator
++    // {
++    //     protected void engineInit(
++    //             AlgorithmParameterSpec  genParamSpec,
++    //             SecureRandom            random)
++    //     throws InvalidAlgorithmParameterException
++    //     {
++    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for GOST3410 parameter generation.");
++    //     }
++    //    
++    //     protected AlgorithmParameters engineGenerateParameters()
++    //     {
++    //         GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator();
++    //        
++    //         if (random != null)
++    //         {
++    //             pGen.init(strength, 2, random);
++    //         }
++    //         else
++    //         {
++    //             pGen.init(strength, 2, new SecureRandom());
++    //         }
++    //        
++    //         GOST3410Parameters p = pGen.generateParameters();
++    //        
++    //         AlgorithmParameters params;
++    //
++    //         try
++    //         {
++    //             params = AlgorithmParameters.getInstance("GOST3410", BouncyCastleProvider.PROVIDER_NAME);
++    //             params.init(new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(p.getP(), p.getQ(), p.getA())));
++    //         }
++    //         catch (Exception e)
++    //         {
++    //             throw new RuntimeException(e.getMessage());
++    //         }
++    //
++    //         return params;
++    //     }
++    // }
++    //
++    // public static class ElGamal
++    //     extends JDKAlgorithmParameterGenerator
++    // {
++    //     private int l = 0;
++    //
++    //     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()
++    //     {
++    //         ElGamalParametersGenerator pGen = new ElGamalParametersGenerator();
++    //
++    //         if (random != null)
++    //         {
++    //             pGen.init(strength, 20, random);
++    //         }
++    //         else
++    //         {
++    //             pGen.init(strength, 20, new SecureRandom());
++    //         }
++    //
++    //         ElGamalParameters p = pGen.generateParameters();
++    //
++    //         AlgorithmParameters params;
++    //
++    //         try
++    //         {
++    //             params = AlgorithmParameters.getInstance("ElGamal", BouncyCastleProvider.PROVIDER_NAME);
++    //             params.init(new DHParameterSpec(p.getP(), p.getG(), l));
++    //         }
++    //         catch (Exception e)
++    //         {
++    //             throw new RuntimeException(e.getMessage());
++    //         }
++    //
++    //         return params;
++    //     }
++    // }
++    //
++    // public static class DES
++    //     extends JDKAlgorithmParameterGenerator
++    // {
++    //     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 = new SecureRandom();
++    //         }
++    //
++    //         random.nextBytes(iv);
++    //
++    //         AlgorithmParameters params;
++    //
++    //         try
++    //         {
++    //             params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
++    //             params.init(new IvParameterSpec(iv));
++    //         }
++    //         catch (Exception e)
++    //         {
++    //             throw new RuntimeException(e.getMessage());
++    //         }
++    //
++    //         return params;
++    //     }
++    // }
++    //
++    // public static class RC2
++    //     extends JDKAlgorithmParameterGenerator
++    // {
++    //     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 = new SecureRandom();
++    //             }
++    //
++    //             random.nextBytes(iv);
++    //
++    //             try
++    //             {
++    //                 params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
++    //                 params.init(new IvParameterSpec(iv));
++    //             }
++    //             catch (Exception e)
++    //             {
++    //                 throw new RuntimeException(e.getMessage());
++    //             }
++    //         }
++    //         else
++    //         {
++    //             try
++    //             {
++    //                 params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
++    //                 params.init(spec);
++    //             }
++    //             catch (Exception e)
++    //             {
++    //                 throw new RuntimeException(e.getMessage());
++    //             }
++    //         }
++    //
++    //         return params;
++    //     }
++    // }
++    // END android-removed
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java	2011-09-08 21:28:49.000000000 +0000
 @@ -10,21 +10,27 @@
  import org.bouncycastle.asn1.DERObjectIdentifier;
  import org.bouncycastle.asn1.DEROctetString;
@@ -10026,12 +6828,12 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKDSASigner.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKDSASigner.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKDSASigner.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKDSASigner.java	2011-09-03 18:25:17.000000000 +0000
-@@ -22,13 +22,17 @@
- import org.bouncycastle.crypto.DSA;
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKDSASigner.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKDSASigner.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKDSASigner.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKDSASigner.java	2011-09-08 21:28:49.000000000 +0000
+@@ -23,13 +23,17 @@
  import org.bouncycastle.crypto.Digest;
+ import org.bouncycastle.crypto.digests.NullDigest;
  import org.bouncycastle.crypto.digests.SHA1Digest;
 -import org.bouncycastle.crypto.digests.SHA224Digest;
 +// BEGIN android-removed
@@ -10046,9 +6848,9 @@
 +// BEGIN android-removed
 +// import org.bouncycastle.jce.interfaces.GOST3410Key;
 +// END android-removed
- import org.bouncycastle.jce.provider.util.NullDigest;
  
  public class JDKDSASigner
+     extends SignatureSpi
 @@ -53,11 +57,16 @@
      {
          CipherParameters    param;
@@ -10177,10 +6979,10 @@
  
      static public class noneDSA
          extends JDKDSASigner
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKDigestSignature.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKDigestSignature.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKDigestSignature.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKDigestSignature.java	2011-09-03 18:25:17.000000000 +0000
-@@ -23,14 +23,20 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKDigestSignature.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKDigestSignature.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKDigestSignature.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKDigestSignature.java	2011-09-08 21:28:49.000000000 +0000
+@@ -23,15 +23,21 @@
  import org.bouncycastle.crypto.AsymmetricBlockCipher;
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.Digest;
@@ -10191,6 +6993,7 @@
 +// import org.bouncycastle.crypto.digests.MD4Digest;
 +// END android-removed
  import org.bouncycastle.crypto.digests.MD5Digest;
+ import org.bouncycastle.crypto.digests.NullDigest;
 -import org.bouncycastle.crypto.digests.RIPEMD128Digest;
 -import org.bouncycastle.crypto.digests.RIPEMD160Digest;
 -import org.bouncycastle.crypto.digests.RIPEMD256Digest;
@@ -10207,32 +7010,6 @@
  import org.bouncycastle.crypto.digests.SHA256Digest;
  import org.bouncycastle.crypto.digests.SHA384Digest;
  import org.bouncycastle.crypto.digests.SHA512Digest;
-@@ -179,13 +185,13 @@
-                 }
-             }
-         }
--        else if (sig.length == expected.length - 2)  // NULL left out
-+        else if (expected.length == sig.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;
-+            sig[1] -= 2;      // adjust lengths
-+            sig[3] -= 2;
- 
-             for (int i = 0; i < hash.length; i++)
-             {
-@@ -195,7 +201,7 @@
-                 }
-             }
- 
--            for (int i = 0; i < sigOffset; i++)
-+            for (int i = 0; i < expectedOffset; i++)
-             {
-                 if (sig[i] != expected[i])  // check header less NULL
-                 {
 @@ -265,14 +271,16 @@
          }
      }
@@ -10378,9 +7155,9 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyFactory.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyFactory.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyFactory.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyFactory.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyFactory.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyFactory.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyFactory.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyFactory.java	2011-09-08 21:28:49.000000000 +0000
 @@ -36,17 +36,21 @@
  import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
  import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
@@ -10545,7 +7322,7 @@
          else
          {
              throw new RuntimeException("algorithm identifier " + algOid + " in key not recognised");
-@@ -290,10 +321,12 @@
+@@ -294,10 +325,12 @@
          {
                return new JCEDHPrivateKey(info);
          }
@@ -10562,7 +7339,7 @@
          else if (algOid.equals(X9ObjectIdentifiers.id_dsa))
          {
                return new JDKDSAPrivateKey(info);
-@@ -302,14 +335,16 @@
+@@ -306,14 +339,16 @@
          {
                return new JCEECPrivateKey(info);
          }
@@ -10587,7 +7364,7 @@
          else
          {
              throw new RuntimeException("algorithm identifier " + algOid + " in key not recognised");
-@@ -440,89 +475,92 @@
+@@ -444,89 +479,92 @@
          }
      }
  
@@ -10764,9 +7541,9 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java	2011-09-08 21:28:49.000000000 +0000
 @@ -6,9 +6,11 @@
  import org.bouncycastle.crypto.generators.DHParametersGenerator;
  import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
@@ -11108,9 +7885,9 @@
 +   // }
 +   // END android-removed
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyStore.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyStore.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKKeyStore.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKKeyStore.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyStore.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyStore.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKKeyStore.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKKeyStore.java	2011-09-08 21:28:49.000000000 +0000
 @@ -39,7 +39,12 @@
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.Digest;
@@ -11211,9 +7988,9 @@
 -    }
 +    }    
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKMessageDigest.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKMessageDigest.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKMessageDigest.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKMessageDigest.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKMessageDigest.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKMessageDigest.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKMessageDigest.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKMessageDigest.java	2011-09-08 21:28:49.000000000 +0000
 @@ -57,36 +57,38 @@
          {
              super(new SHA1Digest());
@@ -11658,10 +8435,10 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java	2011-09-03 18:25:17.000000000 +0000
-@@ -255,10 +255,13 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java	2011-09-08 21:28:49.000000000 +0000
+@@ -260,10 +260,13 @@
              }
          }
  
@@ -11679,7 +8456,7 @@
      }
  
      /**
-@@ -433,6 +436,14 @@
+@@ -438,6 +441,14 @@
      
      public Date engineGetCreationDate(String alias) 
      {
@@ -11694,7 +8471,7 @@
          return new Date();
      }
  
-@@ -491,6 +502,11 @@
+@@ -496,6 +507,11 @@
          Certificate[]   chain) 
          throws KeyStoreException
      {
@@ -11706,7 +8483,7 @@
          if ((key instanceof PrivateKey) && (chain == null))
          {
              throw new KeyStoreException("no certificate chain for private key");
-@@ -502,12 +518,18 @@
+@@ -507,12 +523,18 @@
          }
  
          keys.put(alias, key);
@@ -11725,7 +8502,7 @@
      }
  
      public int engineSize() 
-@@ -1434,7 +1456,9 @@
+@@ -1488,7 +1510,9 @@
          {
              byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount, password, false, data);
  
@@ -11736,7 +8513,7 @@
              DigestInfo              dInfo = new DigestInfo(algId, res);
  
              mData = new MacData(dInfo, mSalt, itCount);
-@@ -1484,32 +1508,34 @@
+@@ -1545,32 +1569,34 @@
          }
      }
  
@@ -11797,7 +8574,7 @@
  
      private static class IgnoresCaseHashtable
      {
-@@ -1518,7 +1544,7 @@
+@@ -1579,7 +1605,7 @@
  
          public void put(String key, Object value)
          {
@@ -11806,7 +8583,7 @@
              String k = (String)keys.get(lower);
              if (k != null)
              {
-@@ -1536,7 +1562,9 @@
+@@ -1597,7 +1623,9 @@
  
          public Object remove(String alias)
          {
@@ -11817,7 +8594,7 @@
              if (k == null)
              {
                  return null;
-@@ -1547,7 +1575,9 @@
+@@ -1608,7 +1636,9 @@
  
          public Object get(String alias)
          {
@@ -11828,9 +8605,9 @@
              if (k == null)
              {
                  return null;
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PBE.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PBE.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PBE.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PBE.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PBE.java bcprov-jdk16-146/org/bouncycastle/jce/provider/PBE.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PBE.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/PBE.java	2011-09-08 21:28:49.000000000 +0000
 @@ -7,12 +7,18 @@
  
  import org.bouncycastle.crypto.CipherParameters;
@@ -11903,152 +8680,9 @@
                  case SHA256:
                      generator = new PKCS12ParametersGenerator(new SHA256Digest());
                      break;
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java	2011-09-03 18:25:17.000000000 +0000
-@@ -1,6 +1,9 @@
- package org.bouncycastle.jce.provider;
- 
- import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
-+// BEGIN android-added
-+import org.bouncycastle.asn1.OrderedTable;
-+// END android-added
- import org.bouncycastle.asn1.DERObjectIdentifier;
- import org.bouncycastle.asn1.DEREncodable;
- import org.bouncycastle.asn1.ASN1OutputStream;
-@@ -17,65 +20,73 @@
- class PKCS12BagAttributeCarrierImpl
-     implements PKCS12BagAttributeCarrier
- {
--    private Hashtable pkcs12Attributes;
--    private Vector pkcs12Ordering;
--
--    PKCS12BagAttributeCarrierImpl(Hashtable attributes, Vector ordering)
--    {
--        this.pkcs12Attributes = attributes;
--        this.pkcs12Ordering = ordering;
--    }
-+    // BEGIN android-changed
-+    private OrderedTable pkcs12 = new OrderedTable();
-+    // END android-changed
-+
-+    // BEGIN android-removed
-+    // PKCS12BagAttributeCarrierImpl(Hashtable attributes, Vector ordering)
-+    // {
-+    //     this.pkcs12Attributes = attributes;
-+    //     this.pkcs12Ordering = ordering;
-+    // }
-+    // END android-removed
- 
-     public PKCS12BagAttributeCarrierImpl()
-     {
--        this(new Hashtable(), new Vector());
-+        // BEGIN android-removed
-+        // this(new Hashtable(), new Vector());
-+        // END android-removed
-     }
- 
-     public void setBagAttribute(
-         DERObjectIdentifier oid,
-         DEREncodable        attribute)
-     {
--        if (pkcs12Attributes.containsKey(oid))
--        {                           // preserve original ordering
--            pkcs12Attributes.put(oid, attribute);
--        }
--        else
--        {
--            pkcs12Attributes.put(oid, attribute);
--            pkcs12Ordering.addElement(oid);
--        }
-+        // BEGIN android-changed
-+        // preserve original ordering
-+        pkcs12.put(oid, attribute);
-+        // END android-changed
-     }
- 
-     public DEREncodable getBagAttribute(
-         DERObjectIdentifier oid)
-     {
--        return (DEREncodable)pkcs12Attributes.get(oid);
-+        // BEGIN android-changed
-+        return (DEREncodable)pkcs12.get(oid);
-+        // END android-changed
-     }
- 
-     public Enumeration getBagAttributeKeys()
-     {
--        return pkcs12Ordering.elements();
-+        // BEGIN android-changed
-+        return pkcs12.getKeys();
-+        // END android-changed
-     }
- 
-     int size()
-     {
--        return pkcs12Ordering.size();
--    }
--
--    Hashtable getAttributes()
--    {
--        return pkcs12Attributes;
--    }
--
--    Vector getOrdering()
--    {
--        return pkcs12Ordering;
--    }
-+        // BEGIN android-changed
-+        return pkcs12.size();
-+        // END android-changed
-+    }
-+
-+    // BEGIN android-removed
-+    // Hashtable getAttributes()
-+    // {
-+    //     return pkcs12Attributes;
-+    // }
-+    //
-+    // Vector getOrdering()
-+    // {
-+    //     return pkcs12Ordering;
-+    // }
-+    // END android-removed
- 
-     public void writeObject(ObjectOutputStream out)
-         throws IOException
-     {
--        if (pkcs12Ordering.size() == 0)
-+        if (pkcs12.size() == 0)
-         {
-             out.writeObject(new Hashtable());
-             out.writeObject(new Vector());
-@@ -92,7 +103,7 @@
-                 DERObjectIdentifier    oid = (DERObjectIdentifier)e.nextElement();
- 
-                 aOut.writeObject(oid);
--                aOut.writeObject(pkcs12Attributes.get(oid));
-+                aOut.writeObject(pkcs12.get(oid));
-             }
- 
-             out.writeObject(bOut.toByteArray());
-@@ -106,8 +117,11 @@
- 
-         if (obj instanceof Hashtable)
-         {
--            this.pkcs12Attributes = (Hashtable)obj;
--            this.pkcs12Ordering = (Vector)in.readObject();
-+            // BEGIN android-changed
-+            // we only write out Hashtable/Vector in empty case
-+            in.readObject(); // consume empty Vector
-+            this.pkcs12 = new OrderedTable();
-+            // END android-changed
-         }
-         else
-         {
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPath.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPath.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPath.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPath.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXCertPath.java bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXCertPath.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXCertPath.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXCertPath.java	2011-09-08 21:28:49.000000000 +0000
 @@ -33,7 +33,9 @@
  import org.bouncycastle.asn1.pkcs.ContentInfo;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
@@ -12111,24 +8745,9 @@
          else
          {
              throw new CertificateEncodingException("unsupported encoding: " + encoding);
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java	2011-09-03 18:25:17.000000000 +0000
-@@ -172,8 +172,9 @@
-         try
-         {
-             // check whether the issuer of <tbvCert> is a TrustAnchor
--            if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams.getTrustAnchors(),
--                pkixParams.getSigProvider()) != null)
-+            // BEGIN android-changed
-+            if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams) != null)
-+                // END android-changed
-             {
-                 // exception message from possibly later tried certification
-                 // chains
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2011-09-08 21:28:49.000000000 +0000
 @@ -1,5 +1,8 @@
  package org.bouncycastle.jce.provider;
  
@@ -12146,14 +8765,7 @@
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
-@@ -20,9 +24,17 @@
- 
- import javax.security.auth.x500.X500Principal;
- 
-+// BEGIN android-added
-+import org.apache.harmony.xnet.provider.jsse.IndexedPKIXParameters;
-+
-+// END android-added
+@@ -23,6 +27,10 @@
  import org.bouncycastle.asn1.DEREncodable;
  import org.bouncycastle.asn1.DERObjectIdentifier;
  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -12164,7 +8776,7 @@
  import org.bouncycastle.jce.exception.ExtCertPathValidatorException;
  import org.bouncycastle.x509.ExtendedPKIXParameters;
  
-@@ -33,6 +45,63 @@
+@@ -33,6 +41,63 @@
  public class PKIXCertPathValidatorSpi
          extends CertPathValidatorSpi
  {
@@ -12228,26 +8840,7 @@
  
      public CertPathValidatorResult engineValidate(
              CertPath certPath,
-@@ -46,6 +115,18 @@
-                     + " instance.");
-         }
- 
-+        // BEGIN android-added
-+        IndexedPKIXParameters indexedParams;
-+        if (params instanceof IndexedPKIXParameters)
-+        {
-+            indexedParams = (IndexedPKIXParameters)params;
-+        }
-+        else
-+        {
-+            indexedParams = null;
-+        }
-+
-+        // END android-added
-         ExtendedPKIXParameters paramsPKIX;
-         if (params instanceof ExtendedPKIXParameters)
-         {
-@@ -75,6 +156,22 @@
+@@ -75,6 +140,22 @@
          {
              throw new CertPathValidatorException("Certification path is empty.", null, certPath, 0);
          }
@@ -12270,19 +8863,7 @@
  
          //
          // (b)
-@@ -92,8 +189,10 @@
-         TrustAnchor trust;
-         try
-         {
-+            // BEGIN android-changed
-             trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
--                    paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider());
-+                    indexedParams != null ? indexedParams : paramsPKIX);
-+            // END android-changed
-         }
-         catch (AnnotatedException e)
-         {
-@@ -251,6 +350,15 @@
+@@ -251,6 +332,15 @@
  
          for (index = certs.size() - 1; index >= 0; index--)
          {
@@ -12298,9 +8879,9 @@
              // try
              // {
              //
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java	2011-09-08 21:28:49.000000000 +0000
 @@ -1533,7 +1533,9 @@
          for (Enumeration e = permitted.getObjects(); e.hasMoreElements();)
          {
@@ -12312,23 +8893,10 @@
              if (subtreesMap.get(tagNo) == null)
              {
                  subtreesMap.put(tagNo, new HashSet());
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/WrapCipherSpi.java bcprov-jdk16-145/org/bouncycastle/jce/provider/WrapCipherSpi.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/WrapCipherSpi.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/WrapCipherSpi.java	2011-09-03 18:25:17.000000000 +0000
-@@ -12,8 +12,10 @@
- import org.bouncycastle.crypto.Wrapper;
- import org.bouncycastle.crypto.engines.DESedeEngine;
- import org.bouncycastle.crypto.engines.DESedeWrapEngine;
--import org.bouncycastle.crypto.engines.RC2WrapEngine;
--import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.engines.RC2WrapEngine;
-+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
-+// END android-removed
- import org.bouncycastle.crypto.params.KeyParameter;
- import org.bouncycastle.crypto.params.ParametersWithIV;
- 
-@@ -25,8 +27,10 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/WrapCipherSpi.java bcprov-jdk16-146/org/bouncycastle/jce/provider/WrapCipherSpi.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/WrapCipherSpi.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/WrapCipherSpi.java	2011-09-08 21:28:49.000000000 +0000
+@@ -22,8 +22,10 @@
  import javax.crypto.ShortBufferException;
  import javax.crypto.spec.IvParameterSpec;
  import javax.crypto.spec.PBEParameterSpec;
@@ -12339,9 +8907,20 @@
 +// import javax.crypto.spec.RC5ParameterSpec;
 +// END android-removed
  import javax.crypto.spec.SecretKeySpec;
- import java.security.AlgorithmParameters;
- import java.security.InvalidAlgorithmParameterException;
-@@ -52,8 +56,10 @@
+ 
+ import org.bouncycastle.asn1.ASN1InputStream;
+@@ -36,7 +38,9 @@
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.InvalidCipherTextException;
+ import org.bouncycastle.crypto.Wrapper;
+-import org.bouncycastle.crypto.engines.RC2WrapEngine;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.engines.RC2WrapEngine;
++// END android-removed
+ import org.bouncycastle.crypto.params.KeyParameter;
+ import org.bouncycastle.crypto.params.ParametersWithIV;
+ 
+@@ -50,8 +54,10 @@
                                      {
                                          IvParameterSpec.class,
                                          PBEParameterSpec.class,
@@ -12354,7 +8933,7 @@
                                      };
  
      protected int                     pbeType = PKCS12;
-@@ -265,16 +271,19 @@
+@@ -263,16 +269,19 @@
          return null;
      }
  
@@ -12375,7 +8954,7 @@
  
      protected byte[] engineWrap(
          Key     key)
-@@ -307,7 +316,12 @@
+@@ -305,7 +314,12 @@
          byte[]  wrappedKey,
          String  wrappedKeyAlgorithm,
          int     wrappedKeyType)
@@ -12389,7 +8968,7 @@
      {
          byte[] encoded;
          try
-@@ -358,10 +372,12 @@
+@@ -356,10 +370,12 @@
                  {
                      privKey = new JCEECPrivateKey(in);
                  }
@@ -12406,7 +8985,7 @@
                  else if (oid.equals(X9ObjectIdentifiers.id_dsa))
                  {
                      privKey = new JDKDSAPrivateKey(in);
-@@ -405,10 +421,12 @@
+@@ -403,10 +419,12 @@
              {
                  throw new InvalidKeyException("Unknown key type " + e.getMessage());
              }
@@ -12423,9 +9002,9 @@
              catch (InvalidKeySpecException e2)
              {
                  throw new InvalidKeyException("Unknown key type " + e2.getMessage());
-@@ -433,21 +451,23 @@
-         }
-     }
+@@ -420,12 +438,14 @@
+     // classes that inherit directly from us
+     //
  
 -    public static class RC2Wrap
 -        extends WrapCipherSpi
@@ -12435,15 +9014,6 @@
 -            super(new RC2WrapEngine());
 -        }
 -    }
--
--    public static class RFC3211DESedeWrap
--        extends WrapCipherSpi
--    {
--        public RFC3211DESedeWrap()
--        {
--            super(new RFC3211WrapEngine(new DESedeEngine()), 8);
--        }
--    }
 +    // BEGIN android-removed
 +    // public static class RC2Wrap
 +    //     extends WrapCipherSpi
@@ -12453,21 +9023,12 @@
 +    //         super(new RC2WrapEngine());
 +    //     }
 +    // }
-+    //
-+    // public static class RFC3211DESedeWrap
-+    //     extends WrapCipherSpi
-+    // {
-+    //     public RFC3211DESedeWrap()
-+    //     {
-+    //         super(new RFC3211WrapEngine(new DESedeEngine()), 8);
-+    //     }
-+    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/X509CertificateObject.java bcprov-jdk16-145/org/bouncycastle/jce/provider/X509CertificateObject.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/X509CertificateObject.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/X509CertificateObject.java	2011-09-03 18:25:17.000000000 +0000
-@@ -518,12 +518,20 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/X509CertificateObject.java bcprov-jdk16-146/org/bouncycastle/jce/provider/X509CertificateObject.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/X509CertificateObject.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/X509CertificateObject.java	2011-09-08 21:28:49.000000000 +0000
+@@ -520,12 +520,20 @@
          return JDKKeyFactory.createPublicKeyFromPublicKeyInfo(c.getSubjectPublicKeyInfo());
      }
  
@@ -12489,7 +9050,7 @@
          }
          catch (IOException e)
          {
-@@ -703,7 +711,7 @@
+@@ -711,7 +719,7 @@
      {
          Signature   signature;
          String      sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
@@ -12497,10 +9058,10 @@
 +
          try
          {
-             signature = Signature.getInstance(sigName, "BC");
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java bcprov-jdk16-145/org/bouncycastle/jce/provider/X509SignatureUtil.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/X509SignatureUtil.java	2011-09-03 18:25:17.000000000 +0000
+             signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java bcprov-jdk16-146/org/bouncycastle/jce/provider/X509SignatureUtil.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/X509SignatureUtil.java	2011-09-08 21:28:49.000000000 +0000
 @@ -25,7 +25,9 @@
  
  class X509SignatureUtil
@@ -12591,9 +9152,9 @@
          else
          {
              return digestAlgOID.getId();            
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ECMappings.java bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ECMappings.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ECMappings.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ECMappings.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/EC.java bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/EC.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/EC.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/EC.java	2011-09-08 21:28:49.000000000 +0000
 @@ -4,8 +4,10 @@
  
  import org.bouncycastle.asn1.DERObjectIdentifier;
@@ -12606,122 +9167,126 @@
 +// END android-removed
  import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
  
- public class ECMappings
-@@ -14,39 +16,49 @@
-     public ECMappings()
-     {
-         put("KeyAgreement.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DH");
--        put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
--        put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
--        put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
--        put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
-+        // BEGIN android-removed
-+        // put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
-+        // put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
-+        // put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
-+        // put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
-+        // END android-removed
+ public class EC
+@@ -16,39 +18,49 @@
+         public Mappings()
+         {
+             put("KeyAgreement.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DH");
+-            put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
+-            put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
+-            put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
+-            put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
++            // BEGIN android-removed
++            // put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
++            // put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
++            // put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
++            // put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
++            // END android-removed
  
-         put("KeyFactory.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$EC");
--        put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
--        put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
--        put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
--        put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
-+        // BEGIN android-removed
-+        // put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
-+        // put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
-+        // put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
-+        // put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
-+        // END android-removed
-         put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.id_ecPublicKey, "EC");
-         // TODO Should this be an alias for ECDH?
-         put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
--        put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
- 
--        put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
--        put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
--        put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
--        put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
-+        // put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
-+        // put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
-+        // put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
-+        // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
-+        // END android-removed
- 
-         put("KeyPairGenerator.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$EC");
--        put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
--        put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
--        put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
--        put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
--        put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
-+        // BEGIN android-removed
-+        // put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
-+        // put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
-+        // put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
-+        // put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
-+        // put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
-+        // END android-removed
-         // TODO Should this be an alias for ECDH?
-         put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
--        put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
- 
--        put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
--        put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
--        put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
-+        // put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
-+        // put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
-+        // put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
-+        // END android-removed
- 
-         put("Signature.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA");
-         put("Signature.NONEwithECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSAnone");
-@@ -58,23 +70,27 @@
-         put("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA");
-         put("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA");
-         put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
--        put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
-+        // BEGIN android-removed
-+        // put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
- 
--        addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
-+        // addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
-+        // END android-removed
-         addSignatureAlgorithm("SHA256", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
-         addSignatureAlgorithm("SHA384", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
-         addSignatureAlgorithm("SHA512", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
--        addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
-+        // BEGIN android-removed
-+        // addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
- 
--        put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
--        put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
--        put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
--        put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
--        put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
+             put("KeyFactory.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$EC");
+-            put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
+-            put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
+-            put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
+-            put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
++            // BEGIN android-removed
++            // put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
++            // put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
++            // put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
++            // put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
++            // END android-removed
+             put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.id_ecPublicKey, "EC");
+             // TODO Should this be an alias for ECDH?
+             put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+-            put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
 -
--        addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
--        addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
--        addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
-+        // put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
-+        // put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
-+        // put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
-+        // put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
-+        // put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
-+
-+        // addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
-+        // addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
-+        // addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
-+        // END android-removed
-     }
+-            put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
+-            put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
+-            put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
+-            put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
++            // BEGIN android-removed
++            // put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
++            //
++            // put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
++            // put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
++            // put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
++            // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
++            // END android-removed
  
-     private void addSignatureAlgorithm(
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java	2011-09-03 18:25:17.000000000 +0000
+             put("KeyPairGenerator.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$EC");
+-            put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
+-            put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
+-            put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
+-            put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
+-            put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
++            // BEGIN android-removed
++            // put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
++            // put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
++            // put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
++            // put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
++            // put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
++            // END android-removed
+             // TODO Should this be an alias for ECDH?
+             put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+-            put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
+-
+-            put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
+-            put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
+-            put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
++            // BEGIN android-removed
++            // put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
++            //
++            // put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
++            // put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
++            // put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
++            // END android-removed
+ 
+             put("Signature.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA");
+             put("Signature.NONEwithECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSAnone");
+@@ -60,23 +72,27 @@
+             put("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA");
+             put("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA");
+             put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
+-            put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
+-
+-            addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
++            // BEGIN android-removed
++            // put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
++            //
++            // addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
++            // END android-removed
+             addSignatureAlgorithm("SHA256", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
+             addSignatureAlgorithm("SHA384", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
+             addSignatureAlgorithm("SHA512", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
+-            addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
+-
+-            put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
+-            put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
+-            put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
+-            put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
+-            put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
+-
+-            addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
+-            addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
+-            addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
++            // BEGIN android-removed
++            // addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
++            //
++            // put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
++            // put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
++            // put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
++            // put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
++            // put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
++            //
++            // addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
++            // addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
++            // addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
++            // END android-removed
+         }
+ 
+         private void addSignatureAlgorithm(
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/ECUtil.java	2011-09-08 21:28:49.000000000 +0000
 @@ -1,10 +1,14 @@
  package org.bouncycastle.jce.provider.asymmetric.ec;
  
@@ -12806,9 +9371,9 @@
          }
  
          return name;
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java	2011-09-08 21:28:49.000000000 +0000
 @@ -24,20 +24,26 @@
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.DerivationFunction;
@@ -12844,7 +9409,22 @@
  
  /**
   * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
-@@ -70,7 +76,9 @@
+@@ -53,9 +59,11 @@
+ 
+     static
+     {
+-        Integer i128 = new Integer(128);
+-        Integer i192 = new Integer(192);
+-        Integer i256 = new Integer(256);
++        // BEGIN android-changed
++        Integer i128 = Integer.valueOf(128);
++        Integer i192 = Integer.valueOf(192);
++        Integer i256 = Integer.valueOf(256);
++        // END android-changed
+ 
+         algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
+         algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
+@@ -70,7 +78,9 @@
      private BigInteger             result;
      private ECDomainParameters     parameters;
      private BasicAgreement         agreement;
@@ -12855,7 +9435,7 @@
  
      private byte[] bigIntToBytes(
          BigInteger    r)
-@@ -85,7 +93,9 @@
+@@ -85,7 +95,9 @@
      {
          this.kaAlgorithm = kaAlgorithm;
          this.agreement = agreement;
@@ -12866,7 +9446,7 @@
      }
  
      protected Key engineDoPhase(
-@@ -104,25 +114,27 @@
+@@ -104,25 +116,27 @@
          }
  
          CipherParameters pubKey;        
@@ -12913,7 +9493,7 @@
          {
              if (!(key instanceof ECPublicKey))
              {
-@@ -143,11 +155,13 @@
+@@ -143,11 +157,13 @@
      protected byte[] engineGenerateSecret()
          throws IllegalStateException
      {
@@ -12932,7 +9512,7 @@
  
          return bigIntToBytes(result);
      }
-@@ -175,23 +189,25 @@
+@@ -175,23 +191,25 @@
      {
          byte[] secret = bigIntToBytes(result);
  
@@ -12975,7 +9555,7 @@
          {
              // TODO Should we be ensuring the key is the right length?
          }
-@@ -219,35 +235,37 @@
+@@ -219,35 +237,37 @@
      private void initFromKey(Key key)
          throws InvalidKeyException
      {
@@ -13042,7 +9622,7 @@
          {
              if (!(key instanceof ECPrivateKey))
              {
-@@ -278,39 +296,41 @@
+@@ -278,39 +298,41 @@
          }
      }
  
@@ -13119,9 +9699,9 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java	2011-09-08 21:28:49.000000000 +0000
 @@ -10,10 +10,14 @@
  import java.util.Hashtable;
  
@@ -13139,7 +9719,30 @@
  import org.bouncycastle.asn1.x9.X962NamedCurves;
  import org.bouncycastle.asn1.x9.X9ECParameters;
  import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
-@@ -83,7 +87,13 @@
+@@ -56,13 +60,15 @@
+         static {
+             ecParameters = new Hashtable();
+ 
+-            ecParameters.put(new Integer(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
+-            ecParameters.put(new Integer(239), new ECGenParameterSpec("prime239v1"));
+-            ecParameters.put(new Integer(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
+-
+-            ecParameters.put(new Integer(224), new ECGenParameterSpec("P-224"));
+-            ecParameters.put(new Integer(384), new ECGenParameterSpec("P-384"));
+-            ecParameters.put(new Integer(521), new ECGenParameterSpec("P-521"));
++            // BEGIN android-changed
++            ecParameters.put(Integer.valueOf(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
++            ecParameters.put(Integer.valueOf(239), new ECGenParameterSpec("prime239v1"));
++            ecParameters.put(Integer.valueOf(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
++
++            ecParameters.put(Integer.valueOf(224), new ECGenParameterSpec("P-224"));
++            ecParameters.put(Integer.valueOf(384), new ECGenParameterSpec("P-384"));
++            ecParameters.put(Integer.valueOf(521), new ECGenParameterSpec("P-521"));
++            // END android-changed
+         }
+ 
+         public EC()
+@@ -83,8 +89,16 @@
              SecureRandom    random)
          {
              this.strength = strength;
@@ -13147,13 +9750,17 @@
 +            if (random != null) {
 +            // END android-added
              this.random = random;
+-            this.ecParams = ecParameters.get(new Integer(strength));
 +            // BEGIN android-added
 +            }
 +            // END android-added
-             this.ecParams = ecParameters.get(new Integer(strength));
++            // BEGIN android-changed
++            this.ecParams = ecParameters.get(Integer.valueOf(strength));
++            // END android-changed
  
              if (ecParams != null)
-@@ -108,6 +118,11 @@
+             {
+@@ -108,6 +122,11 @@
              SecureRandom            random)
              throws InvalidAlgorithmParameterException
          {
@@ -13165,7 +9772,7 @@
              if (params instanceof ECParameterSpec)
              {
                  ECParameterSpec p = (ECParameterSpec)params;
-@@ -135,23 +150,25 @@
+@@ -135,23 +154,25 @@
              {
                  final String curveName = ((ECGenParameterSpec)params).getName();
  
@@ -13208,7 +9815,7 @@
                  {
                      X9ECParameters  ecP = X962NamedCurves.getByName(curveName);
                      if (ecP == null)
-@@ -161,10 +178,12 @@
+@@ -161,10 +182,12 @@
                          {
                              ecP = NISTNamedCurves.getByName(curveName);
                          }
@@ -13225,7 +9832,7 @@
                          if (ecP == null)
                          {
                              // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
-@@ -180,10 +199,12 @@
+@@ -180,10 +203,12 @@
                                  {
                                      ecP = NISTNamedCurves.getByOID(oid);
                                  }
@@ -13242,7 +9849,7 @@
                                  if (ecP == null)
                                  {
                                      throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
-@@ -239,7 +260,15 @@
+@@ -239,7 +264,15 @@
          {
              if (!initialised)
              {
@@ -13259,7 +9866,7 @@
              }
  
              AsymmetricCipherKeyPair     pair = engine.generateKeyPair();
-@@ -279,14 +308,16 @@
+@@ -279,14 +312,16 @@
          }
      }
  
@@ -13284,20 +9891,20 @@
  
      public static class ECDH
          extends EC
-@@ -314,4 +345,4 @@
+@@ -314,4 +349,4 @@
              super("ECMQV");
          }
      }
 -}
 \ No newline at end of file
 +}
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java	2011-09-08 21:28:49.000000000 +0000
 @@ -18,15 +18,21 @@
- import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.DSA;
  import org.bouncycastle.crypto.Digest;
+ import org.bouncycastle.crypto.digests.NullDigest;
 -import org.bouncycastle.crypto.digests.RIPEMD160Digest;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
@@ -13319,7 +9926,7 @@
  import org.bouncycastle.jce.interfaces.ECKey;
  import org.bouncycastle.jce.provider.DSABase;
  import org.bouncycastle.jce.provider.DSAEncoder;
-@@ -123,14 +129,16 @@
+@@ -122,14 +128,16 @@
          }
      }
  
@@ -13344,7 +9951,7 @@
  
      static public class ecDSA256
          extends Signature
-@@ -159,86 +167,88 @@
+@@ -158,86 +166,88 @@
          }
      }
  
@@ -13513,28 +10120,30 @@
  
      private static class StdDSAEncoder
          implements DSAEncoder
-@@ -332,4 +342,4 @@
+@@ -331,4 +341,4 @@
              return sig;
          }
      }
 -}
 \ No newline at end of file
 +}
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/symmetric/AES.java bcprov-jdk16-145/org/bouncycastle/jce/provider/symmetric/AES.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/symmetric/AES.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/symmetric/AES.java	2011-09-03 18:25:17.000000000 +0000
-@@ -5,7 +5,9 @@
- import org.bouncycastle.crypto.engines.AESEngine;
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/AES.java bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/AES.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/AES.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/AES.java	2011-09-08 21:28:49.000000000 +0000
+@@ -13,8 +13,10 @@
+ import org.bouncycastle.crypto.CipherKeyGenerator;
  import org.bouncycastle.crypto.engines.AESFastEngine;
  import org.bouncycastle.crypto.engines.AESWrapEngine;
 -import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+-import org.bouncycastle.crypto.macs.CMac;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
++// import org.bouncycastle.crypto.macs.CMac;
 +// END android-removed
  import org.bouncycastle.crypto.modes.CBCBlockCipher;
  import org.bouncycastle.crypto.modes.CFBBlockCipher;
  import org.bouncycastle.crypto.modes.OFBBlockCipher;
-@@ -36,32 +38,34 @@
+@@ -41,41 +43,43 @@
          }
      }
  
@@ -13564,6 +10173,15 @@
 -            super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128);
 -        }
 -    }
+-
+-    public static class AESCMAC
+-        extends JCEMac
+-    {
+-        public AESCMAC()
+-        {
+-            super(new CMac(new AESFastEngine()));
+-        }
+-    }
 +    // BEGIN android-removed
 +    // public static class CBC
 +    //    extends JCEBlockCipher
@@ -13591,11 +10209,20 @@
 +    //         super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128);
 +    //     }
 +    // }
++    //
++    // public static class AESCMAC
++    //     extends JCEMac
++    // {
++    //     public AESCMAC()
++    //     {
++    //         super(new CMac(new AESFastEngine()));
++    //     }
++    // }
 +    // END android-removed
  
      static public class Wrap
          extends WrapCipherSpi
-@@ -72,14 +76,16 @@
+@@ -86,14 +90,16 @@
          }
      }
  
@@ -13604,7 +10231,7 @@
 -    {
 -        public RFC3211Wrap()
 -        {
--            super(new RFC3211WrapEngine(new AESEngine()), 16);
+-            super(new RFC3211WrapEngine(new AESFastEngine()), 16);
 -        }
 -    }
 +    // BEGIN android-removed
@@ -13613,14 +10240,14 @@
 +    // {
 +    //     public RFC3211Wrap()
 +    //     {
-+    //         super(new RFC3211WrapEngine(new AESEngine()), 16);
++    //         super(new RFC3211WrapEngine(new AESFastEngine()), 16);
 +    //     }
 +    // }
 +    // END android-removed
  
      public static class KeyGen
          extends JCEKeyGenerator
-@@ -95,70 +101,72 @@
+@@ -109,70 +115,72 @@
          }
      }
  
@@ -13677,7 +10304,7 @@
 -
 -            try
 -            {
--                params = AlgorithmParameters.getInstance("AES", "BC");
+-                params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
 -                params.init(new IvParameterSpec(iv));
 -            }
 -            catch (Exception e)
@@ -13742,7 +10369,7 @@
 +    //
 +    //         try
 +    //         {
-+    //             params = AlgorithmParameters.getInstance("AES", "BC");
++    //             params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
 +    //             params.init(new IvParameterSpec(iv));
 +    //         }
 +    //         catch (Exception e)
@@ -13757,116 +10384,332 @@
  
      public static class AlgParams
          extends JDKAlgorithmParameters.IVAlgorithmParameters
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/symmetric/AESMappings.java bcprov-jdk16-145/org/bouncycastle/jce/provider/symmetric/AESMappings.java
---- bcprov-jdk16-145.orig/org/bouncycastle/jce/provider/symmetric/AESMappings.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/jce/provider/symmetric/AESMappings.java	2011-09-03 18:25:17.000000000 +0000
-@@ -26,55 +26,63 @@
-         put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
-         put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+@@ -205,58 +213,66 @@
+             put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+             put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
  
--        put("AlgorithmParameterGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParamGen");
--        put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
--        put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
--        put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
--        put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
--        put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
--        put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
-+        // BEGIN android-removed
-+        // put("AlgorithmParameterGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParamGen");
-+        // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
-+        // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
-+        // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
-+        // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
-+        // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
-+        // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
-+        // END android-removed
+-            put("AlgorithmParameterGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParamGen");
+-            put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
+-            put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
+-            put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
+-            put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+-            put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+-            put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
++            // BEGIN android-removed
++            // put("AlgorithmParameterGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParamGen");
++            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
++            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
++            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
++            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
++            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
++            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
++            // END android-removed
  
-         put("Cipher.AES", "org.bouncycastle.jce.provider.symmetric.AES$ECB");
-         put("Alg.Alias.Cipher." + wrongAES128, "AES");
-         put("Alg.Alias.Cipher." + wrongAES192, "AES");
-         put("Alg.Alias.Cipher." + wrongAES256, "AES");
--        put("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
--        put("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
--        put("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
--        put("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
--        put("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
--        put("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
--        put("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
--        put("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
--        put("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
--        put("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
--        put("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
--        put("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
-+        // BEGIN android-changed
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_ECB, "AES");
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_ECB, "AES");
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_ECB, "AES");
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_OFB, "AES");
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_OFB, "AES");
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_OFB, "AES");
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_CFB, "AES");
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_CFB, "AES");
-+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_CFB, "AES");
-+        // END android-changed
-         put("Cipher.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$Wrap");
-         put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
-         put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
-         put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
--        put("Cipher.AESRFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.AES$RFC3211Wrap");
-+        // BEGIN android-removed
-+        // put("Cipher.AESRFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.AES$RFC3211Wrap");
-+        // END android-removed
+             put("Cipher.AES", "org.bouncycastle.jce.provider.symmetric.AES$ECB");
+             put("Alg.Alias.Cipher." + wrongAES128, "AES");
+             put("Alg.Alias.Cipher." + wrongAES192, "AES");
+             put("Alg.Alias.Cipher." + wrongAES256, "AES");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
+-            put("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
++            // BEGIN android-removed
++            // put("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
++            // put("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
++            // put("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
++            // put("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
++            // put("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
++            // put("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
++            // put("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
++            // put("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
++            // put("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
++            // put("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
++            // put("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
++            // put("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
++            // END android-removed
+             put("Cipher.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$Wrap");
+             put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
+             put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
+             put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
+-            put("Cipher.AESRFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.AES$RFC3211Wrap");
++            // BEGIN android-removed
++            // put("Cipher.AESRFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.AES$RFC3211Wrap");
++            // END android-removed
  
-         put("KeyGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
--        put("KeyGenerator.2.16.840.1.101.3.4.2", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--        put("KeyGenerator.2.16.840.1.101.3.4.22", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--        put("KeyGenerator.2.16.840.1.101.3.4.42", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
--        put("KeyGenerator.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
--        put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+        // BEGIN android-removed
-+        // put("KeyGenerator.2.16.840.1.101.3.4.2", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+        // put("KeyGenerator.2.16.840.1.101.3.4.22", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+        // put("KeyGenerator.2.16.840.1.101.3.4.42", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+        // put("KeyGenerator.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-+        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-+        // END android-removed
+             put("KeyGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
+-            put("KeyGenerator.2.16.840.1.101.3.4.2", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+-            put("KeyGenerator.2.16.840.1.101.3.4.22", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+-            put("KeyGenerator.2.16.840.1.101.3.4.42", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+-            put("KeyGenerator.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+-            put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+-
+-            put("Mac.AESCMAC", "org.bouncycastle.jce.provider.symmetric.AES$AESCMAC");
++            // BEGIN android-removed
++            // put("KeyGenerator.2.16.840.1.101.3.4.2", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
++            // put("KeyGenerator.2.16.840.1.101.3.4.22", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
++            // put("KeyGenerator.2.16.840.1.101.3.4.42", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
++            // put("KeyGenerator.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
++            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
++            //
++            // put("Mac.AESCMAC", "org.bouncycastle.jce.provider.symmetric.AES$AESCMAC");
++            // END android-removed
+         }
      }
  }
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/x509/X509Util.java bcprov-jdk16-145/org/bouncycastle/x509/X509Util.java
---- bcprov-jdk16-145.orig/org/bouncycastle/x509/X509Util.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/x509/X509Util.java	2011-09-03 18:25:17.000000000 +0000
-@@ -43,8 +43,10 @@
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/ARC4.java bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/ARC4.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/ARC4.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/ARC4.java	2011-09-08 21:28:49.000000000 +0000
+@@ -27,7 +27,9 @@
+     {
+         public KeyGen()
+         {
+-            super("RC4", 128, new CipherKeyGenerator());
++            // BEGIN android-changed
++            super("ARC4", 128, new CipherKeyGenerator());
++            // END android-changed
+         }
+     }
+ 
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/Blowfish.java bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/Blowfish.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/Blowfish.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/Blowfish.java	2011-09-08 21:28:49.000000000 +0000
+@@ -57,7 +57,9 @@
+         public Mappings()
+         {
+             put("Cipher.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$ECB");
+-            put("Cipher.1.3.6.1.4.1.3029.1.2", "org.bouncycastle.jce.provider.symmetric.Blowfish$CBC");
++            // BEGIN android-removed
++            // put("Cipher.1.3.6.1.4.1.3029.1.2", "org.bouncycastle.jce.provider.symmetric.Blowfish$CBC");
++            // END android-removed
+             put("KeyGenerator.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$KeyGen");
+             put("Alg.Alias.KeyGenerator.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
+             put("AlgorithmParameters.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$AlgParams");
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/DESede.java bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/DESede.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/jce/provider/symmetric/DESede.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/jce/provider/symmetric/DESede.java	2011-09-08 21:28:49.000000000 +0000
+@@ -14,11 +14,15 @@
+ import org.bouncycastle.crypto.KeyGenerationParameters;
+ import org.bouncycastle.crypto.engines.DESedeEngine;
+ import org.bouncycastle.crypto.engines.DESedeWrapEngine;
+-import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
++// END android-removed
+ import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
+ import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+-import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+-import org.bouncycastle.crypto.macs.CMac;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
++// import org.bouncycastle.crypto.macs.CMac;
++// END android-removed
+ import org.bouncycastle.crypto.modes.CBCBlockCipher;
+ import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+ import org.bouncycastle.jce.provider.JCEBlockCipher;
+@@ -51,17 +55,19 @@
+         }
+     }
+ 
+-    /**
+-     * DESede   CFB8
+-     */
+-    public static class DESedeCFB8
+-        extends JCEMac
+-    {
+-        public DESedeCFB8()
+-        {
+-            super(new CFBBlockCipherMac(new DESedeEngine()));
+-        }
+-    }
++    // BEGIN android-removed
++    // /**
++    //  * DESede   CFB8
++    //  */
++    // public static class DESedeCFB8
++    //     extends JCEMac
++    // {
++    //     public DESedeCFB8()
++    //     {
++    //         super(new CFBBlockCipherMac(new DESedeEngine()));
++    //     }
++    // }
++    // END android-removed
+ 
+     /**
+      * DESede64
+@@ -96,14 +102,16 @@
+         }
+     }
+ 
+-    static public class CMAC
+-        extends JCEMac
+-    {
+-        public CMAC()
+-        {
+-            super(new CMac(new DESedeEngine()));
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class CMAC
++    //     extends JCEMac
++    // {
++    //     public CMAC()
++    //     {
++    //         super(new CMac(new DESedeEngine()));
++    //     }
++    // }
++    // END android-removed
+ 
+     public static class Wrap
+         extends WrapCipherSpi
+@@ -114,14 +122,16 @@
+         }
+     }
+ 
+-    public static class RFC3211
+-        extends WrapCipherSpi
+-    {
+-        public RFC3211()
+-        {
+-            super(new RFC3211WrapEngine(new DESedeEngine()), 8);
+-        }
+-    }
++    // BEGIN android-removed
++    // public static class RFC3211
++    //     extends WrapCipherSpi
++    // {
++    //     public RFC3211()
++    //     {
++    //         super(new RFC3211WrapEngine(new DESedeEngine()), 8);
++    //     }
++    // }
++    // END android-removed
+ 
+   /**
+      * DESede - the default for this is to generate a key in
+@@ -262,32 +272,42 @@
+         public Mappings()
+         {
+             put("Cipher.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$ECB");
+-            put("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
+-            put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
++            // BEGIN android-removed
++            // put("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
++            // put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
++            // END android-removed
+             put("Cipher.DESEDEWRAP", "org.bouncycastle.jce.provider.symmetric.DESede$Wrap");
+-            put("Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "org.bouncycastle.jce.provider.symmetric.DESede$Wrap");
+-            put("Cipher.DESEDERFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.DESede$RFC3211");
++            // BEGIN android-changed
++            put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWRAP");
++            // END android-changed
++            // BEGIN android-removed
++            // put("Cipher.DESEDERFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.DESede$RFC3211");
++            // END android-removed
+ 
+             put("KeyGenerator.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator");
+-            put("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator3");
+-            put("KeyGenerator.DESEDEWRAP", "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator");
++            // BEGIN android-removed
++            // put("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator3");
++            // put("KeyGenerator.DESEDEWRAP", "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator");
++            // END android-removed
+ 
+             put("SecretKeyFactory.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$KeyFactory");
+ 
+-            put("Mac.DESEDECMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CMAC");
+-            put("Mac.DESEDEMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CBCMAC");
+-            put("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
+-
+-            put("Mac.DESEDEMAC/CFB8", "org.bouncycastle.jce.provider.symmetric.DESede$DESedeCFB8");
+-            put("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
+-
+-            put("Mac.DESEDEMAC64", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64");
+-            put("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
+-
+-            put("Mac.DESEDEMAC64WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64with7816d4");
+-            put("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+-            put("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+-            put("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
++            // BEGIN android-removed
++            // put("Mac.DESEDECMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CMAC");
++            // put("Mac.DESEDEMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CBCMAC");
++            // put("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
++            //
++            // put("Mac.DESEDEMAC/CFB8", "org.bouncycastle.jce.provider.symmetric.DESede$DESedeCFB8");
++            // put("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
++            //
++            // put("Mac.DESEDEMAC64", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64");
++            // put("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
++            //
++            // put("Mac.DESEDEMAC64WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64with7816d4");
++            // put("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
++            // put("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
++            // put("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
++            // END android-removed
+         }
+     }
+ }
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/openssl/PEMUtilities.java bcprov-jdk16-146/org/bouncycastle/openssl/PEMUtilities.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/openssl/PEMUtilities.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/openssl/PEMUtilities.java	2011-09-08 21:28:50.000000000 +0000
+@@ -45,10 +45,12 @@
+         PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC);
+         PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC);
+ 
+-        KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), new Integer(192));
+-        KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), new Integer(128));
+-        KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), new Integer(192));
+-        KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), new Integer(256));
++        // BEGIN android-changed
++        KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integer.valueOf(192));
++        KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integer.valueOf(128));
++        KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integer.valueOf(192));
++        KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integer.valueOf(256));
++        // END android-changed
+     }
+ 
+     static int getKeySize(String algorithm)
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/x509/X509Util.java bcprov-jdk16-146/org/bouncycastle/x509/X509Util.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/x509/X509Util.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/x509/X509Util.java	2011-09-08 21:28:50.000000000 +0000
+@@ -44,14 +44,18 @@
      
      static
      {   
@@ -13879,7 +10722,103 @@
          algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
          algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
          algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
-@@ -106,19 +108,29 @@
+         algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+-        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+-        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
++        // BEGIN android-removed
++        // algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
++        // algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
++        // END android-removed
+         algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+         algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+         algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+@@ -59,45 +63,59 @@
+         algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+         algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+         algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+-        algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
++        // BEGIN android-removed
++        // algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
++        // END android-removed
+         algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+         algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+         algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+-        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);
++        // BEGIN android-removed
++        // 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
+         algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+         algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+-        algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
++        // BEGIN android-removed
++        // algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
++        // END android-removed
+         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);
++        // BEGIN android-removed
++        // algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
++        // END android-removed
+         algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+         algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+         algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+-        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);
++        // BEGIN android-removed
++        // 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
+ 
+         //
+         // 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);
++        // BEGIN android-removed
++        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
++        // END android-removed
+         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);
++        // BEGIN android-removed
++        // noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
++        // END android-removed
+         noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+         noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
+         noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
+@@ -105,25 +123,39 @@
+         //
+         // RFC 4491
+         //
+-        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+-        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
++        // BEGIN android-removed
++        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
++        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
++        // END android-removed
+ 
          //
          // explicit params
          //
@@ -13890,12 +10829,16 @@
          params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
  
 -        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, new DERNull());
-+        // BEGIN android-changed
-+        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
-+        // END android-changed
-         params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
- 
+-        params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+-
 -        AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, new DERNull());
++        // BEGIN android-removed
++        // // BEGIN android-changed
++        // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
++        // // END android-changed
++        // params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
++        // END android-removed
++
 +        // BEGIN android-changed
 +        AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
 +        // END android-changed
@@ -13914,7 +10857,7 @@
          params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
      }
  
-@@ -161,7 +173,9 @@
+@@ -166,7 +198,9 @@
          }
          else
          {
@@ -13925,9 +10868,9 @@
          }
      }
      
-diff -Naur bcprov-jdk16-145.orig/org/bouncycastle/x509/extension/X509ExtensionUtil.java bcprov-jdk16-145/org/bouncycastle/x509/extension/X509ExtensionUtil.java
---- bcprov-jdk16-145.orig/org/bouncycastle/x509/extension/X509ExtensionUtil.java	2010-01-11 21:46:14.000000000 +0000
-+++ bcprov-jdk16-145/org/bouncycastle/x509/extension/X509ExtensionUtil.java	2011-09-03 18:25:17.000000000 +0000
+diff -Naur bcprov-jdk16-146.orig/org/bouncycastle/x509/extension/X509ExtensionUtil.java bcprov-jdk16-146/org/bouncycastle/x509/extension/X509ExtensionUtil.java
+--- bcprov-jdk16-146.orig/org/bouncycastle/x509/extension/X509ExtensionUtil.java	2011-02-23 20:08:56.000000000 +0000
++++ bcprov-jdk16-146/org/bouncycastle/x509/extension/X509ExtensionUtil.java	2011-09-08 21:28:50.000000000 +0000
 @@ -62,7 +62,9 @@
              {
                  GeneralName genName = GeneralName.getInstance(it.nextElement());
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java b/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java
index 83bc39d..f87064f 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java
@@ -3,7 +3,7 @@
 import java.io.IOException;
 
 public interface ASN1ApplicationSpecificParser
-    extends DEREncodable
+    extends DEREncodable, InMemoryRepresentable
 {
     DEREncodable readObject()
         throws IOException;
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Collection.java b/src/main/java/org/bouncycastle/asn1/ASN1Collection.java
deleted file mode 100644
index aa17d3c..0000000
--- a/src/main/java/org/bouncycastle/asn1/ASN1Collection.java
+++ /dev/null
@@ -1,298 +0,0 @@
-package org.bouncycastle.asn1;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.Enumeration;
-import java.util.ConcurrentModificationException;
-
-// BEGIN android-note
-/*
- * This is a new class that was synthesized from ASN1Sequence and
- * ASN1Set, but with extra smarts about efficiently storing its
- * elements.
- */
-// END android-note
-
-/**
- * Base class for collection-like <code>DERObject</code>s. Instances
- * of this class will keep up to four elements directly, resorting to
- * an external collection only if more elements than that need to be
- * stored.
- */
-public abstract class ASN1Collection
-    extends ASN1Object
-{
-    /** &gt;= 0; size of the collection */
-    private int size;
-
-    /** null-ok; element #0 */
-    private DEREncodable obj0;
-
-    /** null-ok; element #1 */
-    private DEREncodable obj1;
-
-    /** null-ok; element #2 */
-    private DEREncodable obj2;
-
-    /** null-ok; element #3 */
-    private DEREncodable obj3;
-
-    /** null-ok; elements #4 and higher */
-    private DEREncodable[] rest;
-
-    /**
-     * Returns the object at the postion indicated by index.
-     *
-     * @param index the index (starting at zero) of the object
-     * @return the object at the postion indicated by index
-     */
-    public DEREncodable getObjectAt(int index) {
-        if ((index < 0) || (index >= size)) {
-            throw new IndexOutOfBoundsException(Integer.toString(index));
-        }
-                    
-        switch (index) {
-            case 0: return obj0;
-            case 1: return obj1;
-            case 2: return obj2;
-            case 3: return obj3;
-            default: return rest[index - 4];
-        }
-    }
-
-    /**
-     * Returns the number of objects in this instance.
-     *
-     * @return the number of objects in this instance
-     */
-    public int size() {
-        return size;
-    }
-
-    /** {@inheritDoc} */
-    public final int hashCode() {
-        Enumeration e = this.getObjects();
-        int hashCode = 0;
-
-        while (e.hasMoreElements()) {
-            Object o = e.nextElement();
-            
-            if (o != null) {
-                hashCode ^= o.hashCode();
-            }
-        }
-
-        return hashCode;
-    }
-
-    /**
-     * Adds a new element to this instance.
-     * 
-     * @param obj non-null; the instance to add
-     */
-    protected void addObject(DEREncodable obj) {
-        if (obj == null) {
-            throw new NullPointerException("obj == null");
-        }
-
-        int sz = size;
-        
-        switch (sz) {
-            case 0: obj0 = obj; break;
-            case 1: obj1 = obj; break;
-            case 2: obj2 = obj; break;
-            case 3: obj3 = obj; break;
-            case 4: {
-                // Initial allocation of rest.
-                rest = new DEREncodable[5];
-                rest[0] = obj;
-                break;
-            }
-            default: {
-                int index = sz - 4;
-                if (index >= rest.length) {
-                    // Grow rest.
-                    DEREncodable[] newRest = new DEREncodable[index * 2 + 10];
-                    System.arraycopy(rest, 0, newRest, 0, rest.length);
-                    rest = newRest;
-                }
-                rest[index] = obj;
-                break;
-            }
-        }
-
-        size++;
-    }
-
-    /**
-     * Sets the element at a given index (used by {@link #sort}).
-     * 
-     * @param obj non-null; the object to set
-     * @param index &gt;= 0; the index
-     */
-    private void setObjectAt(DEREncodable obj, int index) {
-        switch (index) {
-            case 0: obj0 = obj; break;
-            case 1: obj1 = obj; break;
-            case 2: obj2 = obj; break;
-            case 3: obj3 = obj; break;
-            default: {
-                rest[index - 4] = obj;
-                break;
-            }
-        }
-    }
-
-    /**
-     * Encodes this instance to the given stream.
-     * 
-     * @param out non-null; stream to encode to
-     */
-    /*package*/ abstract void encode(DEROutputStream out) throws IOException;
-
-    /**
-     * Gets an enumeration of all the objects in this collection.
-     * 
-     * @return non-null; the enumeration
-     */
-    public Enumeration getObjects() {
-        return new ASN1CollectionEnumeration();
-    }
-
-    /**
-     * Associated enumeration class.
-     */
-    private class ASN1CollectionEnumeration implements Enumeration {
-        /** original size; used for modification detection */
-        private final int origSize = size;
-
-        /** &gt;= 0; current cursor */
-        private int at = 0;
-
-        /** {@inheritDoc} */
-        public boolean hasMoreElements() {
-            if (size != origSize) {
-                throw new ConcurrentModificationException();
-            }
-
-            return at < origSize;
-        }
-
-        /** {@inheritDoc} */
-        public Object nextElement() {
-            if (size != origSize) {
-                throw new ConcurrentModificationException();
-            }
-
-            switch (at++) {
-                case 0: return obj0;
-                case 1: return obj1;
-                case 2: return obj2;
-                case 3: return obj3;
-                default: return rest[at - 5];
-            }
-        }
-    }
-
-    /**
-     * Sorts the elements in this instance.
-     */
-    protected void sort() {
-        if (size <= 1) {
-            return;
-        }
-
-        boolean swapped = true;
-
-        // TODO: This is bubble sort. Probably not the best choice.
-        while (swapped) {
-            int index = 0;
-            byte[] a = getEncoded(getObjectAt(0));
-                
-            swapped = false;
-                
-            while (index != size - 1) {
-                int nextIndex = index + 1;
-                byte[] b = getEncoded(getObjectAt(nextIndex));
-
-                if (lessThanOrEqual(a, b)) {
-                    a = b;
-                } else {
-                    DEREncodable o = getObjectAt(index);
-                    
-                    setObjectAt(getObjectAt(nextIndex), index);
-                    setObjectAt(o, nextIndex);
-
-                    swapped = true;
-                }
-
-                index++;
-            }
-        }
-    }
-    
-    /**
-     * Returns true if a <= b (arrays are assumed padded with zeros).
-     */
-    private static boolean lessThanOrEqual(byte[] a, byte[] b) {
-        if (a.length <= b.length) {
-            for (int i = 0; i != a.length; i++) {
-                int l = a[i] & 0xff;
-                int r = b[i] & 0xff;
-                 
-                if (r > l) {
-                    return true;
-                } else if (l > r) {
-                    return false;
-                }
-            }
-
-            return true;
-        } else {
-            for (int i = 0; i != b.length; i++) {
-                 int l = a[i] & 0xff;
-                 int r = b[i] & 0xff;
-                 
-                 if (r > l) {
-                     return true;
-                 } else if (l > r) {
-                     return false;
-                 }
-             }
-
-             return false;
-         }
-    }
-
-    /**
-     * Gets the encoded form of an object.
-     * 
-     * @param obj non-null; object to encode
-     * @return non-null; the encoded form
-     */
-    private static byte[] getEncoded(DEREncodable obj) {
-        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-        ASN1OutputStream aOut = new ASN1OutputStream(bOut);
-
-        try {
-            aOut.writeObject(obj);
-        } catch (IOException e) {
-            throw new IllegalArgumentException(
-                    "cannot encode object added to collection");
-        }
-
-        return bOut.toByteArray();
-    }
-
-    /** {@inheritDoc} */
-    public final String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append('[');
-        for (int i = 0; i < size; i++) {
-            if (i != 0) sb.append(", ");
-            sb.append(getObjectAt(i));
-        }
-        sb.append(']');
-        return sb.toString();
-    }
-}
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java b/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java
index 1f50ddf..3f736e4 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java
@@ -1,14 +1,32 @@
 package org.bouncycastle.asn1;
 
+import java.util.Vector;
+
 /**
  * the parent class for this will eventually disappear. Use this one!
  */
 public class ASN1EncodableVector
     extends DEREncodableVector
 {
-    // migrating from DEREncodeableVector
+    Vector v = new Vector();
+
     public ASN1EncodableVector()
     {
-        
+
+    }
+
+    public void add(DEREncodable obj)
+    {
+        v.addElement(obj);
+    }
+
+    public DEREncodable get(int i)
+    {
+        return (DEREncodable)v.elementAt(i);
+    }
+
+    public int size()
+    {
+        return v.size();
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java b/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java
new file mode 100644
index 0000000..d93fd91
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.asn1;
+
+import java.math.BigInteger;
+
+public class ASN1Enumerated
+    extends DEREnumerated
+{
+    ASN1Enumerated(byte[] bytes)
+    {
+        super(bytes);
+    }
+
+    public ASN1Enumerated(BigInteger value)
+    {
+        super(value);
+    }
+
+    public ASN1Enumerated(int value)
+    {
+        super(value);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Exception.java b/src/main/java/org/bouncycastle/asn1/ASN1Exception.java
new file mode 100644
index 0000000..dc0ee20
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Exception.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class ASN1Exception
+    extends IOException
+{
+    private Throwable cause;
+
+    ASN1Exception(String message)
+    {
+        super(message);
+    }
+
+    ASN1Exception(String message, Throwable cause)
+    {
+        super(message);
+        this.cause = cause;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java b/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java
new file mode 100644
index 0000000..0088a53
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.asn1;
+
+import java.util.Date;
+
+public class ASN1GeneralizedTime
+    extends DERGeneralizedTime
+{
+    ASN1GeneralizedTime(byte[] bytes)
+    {
+        super(bytes);
+    }
+
+    public ASN1GeneralizedTime(Date time)
+    {
+        super(time);
+    }
+
+    public ASN1GeneralizedTime(String time)
+    {
+        super(time);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java b/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
index 05f0664..fb27edd 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
@@ -21,10 +21,24 @@
     private final int limit;
     private final boolean lazyEvaluate;
 
+    static int findLimit(InputStream in)
+    {
+        if (in instanceof LimitedInputStream)
+        {
+            return ((LimitedInputStream)in).getRemaining();
+        }
+        else if (in instanceof ByteArrayInputStream)
+        {
+            return ((ByteArrayInputStream)in).available();
+        }
+
+        return Integer.MAX_VALUE;
+    }
+
     public ASN1InputStream(
         InputStream is)
     {
-        this(is, Integer.MAX_VALUE);
+        this(is, findLimit(is));
     }
 
     /**
@@ -120,7 +134,7 @@
 
         if ((tag & TAGGED) != 0)
         {
-            return new BERTaggedObjectParser(tag, tagNo, defIn).getDERObject();
+            return new ASN1StreamParser(defIn).readTaggedObject(isConstructed, tagNo);
         }
 
         if (isConstructed)
@@ -207,39 +221,44 @@
                 throw new IOException("indefinite length primitive encoding encountered");
             }
 
-            IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this);
+            IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit);
+            ASN1StreamParser sp = new ASN1StreamParser(indIn, limit);
 
             if ((tag & APPLICATION) != 0)
             {
-                ASN1StreamParser sp = new ASN1StreamParser(indIn, limit);
-
-                return new BERApplicationSpecificParser(tagNo, sp).getDERObject();
+                return new BERApplicationSpecificParser(tagNo, sp).getLoadedObject();
             }
+
             if ((tag & TAGGED) != 0)
             {
-                return new BERTaggedObjectParser(tag, tagNo, indIn).getDERObject();
+                return new BERTaggedObjectParser(true, tagNo, sp).getLoadedObject();
             }
 
-            ASN1StreamParser sp = new ASN1StreamParser(indIn, limit);
-
             // TODO There are other tags that may be constructed (e.g. BIT_STRING)
             switch (tagNo)
             {
                 case OCTET_STRING:
-                    return new BEROctetStringParser(sp).getDERObject();
+                    return new BEROctetStringParser(sp).getLoadedObject();
                 case SEQUENCE:
-                    return new BERSequenceParser(sp).getDERObject();
+                    return new BERSequenceParser(sp).getLoadedObject();
                 case SET:
-                    return new BERSetParser(sp).getDERObject();
+                    return new BERSetParser(sp).getLoadedObject();
                 case EXTERNAL:
-                    return new DERExternalParser(sp).getDERObject();
+                    return new DERExternalParser(sp).getLoadedObject();
                 default:
                     throw new IOException("unknown BER object encountered");
             }
         }
         else
         {
-            return buildObject(tag, tagNo, length);
+            try
+            {
+                return buildObject(tag, tagNo, length);
+            }
+            catch (IllegalArgumentException e)
+            {
+                throw new ASN1Exception("corrupted stream detected", e);
+            }
         }
     }
 
@@ -300,6 +319,7 @@
         {
             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);
@@ -339,12 +359,7 @@
         switch (tagNo)
         {
             case BIT_STRING:
-            {
-                int padBits = bytes[0];
-                byte[] data = new byte[bytes.length - 1];
-                System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
-                return new DERBitString(data, padBits);
-            }
+                return DERBitString.fromOctetString(bytes);
             case BMP_STRING:
                 return new DERBMPString(bytes);
             case BOOLEAN:
@@ -352,21 +367,21 @@
                 return DERBoolean.getInstance(bytes);
                 // END android-changed
             case ENUMERATED:
-                return new DEREnumerated(bytes);
+                return new ASN1Enumerated(bytes);
             case GENERALIZED_TIME:
-                return new DERGeneralizedTime(bytes);
+                return new ASN1GeneralizedTime(bytes);
             case GENERAL_STRING:
                 return new DERGeneralString(bytes);
             case IA5_STRING:
                 return new DERIA5String(bytes);
             case INTEGER:
-                return new DERInteger(bytes);
+                return new ASN1Integer(bytes);
             case NULL:
                 return DERNull.INSTANCE;   // actual content is ignored (enforce 0 length?)
             case NUMERIC_STRING:
                 return new DERNumericString(bytes);
             case OBJECT_IDENTIFIER:
-                return new DERObjectIdentifier(bytes);
+                return new ASN1ObjectIdentifier(bytes);
             case OCTET_STRING:
                 return new DEROctetString(bytes);
             case PRINTABLE_STRING:
@@ -376,7 +391,7 @@
             case UNIVERSAL_STRING:
                 return new DERUniversalString(bytes);
             case UTC_TIME:
-                return new DERUTCTime(bytes);
+                return new ASN1UTCTime(bytes);
             case UTF8_STRING:
                 return new DERUTF8String(bytes);
             case VISIBLE_STRING:
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Integer.java b/src/main/java/org/bouncycastle/asn1/ASN1Integer.java
new file mode 100644
index 0000000..71009a0
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Integer.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.asn1;
+
+import java.math.BigInteger;
+
+public class ASN1Integer
+    extends DERInteger
+{
+    ASN1Integer(byte[] bytes)
+    {
+        super(bytes);
+    }
+
+    public ASN1Integer(BigInteger value)
+    {
+        super(value);
+    }
+
+    public ASN1Integer(int value)
+    {
+        super(value);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Object.java b/src/main/java/org/bouncycastle/asn1/ASN1Object.java
index 7a0b113..7e9860a 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1Object.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Object.java
@@ -17,7 +17,14 @@
     {
         ASN1InputStream aIn = new ASN1InputStream(data);
 
-        return (ASN1Object)aIn.readObject();
+        try
+        {
+            return (ASN1Object)aIn.readObject();
+        }
+        catch (ClassCastException e)
+        {
+            throw new IOException("cannot recognise object in stream");    
+        }
     }
 
     public final boolean equals(Object o)
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
new file mode 100644
index 0000000..83b7c86
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.asn1;
+
+public class ASN1ObjectIdentifier
+    extends DERObjectIdentifier
+{
+    public ASN1ObjectIdentifier(String identifier)
+    {
+        super(identifier);
+    }
+
+    ASN1ObjectIdentifier(byte[] bytes)
+    {
+        super(bytes);
+    }
+
+    /**
+     * Return an OID that creates a branch under the current one.
+     *
+     * @param branchID node numbers for the new branch.
+     * @return
+     */
+    public ASN1ObjectIdentifier branch(String branchID)
+    {
+        return new ASN1ObjectIdentifier(getId() + "." + branchID);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1ObjectParser.java b/src/main/java/org/bouncycastle/asn1/ASN1ObjectParser.java
deleted file mode 100644
index ff09a45..0000000
--- a/src/main/java/org/bouncycastle/asn1/ASN1ObjectParser.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.bouncycastle.asn1;
-
-import java.io.InputStream;
-
-/**
- * @deprecated will be removed
- */
-public class ASN1ObjectParser
-{
-    ASN1StreamParser _aIn;
-
-    protected ASN1ObjectParser(
-        int         baseTag,
-        int         tagNumber,
-        InputStream contentStream)
-    {
-        _aIn = new ASN1StreamParser(contentStream);
-    }
-}
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java b/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
index b1d72a2..7d334d7 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
@@ -1,13 +1,11 @@
 package org.bouncycastle.asn1;
 
-import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.util.Arrays;
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Enumeration;
-import java.util.Vector;
+
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
 
 public abstract class ASN1OctetString
     extends ASN1Object
@@ -28,7 +26,16 @@
         ASN1TaggedObject    obj,
         boolean             explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof ASN1OctetString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return BERConstructedOctetString.fromSequence(ASN1Sequence.getInstance(o)); 
+        }
     }
     
     /**
@@ -45,24 +52,12 @@
             return (ASN1OctetString)obj;
         }
 
+        // TODO: this needs to be deleted in V2
         if (obj instanceof ASN1TaggedObject)
         {
             return getInstance(((ASN1TaggedObject)obj).getObject());
         }
 
-        if (obj instanceof ASN1Sequence)
-        {
-            Vector      v = new Vector();
-            Enumeration e = ((ASN1Sequence)obj).getObjects();
-
-            while (e.hasMoreElements())
-            {
-                v.addElement(e.nextElement());
-            }
-
-            return new BERConstructedOctetString(v);
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -125,6 +120,11 @@
         return Arrays.areEqual(string, other.string);
     }
 
+    public DERObject getLoadedObject()
+    {
+        return this.getDERObject();
+    }
+
     abstract void encode(DEROutputStream out)
         throws IOException;
 
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java b/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java
index 641020c..21a3941 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java
@@ -3,7 +3,7 @@
 import java.io.InputStream;
 
 public interface ASN1OctetStringParser
-    extends DEREncodable
+    extends DEREncodable, InMemoryRepresentable
 {
     public InputStream getOctetStream();
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java b/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java
index e31e673..b4a8072 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java
@@ -2,20 +2,12 @@
 
 import java.io.IOException;
 import java.util.Enumeration;
-// BEGIN android-removed
-// import java.util.Vector;
-// END android-removed
-
-// BEGIN android-note
-// Changed inheritence of class.
-// END android-note
+import java.util.Vector;
 
 public abstract class ASN1Sequence
-    extends ASN1Collection
+    extends ASN1Object
 {
-    // BEGIN android-removed
-    // private Vector seq = new Vector();
-    // END android-removed
+    private Vector seq = new Vector();
 
     /**
      * return an ASN1Sequence from the given object.
@@ -30,6 +22,17 @@
         {
             return (ASN1Sequence)obj;
         }
+        else if (obj instanceof byte[])
+        {
+            try
+            {
+                return ASN1Sequence.getInstance(ASN1Object.fromByteArray((byte[])obj));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
+            }
+        }
 
         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
     }
@@ -93,12 +96,10 @@
         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
     }
 
-    // BEGIN android-removed
-    // public Enumeration getObjects()
-    // {
-    //     return seq.elements();
-    // }
-    // END android-removed
+    public Enumeration getObjects()
+    {
+        return seq.elements();
+    }
 
     public ASN1SequenceParser parser()
     {
@@ -130,6 +131,11 @@
                 return obj;
             }
 
+            public DERObject getLoadedObject()
+            {
+                return outer;
+            }
+            
             public DERObject getDERObject()
             {
                 return outer;
@@ -137,47 +143,43 @@
         };
     }
 
-    // BEGIN android-removed
-    // /**
-    //  * 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 DEREncodable getObjectAt(
-    //     int index)
-    // {
-    //     return (DEREncodable)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 = e.nextElement();
-    //         hashCode *= 17;
-    //         if (o != null)
-    //         {
-    //             hashCode ^= o.hashCode();
-    //         }
-    //     }
-    //
-    //     return hashCode;
-    // }
-    // END android-removed
+    /**
+     * 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 DEREncodable getObjectAt(
+        int index)
+    {
+        return (DEREncodable)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(
         DERObject  o)
@@ -199,10 +201,13 @@
 
         while (s1.hasMoreElements())
         {
-            DERObject  o1 = ((DEREncodable)s1.nextElement()).getDERObject();
-            DERObject  o2 = ((DEREncodable)s2.nextElement()).getDERObject();
+            DEREncodable  obj1 = getNext(s1);
+            DEREncodable  obj2 = getNext(s2);
 
-            if (o1 == o2 || (o1 != null && o1.equals(o2)))
+            DERObject  o1 = obj1.getDERObject();
+            DERObject  o2 = obj2.getDERObject();
+
+            if (o1 == o2 || o1.equals(o2))
             {
                 continue;
             }
@@ -213,19 +218,30 @@
         return true;
     }
 
-    // BEGIN android-removed
-    //protected void addObject(
-    //    DEREncodable obj)
-    //{
-    //    seq.addElement(obj);
-    //}
+    private DEREncodable getNext(Enumeration e)
+    {
+        DEREncodable encObj = (DEREncodable)e.nextElement();
 
-    //abstract void encode(DEROutputStream out)
-    //    throws IOException;
+        // unfortunately null was allowed as a substitute for DER null
+        if (encObj == null)
+        {
+            return DERNull.INSTANCE;
+        }
 
-    //public String toString() 
-    //{
-    //  return seq.toString();
-    //}
-    // END android-removed
+        return encObj;
+    }
+
+    protected void addObject(
+        DEREncodable obj)
+    {
+        seq.addElement(obj);
+    }
+
+    abstract void encode(DEROutputStream out)
+        throws IOException;
+
+    public String toString() 
+    {
+      return seq.toString();
+    }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java b/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java
index ceda6bd..49dde79 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java
@@ -3,7 +3,7 @@
 import java.io.IOException;
 
 public interface ASN1SequenceParser
-    extends DEREncodable
+    extends DEREncodable, InMemoryRepresentable
 {
     DEREncodable readObject()
         throws IOException;
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1Set.java b/src/main/java/org/bouncycastle/asn1/ASN1Set.java
index 88a20ee..c395b8b 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1Set.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1Set.java
@@ -3,20 +3,12 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.Enumeration;
-// BEGIN android-removed
-// import java.util.Vector;
-// END android-removed
-
-// BEGIN android-note
-// Changed inheritence of class.
-// END android-note
+import java.util.Vector;
 
 abstract public class ASN1Set
-    extends ASN1Collection
+    extends ASN1Object
 {
-    // BEGIN android-removed
-    // protected Vector set = new Vector();
-    // END android-removed
+    protected Vector set = new Vector();
 
     /**
      * return an ASN1Set from the given object.
@@ -112,34 +104,44 @@
     {
     }
 
-    // BEGIN android-removed
-    // 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 DEREncodable getObjectAt(
-    //     int index)
-    // {
-    //     return (DEREncodable)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();
-    // }
-    // END android-removed
+    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 DEREncodable getObjectAt(
+        int index)
+    {
+        return (DEREncodable)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] = (ASN1Encodable)this.getObjectAt(i);
+        }
+
+        return values;
+    }
 
     public ASN1SetParser parser()
     {
@@ -171,6 +173,11 @@
                 return obj;
             }
 
+            public DERObject getLoadedObject()
+            {
+                return outer;
+            }
+
             public DERObject getDERObject()
             {
                 return outer;
@@ -178,25 +185,21 @@
         };
     }
 
-    // BEGIN android-removed
-    // public int hashCode()
-    // {
-    //     Enumeration             e = this.getObjects();
-    //     int                     hashCode = size();
-    //
-    //     while (e.hasMoreElements())
-    //     {
-    //         Object o = e.nextElement();
-    //         hashCode *= 17;
-    //         if (o != null)
-    //         {
-    //             hashCode ^= o.hashCode();
-    //         }
-    //     }
-    //
-    //     return hashCode;
-    // }
-    // END android-removed
+    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(
         DERObject  o)
@@ -218,10 +221,13 @@
 
         while (s1.hasMoreElements())
         {
-            DERObject  o1 = ((DEREncodable)s1.nextElement()).getDERObject();
-            DERObject  o2 = ((DEREncodable)s2.nextElement()).getDERObject();
+            DEREncodable  obj1 = getNext(s1);
+            DEREncodable  obj2 = getNext(s2);
 
-            if (o1 == o2 || (o1 != null && o1.equals(o2)))
+            DERObject  o1 = obj1.getDERObject();
+            DERObject  o2 = obj2.getDERObject();
+
+            if (o1 == o2 || o1.equals(o2))
             {
                 continue;
             }
@@ -232,54 +238,36 @@
         return true;
     }
 
-    // BEGIN android-removed
-    // /**
-    //  * return true if a <= b (arrays are assumed padded with zeros).
-    //  */
-    // private boolean lessThanOrEqual(
-    //      byte[] a,
-    //      byte[] b)
-    // {
-    //      if (a.length <= b.length)
-    //      {
-    //          for (int i = 0; i != a.length; i++)
-    //          {
-    //              int    l = a[i] & 0xff;
-    //              int    r = b[i] & 0xff;
-    //
-    //              if (r > l)
-    //              {
-    //                  return true;
-    //              }
-    //              else if (l > r)
-    //              {
-    //                  return false;
-    //              }
-    //          }
-    //
-    //          return true;
-    //      }
-    //      else
-    //      {
-    //          for (int i = 0; i != b.length; i++)
-    //          {
-    //              int    l = a[i] & 0xff;
-    //              int    r = b[i] & 0xff;
-    //
-    //              if (r > l)
-    //              {
-    //                  return true;
-    //              }
-    //              else if (l > r)
-    //              {
-    //                  return false;
-    //              }
-    //          }
-    //
-    //          return false;
-    //      }
-    // }
-    // END android-removed
+    private DEREncodable getNext(Enumeration e)
+    {
+        DEREncodable encObj = (DEREncodable)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[] getEncoded(
         DEREncodable obj)
@@ -299,61 +287,59 @@
         return bOut.toByteArray();
     }
 
-    // BEGIN android-removed
-    // protected void sort()
-    // {
-    //     if (set.size() > 1)
-    //     {
-    //         boolean    swapped = true;
-    //         int        lastSwap = set.size() - 1;
-    //
-    //         while (swapped)
-    //         {
-    //             int    index = 0;
-    //             int    swapIndex = 0;
-    //             byte[] a = getEncoded((DEREncodable)set.elementAt(0));
-    //
-    //             swapped = false;
-    //
-    //             while (index != lastSwap)
-    //             {
-    //                 byte[] b = getEncoded((DEREncodable)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;
-    //         }
-    //     }
-    // }
-    //
-    // protected void addObject(
-    //     DEREncodable obj)
-    // {
-    //     set.addElement(obj);
-    // }
-    //
-    // abstract void encode(DEROutputStream out)
-    //         throws IOException;
-    //
-    // public String toString() 
-    // {
-    //   return set.toString();
-    // }
-    // END android-removed
+    protected void sort()
+    {
+        if (set.size() > 1)
+        {
+            boolean    swapped = true;
+            int        lastSwap = set.size() - 1;
+
+            while (swapped)
+            {
+                int    index = 0;
+                int    swapIndex = 0;
+                byte[] a = getEncoded((DEREncodable)set.elementAt(0));
+                
+                swapped = false;
+
+                while (index != lastSwap)
+                {
+                    byte[] b = getEncoded((DEREncodable)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;
+            }
+        }
+    }
+
+    protected void addObject(
+        DEREncodable obj)
+    {
+        set.addElement(obj);
+    }
+
+    abstract void encode(DEROutputStream out)
+            throws IOException;
+
+    public String toString() 
+    {
+      return set.toString();
+    }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java b/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java
index b09a170..9dc99b5 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java
@@ -3,7 +3,7 @@
 import java.io.IOException;
 
 public interface ASN1SetParser
-    extends DEREncodable
+    extends DEREncodable, InMemoryRepresentable
 {
     public DEREncodable readObject()
         throws IOException;
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java b/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java
index 43fcad7..fbcb787 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java
@@ -9,20 +9,10 @@
     private final InputStream _in;
     private final int         _limit;
 
-    private static int findLimit(InputStream in)
-    {
-        if (in instanceof DefiniteLengthInputStream)
-        {
-            return ((DefiniteLengthInputStream)in).getRemaining();
-        }
-
-        return Integer.MAX_VALUE;
-    }
-
     public ASN1StreamParser(
         InputStream in)
     {
-        this(in, findLimit(in));
+        this(in, ASN1InputStream.findLimit(in));
     }
 
     public ASN1StreamParser(
@@ -39,6 +29,90 @@
         this(new ByteArrayInputStream(encoding), encoding.length);
     }
 
+    DEREncodable readIndef(int tagValue) throws IOException
+    {
+        // Note: INDEF => CONSTRUCTED
+
+        // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+        switch (tagValue)
+        {
+            case DERTags.EXTERNAL:
+                return new DERExternalParser(this);
+            case DERTags.OCTET_STRING:
+                return new BEROctetStringParser(this);
+            case DERTags.SEQUENCE:
+                return new BERSequenceParser(this);
+            case DERTags.SET:
+                return new BERSetParser(this);
+            default:
+                throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue));
+        }
+    }
+
+    DEREncodable 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 DERTags.SET:
+                    return new DERSetParser(this);
+                case DERTags.SEQUENCE:
+                    return new DERSequenceParser(this);
+                case DERTags.OCTET_STRING:
+                    return new BEROctetStringParser(this);
+            }
+        }
+        else
+        {
+            switch (tag)
+            {
+                case DERTags.SET:
+                    throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
+                case DERTags.SEQUENCE:
+                    throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
+                case DERTags.OCTET_STRING:
+                    return new DEROctetStringParser((DefiniteLengthInputStream)_in);
+            }
+        }
+
+        // TODO ASN1Exception
+        throw new RuntimeException("implicit tagging not implemented");
+    }
+
+    DERObject 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 DEREncodable readObject()
         throws IOException
     {
@@ -72,37 +146,20 @@
                 throw new IOException("indefinite length primitive encoding encountered");
             }
 
-            IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in);
+            IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
+            ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
 
             if ((tag & DERTags.APPLICATION) != 0)
             {
-                ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
-
                 return new BERApplicationSpecificParser(tagNo, sp);
             }
 
             if ((tag & DERTags.TAGGED) != 0)
             {
-                return new BERTaggedObjectParser(tag, tagNo, indIn);
+                return new BERTaggedObjectParser(true, tagNo, sp);
             }
 
-            ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
-
-            // TODO There are other tags that may be constructed (e.g. BIT_STRING)
-            switch (tagNo)
-            {
-                case DERTags.OCTET_STRING:
-                    return new BEROctetStringParser(sp);
-                case DERTags.SEQUENCE:
-                    return new BERSequenceParser(sp);
-                case DERTags.SET:
-                    return new BERSetParser(sp);
-                case DERTags.EXTERNAL:{
-                    return new DERExternalParser(sp);
-                }
-                default:
-                    throw new IOException("unknown BER object encountered: 0x" + Integer.toHexString(tagNo));
-            }
+            return sp.readIndef(tagNo);
         }
         else
         {
@@ -115,7 +172,7 @@
 
             if ((tag & DERTags.TAGGED) != 0)
             {
-                return new BERTaggedObjectParser(tag, tagNo, defIn);
+                return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn));
             }
 
             if (isConstructed)
@@ -147,7 +204,14 @@
                     return new DEROctetStringParser(defIn);
             }
 
-            return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn.toByteArray());
+            try
+            {
+                return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn.toByteArray());
+            }
+            catch (IllegalArgumentException e)
+            {
+                throw new ASN1Exception("corrupted stream detected", e);
+            }
         }
     }
 
@@ -166,7 +230,14 @@
         DEREncodable obj;
         while ((obj = readObject()) != null)
         {
-            v.add(obj.getDERObject());
+            if (obj instanceof InMemoryRepresentable)
+            {
+                v.add(((InMemoryRepresentable)obj).getLoadedObject());
+            }
+            else
+            {
+                v.add(obj.getDERObject());
+            }
         }
 
         return v;
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1String.java b/src/main/java/org/bouncycastle/asn1/ASN1String.java
new file mode 100644
index 0000000..fde4e23
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/ASN1String.java
@@ -0,0 +1,6 @@
+package org.bouncycastle.asn1;
+
+public interface ASN1String
+{
+    public String getString();
+}
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java b/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
index 1e5d4e8..8ee7960 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
@@ -200,6 +200,11 @@
         throw new RuntimeException("implicit tagging not implemented for tag: " + tag);
     }
 
+    public DERObject getLoadedObject()
+    {
+        return this.getDERObject();
+    }
+    
     abstract void encode(DEROutputStream  out)
         throws IOException;
 
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java b/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java
index 5574bf8..52f6087 100644
--- a/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java
+++ b/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java
@@ -3,7 +3,7 @@
 import java.io.IOException;
 
 public interface ASN1TaggedObjectParser
-    extends DEREncodable
+    extends DEREncodable, InMemoryRepresentable
 {
     public int getTagNo();
     
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java b/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java
new file mode 100644
index 0000000..d3816f2
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.asn1;
+
+import java.util.Date;
+
+public class ASN1UTCTime
+    extends DERUTCTime
+{
+    ASN1UTCTime(byte[] bytes)
+    {
+        super(bytes);
+    }
+
+    public ASN1UTCTime(Date time)
+    {
+        super(time);
+    }
+
+    public ASN1UTCTime(String time)
+    {
+        super(time);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java b/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java
index 0c46ba3..7b6aaaf 100644
--- a/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java
+++ b/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java
@@ -20,15 +20,22 @@
         return parser.readObject();
     }
 
+    public DERObject getLoadedObject()
+        throws IOException
+    {
+         return new BERApplicationSpecific(tag, parser.readVector());
+    }
+
     public DERObject getDERObject()
     {
         try
         {
-            return new BERApplicationSpecific(tag, parser.readVector());
+            return getLoadedObject();
         }
         catch (IOException e)
         {
             throw new ASN1ParsingException(e.getMessage(), e);
         }
     }
+
 }
diff --git a/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java b/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java
index 7e712c3..cceb241 100644
--- a/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java
+++ b/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java
@@ -141,4 +141,17 @@
             super.encode(out);
         }
     }
+
+    public static BERConstructedOctetString 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/src/main/java/org/bouncycastle/asn1/BERConstructedSequence.java b/src/main/java/org/bouncycastle/asn1/BERConstructedSequence.java
deleted file mode 100644
index 998eaeb..0000000
--- a/src/main/java/org/bouncycastle/asn1/BERConstructedSequence.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.bouncycastle.asn1;
-
-import java.io.IOException;
-import java.util.Enumeration;
-
-/**
- * @deprecated use BERSequence
- */
-public class BERConstructedSequence
-    extends DERConstructedSequence
-{
-    /*
-     */
-    void encode(
-        DEROutputStream out)
-        throws IOException
-    {
-        if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
-        {
-            out.write(SEQUENCE | CONSTRUCTED);
-            out.write(0x80);
-            
-            Enumeration e = getObjects();
-            while (e.hasMoreElements())
-            {
-                out.writeObject(e.nextElement());
-            }
-        
-            out.write(0x00);
-            out.write(0x00);
-        }
-        else
-        {
-            super.encode(out);
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/asn1/BERInputStream.java b/src/main/java/org/bouncycastle/asn1/BERInputStream.java
deleted file mode 100644
index 397fc06..0000000
--- a/src/main/java/org/bouncycastle/asn1/BERInputStream.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package org.bouncycastle.asn1;
-
-import java.io.ByteArrayOutputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Vector;
-
-/**
- * @deprecated use ASN1InputStream
- */
-public class BERInputStream
-    extends DERInputStream
-{
-    private static final DERObject END_OF_STREAM = new DERObject()
-    {
-                                        void encode(
-                                            DEROutputStream out)
-                                        throws IOException
-                                        {
-                                            throw new IOException("Eeek!");
-                                        }
-                                        public int hashCode()
-                                        {
-                                            return 0;
-                                        }
-                                        public boolean equals(
-                                            Object o) 
-                                        {
-                                            return o == this;
-                                        }
-                                    };
-    public BERInputStream(
-        InputStream is)
-    {
-        super(is);
-    }
-
-    /**
-     * read a string of bytes representing an indefinite length object.
-     */
-    private byte[] readIndefiniteLengthFully()
-        throws IOException
-    {
-        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
-        int                     b, b1;
-
-        b1 = read();
-
-        while ((b = read()) >= 0)
-        {
-            if (b1 == 0 && b == 0)
-            {
-                break;
-            }
-
-            bOut.write(b1);
-            b1 = b;
-        }
-
-        return bOut.toByteArray();
-    }
-
-    private BERConstructedOctetString buildConstructedOctetString()
-        throws IOException
-    {
-        Vector               octs = new Vector();
-
-        for (;;)
-        {
-            DERObject        o = readObject();
-
-            if (o == END_OF_STREAM)
-            {
-                break;
-            }
-
-            octs.addElement(o);
-        }
-
-        return new BERConstructedOctetString(octs);
-    }
-
-    public DERObject readObject()
-        throws IOException
-    {
-        int tag = read();
-        if (tag == -1)
-        {
-            throw new EOFException();
-        }
-    
-        int     length = readLength();
-
-        if (length < 0)    // indefinite length method
-        {
-            switch (tag)
-            {
-            case NULL:
-                return null;
-            case SEQUENCE | CONSTRUCTED:
-                BERConstructedSequence  seq = new BERConstructedSequence();
-    
-                for (;;)
-                {
-                    DERObject   obj = readObject();
-
-                    if (obj == END_OF_STREAM)
-                    {
-                        break;
-                    }
-
-                    seq.addObject(obj);
-                }
-                return seq;
-            case OCTET_STRING | CONSTRUCTED:
-                return buildConstructedOctetString();
-            case SET | CONSTRUCTED:
-                ASN1EncodableVector  v = new ASN1EncodableVector();
-    
-                for (;;)
-                {
-                    DERObject   obj = readObject();
-
-                    if (obj == END_OF_STREAM)
-                    {
-                        break;
-                    }
-
-                    v.add(obj);
-                }
-                return new BERSet(v);
-            default:
-                //
-                // with tagged object tag number is bottom 5 bits
-                //
-                if ((tag & TAGGED) != 0)  
-                {
-                    if ((tag & 0x1f) == 0x1f)
-                    {
-                        throw new IOException("unsupported high tag encountered");
-                    }
-
-                    //
-                    // simple type - implicit... return an octet string
-                    //
-                    if ((tag & CONSTRUCTED) == 0)
-                    {
-                        byte[]  bytes = readIndefiniteLengthFully();
-
-                        return new BERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes));
-                    }
-
-                    //
-                    // either constructed or explicitly tagged
-                    //
-                    DERObject        dObj = readObject();
-
-                    if (dObj == END_OF_STREAM)     // empty tag!
-                    {
-                        return new DERTaggedObject(tag & 0x1f);
-                    }
-
-                    DERObject       next = readObject();
-
-                    //
-                    // explicitly tagged (probably!) - if it isn't we'd have to
-                    // tell from the context
-                    //
-                    if (next == END_OF_STREAM)
-                    {
-                        return new BERTaggedObject(tag & 0x1f, dObj);
-                    }
-
-                    //
-                    // another implicit object, we'll create a sequence...
-                    //
-                    seq = new BERConstructedSequence();
-
-                    seq.addObject(dObj);
-
-                    do
-                    {
-                        seq.addObject(next);
-                        next = readObject();
-                    }
-                    while (next != END_OF_STREAM);
-
-                    return new BERTaggedObject(false, tag & 0x1f, seq);
-                }
-
-                throw new IOException("unknown BER object encountered");
-            }
-        }
-        else
-        {
-            if (tag == 0 && length == 0)    // end of contents marker.
-            {
-                return END_OF_STREAM;
-            }
-
-            byte[]  bytes = new byte[length];
-    
-            readFully(bytes);
-    
-            return buildObject(tag, bytes);
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java b/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java
index bc937ad..1118a56 100644
--- a/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java
+++ b/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java
@@ -1,9 +1,9 @@
 package org.bouncycastle.asn1;
 
-import org.bouncycastle.util.io.Streams;
-
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.util.io.Streams;
 
 public class BEROctetStringParser
     implements ASN1OctetStringParser
@@ -16,25 +16,22 @@
         _parser = parser;
     }
 
-    /**
-     * @deprecated will be removed
-     */
-    protected BEROctetStringParser(
-        ASN1ObjectParser parser)
-    {
-        _parser = parser._aIn;
-    }
-
     public InputStream getOctetStream()
     {
         return new ConstructedOctetStream(_parser);
     }
 
+    public DERObject getLoadedObject()
+        throws IOException
+    {
+        return new BERConstructedOctetString(Streams.readAll(getOctetStream()));
+    }
+
     public DERObject getDERObject()
     {
         try
         {
-            return new BERConstructedOctetString(Streams.readAll(getOctetStream()));
+            return getLoadedObject();
         }
         catch (IOException e)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/BERSequence.java b/src/main/java/org/bouncycastle/asn1/BERSequence.java
index c389fa8..aec6fd6 100644
--- a/src/main/java/org/bouncycastle/asn1/BERSequence.java
+++ b/src/main/java/org/bouncycastle/asn1/BERSequence.java
@@ -26,7 +26,7 @@
      * create a sequence containing a vector of objects.
      */
     public BERSequence(
-        DEREncodableVector   v)
+        ASN1EncodableVector   v)
     {
         super(v);
     }
diff --git a/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java b/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java
index cd0ca27..4f3b7ec 100644
--- a/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java
+++ b/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java
@@ -18,11 +18,17 @@
         return _parser.readObject();
     }
 
+    public DERObject getLoadedObject()
+        throws IOException
+    {
+        return new BERSequence(_parser.readVector());
+    }
+    
     public DERObject getDERObject()
     {
         try
         {
-            return new BERSequence(_parser.readVector());
+            return getLoadedObject();
         }
         catch (IOException e)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/BERSet.java b/src/main/java/org/bouncycastle/asn1/BERSet.java
index 1ccf0fd..a5a2633 100644
--- a/src/main/java/org/bouncycastle/asn1/BERSet.java
+++ b/src/main/java/org/bouncycastle/asn1/BERSet.java
@@ -26,7 +26,7 @@
      * @param v - a vector of objects making up the set.
      */
     public BERSet(
-        DEREncodableVector   v)
+        ASN1EncodableVector   v)
     {
         super(v, false);
     }
@@ -35,7 +35,7 @@
      * @param v - a vector of objects making up the set.
      */
     BERSet(
-        DEREncodableVector   v,
+        ASN1EncodableVector  v,
         boolean              needsSorting)
     {
         super(v, needsSorting);
diff --git a/src/main/java/org/bouncycastle/asn1/BERSetParser.java b/src/main/java/org/bouncycastle/asn1/BERSetParser.java
index ac280d3..e345f3f 100644
--- a/src/main/java/org/bouncycastle/asn1/BERSetParser.java
+++ b/src/main/java/org/bouncycastle/asn1/BERSetParser.java
@@ -18,11 +18,17 @@
         return _parser.readObject();
     }
 
+    public DERObject getLoadedObject()
+        throws IOException
+    {
+        return new BERSet(_parser.readVector(), false);
+    }
+
     public DERObject getDERObject()
     {
         try
         {
-            return new BERSet(_parser.readVector(), false);
+            return getLoadedObject();
         }
         catch (IOException e)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java b/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java
index ce7318d..40333fb 100644
--- a/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java
+++ b/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java
@@ -6,33 +6,41 @@
 public class BERTaggedObjectParser
     implements ASN1TaggedObjectParser
 {
-    private int _baseTag;
+    private boolean _constructed;
     private int _tagNumber;
-    private InputStream _contentStream;
+    private ASN1StreamParser _parser;
 
-    private boolean _indefiniteLength;
-
+    /**
+     * @deprecated
+     */
     protected BERTaggedObjectParser(
         int         baseTag,
         int         tagNumber,
         InputStream contentStream)
     {
-        _baseTag = baseTag;
+        this((baseTag & DERTags.CONSTRUCTED) != 0, tagNumber, new ASN1StreamParser(contentStream));
+    }
+
+    BERTaggedObjectParser(
+        boolean             constructed,
+        int                 tagNumber,
+        ASN1StreamParser    parser)
+    {
+        _constructed = constructed;
         _tagNumber = tagNumber;
-        _contentStream = contentStream;
-        _indefiniteLength = contentStream instanceof IndefiniteLengthInputStream;
+        _parser = parser;
     }
 
     public boolean isConstructed()
     {
-        return (_baseTag & DERTags.CONSTRUCTED) != 0;
+        return _constructed;
     }
 
     public int getTagNo()
     {
         return _tagNumber;
     }
-    
+
     public DEREncodable getObjectParser(
         int     tag,
         boolean isExplicit)
@@ -40,84 +48,31 @@
     {
         if (isExplicit)
         {
-            return new ASN1StreamParser(_contentStream).readObject();
+            if (!_constructed)
+            {
+                throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
+            }
+            return _parser.readObject();
         }
 
-        switch (tag)
-        {
-            case DERTags.SET:
-                if (_indefiniteLength)
-                {
-                    return new BERSetParser(new ASN1StreamParser(_contentStream));
-                }
-                else
-                {
-                    return new DERSetParser(new ASN1StreamParser(_contentStream));
-                }
-            case DERTags.SEQUENCE:
-                if (_indefiniteLength)
-                {
-                    return new BERSequenceParser(new ASN1StreamParser(_contentStream));
-                }
-                else
-                {
-                    return new DERSequenceParser(new ASN1StreamParser(_contentStream));
-                }
-            case DERTags.OCTET_STRING:
-                // TODO Is the handling of definite length constructed encodings correct?
-                if (_indefiniteLength || this.isConstructed())
-                {
-                    return new BEROctetStringParser(new ASN1StreamParser(_contentStream));
-                }
-                else
-                {
-                    return new DEROctetStringParser((DefiniteLengthInputStream)_contentStream);
-                }
-        }
-
-        throw new RuntimeException("implicit tagging not implemented");
+        return _parser.readImplicit(_constructed, tag);
     }
 
-    private ASN1EncodableVector rLoadVector(InputStream in)
+    public DERObject getLoadedObject()
+        throws IOException
     {
-        try
-        {
-            return new ASN1StreamParser(in).readVector();
-        }
-        catch (IOException e)
-        {
-            throw new ASN1ParsingException(e.getMessage(), e);
-        }
+        return _parser.readTaggedObject(_constructed, _tagNumber);
     }
 
     public DERObject getDERObject()
     {
-        if (_indefiniteLength)
-        {
-            ASN1EncodableVector v = rLoadVector(_contentStream);
-
-            return v.size() == 1
-                ?   new BERTaggedObject(true, _tagNumber, v.get(0))
-                :   new BERTaggedObject(false, _tagNumber, BERFactory.createSequence(v));
-        }
-
-        if (this.isConstructed())
-        {
-            ASN1EncodableVector v = rLoadVector(_contentStream);
-
-            return v.size() == 1
-                ?   new DERTaggedObject(true, _tagNumber, v.get(0))
-                :   new DERTaggedObject(false, _tagNumber, DERFactory.createSequence(v));
-        }
-
         try
         {
-            DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_contentStream;
-            return new DERTaggedObject(false, _tagNumber, new DEROctetString(defIn.toByteArray()));
+            return this.getLoadedObject();
         }
         catch (IOException e)
         {
-            throw new IllegalStateException(e.getMessage());
+            throw new ASN1ParsingException(e.getMessage());
         }
     }
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERBMPString.java b/src/main/java/org/bouncycastle/asn1/DERBMPString.java
index 1472325..1ff72de 100644
--- a/src/main/java/org/bouncycastle/asn1/DERBMPString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERBMPString.java
@@ -25,16 +25,6 @@
             return (DERBMPString)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERBMPString(((ASN1OctetString)obj).getOctets());
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -51,7 +41,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DERBMPString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERBMPString(ASN1OctetString.getInstance(o).getOctets());
+        }
     }
     
 
diff --git a/src/main/java/org/bouncycastle/asn1/DERBitString.java b/src/main/java/org/bouncycastle/asn1/DERBitString.java
index efcdaca..efca7d3 100644
--- a/src/main/java/org/bouncycastle/asn1/DERBitString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERBitString.java
@@ -1,10 +1,10 @@
 package org.bouncycastle.asn1;
 
-import org.bouncycastle.util.Arrays;
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
+import org.bouncycastle.util.Arrays;
+
 public class DERBitString
     extends ASN1Object
     implements DERString
@@ -100,22 +100,6 @@
             return (DERBitString)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            byte[]  bytes = ((ASN1OctetString)obj).getOctets();
-            int     padBits = bytes[0];
-            byte[]  data = new byte[bytes.length - 1];
-
-            System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
-
-            return new DERBitString(data, padBits);
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -132,7 +116,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DERBitString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return fromOctetString(((ASN1OctetString)o).getOctets());
+        }
     }
     
     protected DERBitString(
@@ -263,4 +256,22 @@
     {
         return getString();
     }
+
+    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/src/main/java/org/bouncycastle/asn1/DERBoolean.java b/src/main/java/org/bouncycastle/asn1/DERBoolean.java
index 5667715..5cba346 100644
--- a/src/main/java/org/bouncycastle/asn1/DERBoolean.java
+++ b/src/main/java/org/bouncycastle/asn1/DERBoolean.java
@@ -25,18 +25,6 @@
             return (DERBoolean)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            // BEGIN android-changed
-            return getInstance(((ASN1OctetString)obj).getOctets());
-            // END android-changed
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -73,24 +61,40 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
-    }
+        DERObject o = obj.getObject();
 
+        if (explicit || o instanceof DERBoolean)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            // BEGIN android-changed
+            return getInstance(((ASN1OctetString)o).getOctets());
+            // END android-changed
+        }
+    }
+    
     // BEGIN android-removed
-    //private DERBoolean(
-    //    byte[]       value)
-    //{
-    //    this.value = value[0];
-    //}
+    // public DERBoolean(
+    //     byte[]       value)
+    // {
+    //     if (value.length != 1)
+    //     {
+    //         throw new IllegalArgumentException("byte value should have 1 byte in it");
+    //     }
+    //
+    //     this.value = value[0];
+    // }
     // END android-removed
 
     // BEGIN android-changed
-    private DERBoolean(
+    protected DERBoolean(
         boolean     value)
+    // END android-changed
     {
         this.value = (value) ? (byte)0xff : (byte)0;
     }
-    // END android-changed
 
     public boolean isTrue()
     {
diff --git a/src/main/java/org/bouncycastle/asn1/DERConstructedSequence.java b/src/main/java/org/bouncycastle/asn1/DERConstructedSequence.java
deleted file mode 100644
index 99a493e..0000000
--- a/src/main/java/org/bouncycastle/asn1/DERConstructedSequence.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.bouncycastle.asn1;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.Enumeration;
-
-/**
- * @deprecated use DERSequence.
- */
-public class DERConstructedSequence
-    extends ASN1Sequence
-{
-    public void addObject(
-        DEREncodable obj)
-    {
-        super.addObject(obj);
-    }
-
-    public int getSize()
-    {
-        return size();
-    }
-
-    /*
-     * 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 outputing SEQUENCE,
-     * we also have to specify CONSTRUCTED, and the objects length.
-     */
-    void encode(
-        DEROutputStream out)
-        throws IOException
-    {
-        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
-        DEROutputStream         dOut = new DEROutputStream(bOut);
-        Enumeration             e = this.getObjects();
-
-        while (e.hasMoreElements())
-        {
-            Object    obj = e.nextElement();
-
-            dOut.writeObject(obj);
-        }
-
-        dOut.close();
-
-        byte[]  bytes = bOut.toByteArray();
-
-        out.writeEncoded(SEQUENCE | CONSTRUCTED, bytes);
-    }
-}
diff --git a/src/main/java/org/bouncycastle/asn1/DERConstructedSet.java b/src/main/java/org/bouncycastle/asn1/DERConstructedSet.java
deleted file mode 100644
index 695cef3..0000000
--- a/src/main/java/org/bouncycastle/asn1/DERConstructedSet.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.bouncycastle.asn1;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.Enumeration;
-
-/**
- * 
- * @deprecated use DERSet
- */
-public class DERConstructedSet
-    extends ASN1Set
-{
-    public DERConstructedSet()
-    {
-    }
-
-    /**
-     * @param obj - a single object that makes up the set.
-     */
-    public DERConstructedSet(
-        DEREncodable   obj)
-    {
-        this.addObject(obj);
-    }
-
-    /**
-     * @param v - a vector of objects making up the set.
-     */
-    public DERConstructedSet(
-        DEREncodableVector   v)
-    {
-        for (int i = 0; i != v.size(); i++)
-        {
-            this.addObject(v.get(i));
-        }
-    }
-
-    public void addObject(
-        DEREncodable    obj)
-    {
-        super.addObject(obj);
-    }
-
-    public int getSize()
-    {
-        return size();
-    }
-
-    /*
-     * 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 outputing SET,
-     * we also have to specify CONSTRUCTED, and the objects length.
-     */
-    void encode(
-        DEROutputStream out)
-        throws IOException
-    {
-        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
-        DEROutputStream         dOut = new DEROutputStream(bOut);
-        Enumeration             e = this.getObjects();
-
-        while (e.hasMoreElements())
-        {
-            Object    obj = e.nextElement();
-
-            dOut.writeObject(obj);
-        }
-
-        dOut.close();
-
-        byte[]  bytes = bOut.toByteArray();
-
-        out.writeEncoded(SET | CONSTRUCTED, bytes);
-    }
-}
diff --git a/src/main/java/org/bouncycastle/asn1/DEREnumerated.java b/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
index 5a9da4c..440744e 100644
--- a/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
+++ b/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
@@ -1,10 +1,10 @@
 package org.bouncycastle.asn1;
 
-import org.bouncycastle.util.Arrays;
-
 import java.io.IOException;
 import java.math.BigInteger;
 
+import org.bouncycastle.util.Arrays;
+
 public class DEREnumerated
     extends ASN1Object
 {
@@ -23,16 +23,6 @@
             return (DEREnumerated)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DEREnumerated(((ASN1OctetString)obj).getOctets());
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -49,7 +39,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DEREnumerated)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DEREnumerated(((ASN1OctetString)o).getOctets());
+        }
     }
 
     public DEREnumerated(
diff --git a/src/main/java/org/bouncycastle/asn1/DERExternal.java b/src/main/java/org/bouncycastle/asn1/DERExternal.java
index ad062c8..769c945 100644
--- a/src/main/java/org/bouncycastle/asn1/DERExternal.java
+++ b/src/main/java/org/bouncycastle/asn1/DERExternal.java
@@ -18,25 +18,32 @@
     public DERExternal(ASN1EncodableVector vector)
     {
         int offset = 0;
-        DERObject enc = vector.get(offset).getDERObject();
+
+        DERObject enc = getObjFromVector(vector, offset);
         if (enc instanceof DERObjectIdentifier)
         {
             directReference = (DERObjectIdentifier)enc;
             offset++;
-            enc = vector.get(offset).getDERObject();
+            enc = getObjFromVector(vector, offset);
         }
         if (enc instanceof DERInteger)
         {
             indirectReference = (DERInteger) enc;
             offset++;
-            enc = vector.get(offset).getDERObject();
+            enc = getObjFromVector(vector, offset);
         }
         if (!(enc instanceof DERTaggedObject))
         {
             dataValueDescriptor = (ASN1Object) enc;
             offset++;
-            enc = vector.get(offset).getDERObject();
+            enc = getObjFromVector(vector, offset);
         }
+
+        if (vector.size() != offset + 1)
+        {
+            throw new IllegalArgumentException("input vector too large");
+        }
+
         if (!(enc instanceof DERTaggedObject))
         {
             throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External");
@@ -46,6 +53,15 @@
         externalContent = obj.getObject();
     }
 
+    private DERObject getObjFromVector(ASN1EncodableVector v, int index)
+    {
+        if (v.size() <= index)
+        {
+            throw new IllegalArgumentException("too few objects in input vector");
+        }
+
+        return v.get(index).getDERObject();
+    }
     /**
      * Creates a new instance of DERExternal
      * See X.690 for more informations about the meaning of these parameters
diff --git a/src/main/java/org/bouncycastle/asn1/DERExternalParser.java b/src/main/java/org/bouncycastle/asn1/DERExternalParser.java
index 0fbfb68..059908f 100644
--- a/src/main/java/org/bouncycastle/asn1/DERExternalParser.java
+++ b/src/main/java/org/bouncycastle/asn1/DERExternalParser.java
@@ -3,7 +3,7 @@
 import java.io.IOException;
 
 public class DERExternalParser
-    implements DEREncodable
+    implements DEREncodable, InMemoryRepresentable
 {
     private ASN1StreamParser _parser;
 
@@ -20,12 +20,25 @@
     {
         return _parser.readObject();
     }
+
+    public DERObject getLoadedObject()
+        throws IOException
+    {
+        try
+        {
+            return new DERExternal(_parser.readVector());
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw new ASN1Exception(e.getMessage(), e);
+        }
+    }
     
     public DERObject getDERObject()
     {
         try 
         {
-            return new DERExternal(_parser.readVector());
+            return getLoadedObject();
         }
         catch (IOException ioe) 
         {
diff --git a/src/main/java/org/bouncycastle/asn1/DERGeneralString.java b/src/main/java/org/bouncycastle/asn1/DERGeneralString.java
index 1992cf3..51d4658 100644
--- a/src/main/java/org/bouncycastle/asn1/DERGeneralString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERGeneralString.java
@@ -14,14 +14,7 @@
         {
             return (DERGeneralString) obj;
         }
-        if (obj instanceof ASN1OctetString) 
-        {
-            return new DERGeneralString(((ASN1OctetString) obj).getOctets());
-        }
-        if (obj instanceof ASN1TaggedObject) 
-        {
-            return getInstance(((ASN1TaggedObject) obj).getObject());
-        }
+
         throw new IllegalArgumentException("illegal object in getInstance: "
                 + obj.getClass().getName());
     }
@@ -30,7 +23,16 @@
         ASN1TaggedObject obj, 
         boolean explicit) 
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DERGeneralString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERGeneralString(((ASN1OctetString)o).getOctets());
+        }
     }
 
     public DERGeneralString(byte[] string) 
diff --git a/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java b/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java
index 5366347..728cb22 100644
--- a/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java
+++ b/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java
@@ -28,11 +28,6 @@
             return (DERGeneralizedTime)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERGeneralizedTime(((ASN1OctetString)obj).getOctets());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -49,7 +44,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DERGeneralizedTime)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERGeneralizedTime(((ASN1OctetString)o).getOctets());
+        }
     }
     
     /**
@@ -223,7 +227,7 @@
         {
             d = this.getTime();
             if (hasFractionalSeconds())
-            {
+            { 
                 dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz");
             }
             else
@@ -260,11 +264,22 @@
                     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 dateF.parse(d);
diff --git a/src/main/java/org/bouncycastle/asn1/DERIA5String.java b/src/main/java/org/bouncycastle/asn1/DERIA5String.java
index a90830c..e94c62b 100644
--- a/src/main/java/org/bouncycastle/asn1/DERIA5String.java
+++ b/src/main/java/org/bouncycastle/asn1/DERIA5String.java
@@ -24,16 +24,6 @@
             return (DERIA5String)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERIA5String(((ASN1OctetString)obj).getOctets());
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -50,7 +40,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DERIA5String)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERIA5String(((ASN1OctetString)o).getOctets());
+        }
     }
 
     /**
diff --git a/src/main/java/org/bouncycastle/asn1/DERInputStream.java b/src/main/java/org/bouncycastle/asn1/DERInputStream.java
deleted file mode 100644
index 6edc699..0000000
--- a/src/main/java/org/bouncycastle/asn1/DERInputStream.java
+++ /dev/null
@@ -1,276 +0,0 @@
-package org.bouncycastle.asn1;
-
-import java.io.ByteArrayInputStream;
-import java.io.EOFException;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Don't use this class. It will eventually disappear, use ASN1InputStream.
- * <br>
- * This class is scheduled for removal.
- * @deprecated use ASN1InputStream
- */
-public class DERInputStream
-    extends FilterInputStream implements DERTags
-{
-    /**
-     * @deprecated use ASN1InputStream
-     */
-    public DERInputStream(
-        InputStream is)
-    {
-        super(is);
-    }
-
-    protected int readLength()
-        throws IOException
-    {
-        int length = read();
-        if (length < 0)
-        {
-            throw new IOException("EOF found when length expected");
-        }
-
-        if (length == 0x80)
-        {
-            return -1;      // indefinite-length encoding
-        }
-
-        if (length > 127)
-        {
-            int size = length & 0x7f;
-
-            if (size > 4)
-            {
-                throw new IOException("DER length more than 4 bytes");
-            }
-            
-            length = 0;
-            for (int i = 0; i < size; i++)
-            {
-                int next = read();
-
-                if (next < 0)
-                {
-                    throw new IOException("EOF found reading length");
-                }
-
-                length = (length << 8) + next;
-            }
-            
-            if (length < 0)
-            {
-                throw new IOException("corrupted stream - negative length found");
-            }
-        }
-
-        return length;
-    }
-
-    protected void readFully(
-        byte[]  bytes)
-        throws IOException
-    {
-        int     left = bytes.length;
-
-        if (left == 0)
-        {
-            return;
-        }
-
-        while (left > 0)
-        {
-            int    l = read(bytes, bytes.length - left, left);
-            
-            if (l < 0)
-            {
-                throw new EOFException("unexpected end of stream");
-            }
-            
-            left -= l;
-        }
-    }
-
-    /**
-     * build an object given its tag and a byte stream to construct it
-     * from.
-     */
-    protected DERObject buildObject(
-        int       tag,
-        byte[]    bytes)
-        throws IOException
-    {
-        switch (tag)
-        {
-        case NULL:
-            return null;   
-        case SEQUENCE | CONSTRUCTED:
-            ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
-            BERInputStream          dIn = new BERInputStream(bIn);
-            DERConstructedSequence  seq = new DERConstructedSequence();
-
-            try
-            {
-                for (;;)
-                {
-                    DERObject   obj = dIn.readObject();
-
-                    seq.addObject(obj);
-                }
-            }
-            catch (EOFException ex)
-            {
-                return seq;
-            }
-        case SET | CONSTRUCTED:
-            bIn = new ByteArrayInputStream(bytes);
-            dIn = new BERInputStream(bIn);
-
-            ASN1EncodableVector    v = new ASN1EncodableVector();
-
-            try
-            {
-                for (;;)
-                {
-                    DERObject   obj = dIn.readObject();
-
-                    v.add(obj);
-                }
-            }
-            catch (EOFException ex)
-            {
-                return new DERConstructedSet(v);
-            }
-        case BOOLEAN:
-            // BEGIN android-changed
-            return DERBoolean.getInstance(bytes);
-            // BEGIN android-changed
-        case INTEGER:
-            return new DERInteger(bytes);
-        case ENUMERATED:
-            return new DEREnumerated(bytes);
-        case OBJECT_IDENTIFIER:
-            return new DERObjectIdentifier(bytes);
-        case BIT_STRING:
-            int     padBits = bytes[0];
-            byte[]  data = new byte[bytes.length - 1];
-
-            System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
-
-            return new DERBitString(data, padBits);
-        case UTF8_STRING:
-            return new DERUTF8String(bytes);
-        case PRINTABLE_STRING:
-            return new DERPrintableString(bytes);
-        case IA5_STRING:
-            return new DERIA5String(bytes);
-        case T61_STRING:
-            return new DERT61String(bytes);
-        case VISIBLE_STRING:
-            return new DERVisibleString(bytes);
-        case UNIVERSAL_STRING:
-            return new DERUniversalString(bytes);
-        case GENERAL_STRING:
-            return new DERGeneralString(bytes);
-        case BMP_STRING:
-            return new DERBMPString(bytes);
-        case OCTET_STRING:
-            return new DEROctetString(bytes);
-        case UTC_TIME:
-            return new DERUTCTime(bytes);
-        case GENERALIZED_TIME:
-            return new DERGeneralizedTime(bytes);
-        default:
-            //
-            // with tagged object tag number is bottom 5 bits
-            //
-            if ((tag & TAGGED) != 0)  
-            {
-                if ((tag & 0x1f) == 0x1f)
-                {
-                    throw new IOException("unsupported high tag encountered");
-                }
-
-                if (bytes.length == 0)        // empty tag!
-                {
-                    if ((tag & CONSTRUCTED) == 0)
-                    {
-                        // BEGIN android-changed
-                        return new DERTaggedObject(false, tag & 0x1f, DERNull.INSTANCE);
-                        // END android-changed
-                    }
-                    else
-                    {
-                        return new DERTaggedObject(false, tag & 0x1f, new DERConstructedSequence());
-                    }
-                }
-
-                //
-                // simple type - implicit... return an octet string
-                //
-                if ((tag & CONSTRUCTED) == 0)
-                {
-                    return new DERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes));
-                }
-
-                bIn = new ByteArrayInputStream(bytes);
-                dIn = new BERInputStream(bIn);
-
-                DEREncodable dObj = dIn.readObject();
-
-                //
-                // explicitly tagged (probably!) - if it isn't we'd have to
-                // tell from the context
-                //
-                if (dIn.available() == 0)
-                {
-                    return new DERTaggedObject(tag & 0x1f, dObj);
-                }
-
-                //
-                // another implicit object, we'll create a sequence...
-                //
-                seq = new DERConstructedSequence();
-
-                seq.addObject(dObj);
-
-                try
-                {
-                    for (;;)
-                    {
-                        dObj = dIn.readObject();
-
-                        seq.addObject(dObj);
-                    }
-                }
-                catch (EOFException ex)
-                {
-                    // ignore --
-                }
-
-                return new DERTaggedObject(false, tag & 0x1f, seq);
-            }
-
-            return new DERUnknownTag(tag, bytes);
-        }
-    }
-
-    public DERObject readObject()
-        throws IOException
-    {
-        int tag = read();
-        if (tag == -1)
-        {
-            throw new EOFException();
-        }
-
-        int     length = readLength();
-        byte[]  bytes = new byte[length];
-
-        readFully(bytes);
-
-        return buildObject(tag, bytes);
-    }
-}
diff --git a/src/main/java/org/bouncycastle/asn1/DERInteger.java b/src/main/java/org/bouncycastle/asn1/DERInteger.java
index 8f97428..c72a6cb 100644
--- a/src/main/java/org/bouncycastle/asn1/DERInteger.java
+++ b/src/main/java/org/bouncycastle/asn1/DERInteger.java
@@ -23,16 +23,6 @@
             return (DERInteger)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERInteger(((ASN1OctetString)obj).getOctets());
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -49,7 +39,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DERInteger)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets());
+        }
     }
 
     public DERInteger(
diff --git a/src/main/java/org/bouncycastle/asn1/DERNumericString.java b/src/main/java/org/bouncycastle/asn1/DERNumericString.java
index 3c72193..23314a6 100644
--- a/src/main/java/org/bouncycastle/asn1/DERNumericString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERNumericString.java
@@ -24,16 +24,6 @@
             return (DERNumericString)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERNumericString(((ASN1OctetString)obj).getOctets());
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -50,7 +40,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DERNumericString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERNumericString(ASN1OctetString.getInstance(o).getOctets());
+        }
     }
 
     /**
diff --git a/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
index bad9473..8e579f7 100644
--- a/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
+++ b/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
@@ -23,16 +23,6 @@
             return (DERObjectIdentifier)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERObjectIdentifier(((ASN1OctetString)obj).getOctets());
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -49,7 +39,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DERObjectIdentifier)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new ASN1ObjectIdentifier(ASN1OctetString.getInstance(obj.getObject()).getOctets());
+        }
     }
     
 
@@ -147,39 +146,15 @@
         long            fieldValue)
         throws IOException
     {
-        if (fieldValue >= (1L << 7))
+        byte[] result = new byte[9];
+        int pos = 8;
+        result[pos] = (byte)((int)fieldValue & 0x7f);
+        while (fieldValue >= (1L << 7))
         {
-            if (fieldValue >= (1L << 14))
-            {
-                if (fieldValue >= (1L << 21))
-                {
-                    if (fieldValue >= (1L << 28))
-                    {
-                        if (fieldValue >= (1L << 35))
-                        {
-                            if (fieldValue >= (1L << 42))
-                            {
-                                if (fieldValue >= (1L << 49))
-                                {
-                                    if (fieldValue >= (1L << 56))
-                                    {
-                                        out.write((int)(fieldValue >> 56) | 0x80);
-                                    }
-                                    out.write((int)(fieldValue >> 49) | 0x80);
-                                }
-                                out.write((int)(fieldValue >> 42) | 0x80);
-                            }
-                            out.write((int)(fieldValue >> 35) | 0x80);
-                        }
-                        out.write((int)(fieldValue >> 28) | 0x80);
-                    }
-                    out.write((int)(fieldValue >> 21) | 0x80);
-                }
-                out.write((int)(fieldValue >> 14) | 0x80);
-            }
-            out.write((int)(fieldValue >> 7) | 0x80);
+            fieldValue >>= 7;
+            result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80);
         }
-        out.write((int)fieldValue & 0x7f);
+        out.write(result, pos, 9 - pos);
     }
 
     private void writeField(
diff --git a/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java b/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java
index f6138d9..2318f5c 100644
--- a/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java
+++ b/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java
@@ -1,7 +1,7 @@
 package org.bouncycastle.asn1;
 
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 
 public class DEROctetStringParser
     implements ASN1OctetStringParser
@@ -19,11 +19,17 @@
         return stream;
     }
 
+    public DERObject getLoadedObject()
+        throws IOException
+    {
+        return new DEROctetString(stream.toByteArray());
+    }
+    
     public DERObject getDERObject()
     {
         try
         {
-            return new DEROctetString(stream.toByteArray());
+            return getLoadedObject();
         }
         catch (IOException e)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/DERPrintableString.java b/src/main/java/org/bouncycastle/asn1/DERPrintableString.java
index c7a6f44..2f84c1c 100644
--- a/src/main/java/org/bouncycastle/asn1/DERPrintableString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERPrintableString.java
@@ -26,16 +26,6 @@
             return (DERPrintableString)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERPrintableString(((ASN1OctetString)obj).getOctets());
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -52,7 +42,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DERPrintableString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets());
+        }
     }
 
     /**
diff --git a/src/main/java/org/bouncycastle/asn1/DERSequence.java b/src/main/java/org/bouncycastle/asn1/DERSequence.java
index a2e6ab5..bb7f7fb 100644
--- a/src/main/java/org/bouncycastle/asn1/DERSequence.java
+++ b/src/main/java/org/bouncycastle/asn1/DERSequence.java
@@ -27,7 +27,7 @@
      * create a sequence containing a vector of objects.
      */
     public DERSequence(
-        DEREncodableVector   v)
+        ASN1EncodableVector   v)
     {
         for (int i = 0; i != v.size(); i++)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java b/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java
index 59ba7f7..b91dfa0 100644
--- a/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java
+++ b/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java
@@ -18,11 +18,17 @@
         return _parser.readObject();
     }
 
+    public DERObject getLoadedObject()
+        throws IOException
+    {
+         return new DERSequence(_parser.readVector());
+    }
+
     public DERObject getDERObject()
     {
         try
         {
-            return new DERSequence(_parser.readVector());
+            return getLoadedObject();
         }
         catch (IOException e)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/DERSet.java b/src/main/java/org/bouncycastle/asn1/DERSet.java
index b116e0c..c4acc82 100644
--- a/src/main/java/org/bouncycastle/asn1/DERSet.java
+++ b/src/main/java/org/bouncycastle/asn1/DERSet.java
@@ -30,7 +30,7 @@
      * @param v - a vector of objects making up the set.
      */
     public DERSet(
-        DEREncodableVector   v)
+        ASN1EncodableVector   v)
     {
         this(v, true);
     }
@@ -53,7 +53,7 @@
      * @param v - a vector of objects making up the set.
      */
     DERSet(
-        DEREncodableVector   v,
+        ASN1EncodableVector  v,
         boolean              needsSorting)
     {
         for (int i = 0; i != v.size(); i++)
diff --git a/src/main/java/org/bouncycastle/asn1/DERSetParser.java b/src/main/java/org/bouncycastle/asn1/DERSetParser.java
index 2793e51..44ddb80 100644
--- a/src/main/java/org/bouncycastle/asn1/DERSetParser.java
+++ b/src/main/java/org/bouncycastle/asn1/DERSetParser.java
@@ -18,11 +18,17 @@
         return _parser.readObject();
     }
 
+    public DERObject getLoadedObject()
+        throws IOException
+    {
+        return new DERSet(_parser.readVector(), false);
+    }
+
     public DERObject getDERObject()
     {
         try
         {
-            return new DERSet(_parser.readVector(), false);
+            return getLoadedObject();
         }
         catch (IOException e)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/DERString.java b/src/main/java/org/bouncycastle/asn1/DERString.java
index 3143be9..37dc905 100644
--- a/src/main/java/org/bouncycastle/asn1/DERString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERString.java
@@ -4,6 +4,7 @@
  * basic interface for DER string objects.
  */
 public interface DERString
+    extends ASN1String
 {
-    public String getString();
+
 }
diff --git a/src/main/java/org/bouncycastle/asn1/DERT61String.java b/src/main/java/org/bouncycastle/asn1/DERT61String.java
index 09039fc..519a950 100644
--- a/src/main/java/org/bouncycastle/asn1/DERT61String.java
+++ b/src/main/java/org/bouncycastle/asn1/DERT61String.java
@@ -24,16 +24,6 @@
             return (DERT61String)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERT61String(((ASN1OctetString)obj).getOctets());
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -50,7 +40,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERT61String(ASN1OctetString.getInstance(o).getOctets());
+        }
     }
 
     /**
diff --git a/src/main/java/org/bouncycastle/asn1/DERUTCTime.java b/src/main/java/org/bouncycastle/asn1/DERUTCTime.java
index 7a05664..f183d72 100644
--- a/src/main/java/org/bouncycastle/asn1/DERUTCTime.java
+++ b/src/main/java/org/bouncycastle/asn1/DERUTCTime.java
@@ -27,11 +27,6 @@
             return (DERUTCTime)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERUTCTime(((ASN1OctetString)obj).getOctets());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -48,7 +43,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DERUTCTime)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERUTCTime(((ASN1OctetString)o).getOctets());
+        }
     }
     
     /**
diff --git a/src/main/java/org/bouncycastle/asn1/DERUTF8String.java b/src/main/java/org/bouncycastle/asn1/DERUTF8String.java
index 082aa63..06d6fe9 100644
--- a/src/main/java/org/bouncycastle/asn1/DERUTF8String.java
+++ b/src/main/java/org/bouncycastle/asn1/DERUTF8String.java
@@ -1,9 +1,9 @@
 package org.bouncycastle.asn1;
 
-import org.bouncycastle.util.Strings;
-
 import java.io.IOException;
 
+import org.bouncycastle.util.Strings;
+
 /**
  * DER UTF8String object.
  */
@@ -26,16 +26,6 @@
             return (DERUTF8String)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERUTF8String(((ASN1OctetString)obj).getOctets());
-        }
-
-        if (obj instanceof ASN1TaggedObject)
-        {
-            return getInstance(((ASN1TaggedObject)obj).getObject());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: "
                 + obj.getClass().getName());
     }
@@ -55,15 +45,31 @@
         ASN1TaggedObject obj,
         boolean explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject 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)
+    public DERUTF8String(byte[] string)
     {
-        this.string = Strings.fromUTF8ByteArray(string);
+        try
+        {
+            this.string = Strings.fromUTF8ByteArray(string);
+        }
+        catch (ArrayIndexOutOfBoundsException e)
+        {
+            throw new IllegalArgumentException("UTF8 encoding invalid");
+        }
     }
 
     /**
diff --git a/src/main/java/org/bouncycastle/asn1/DERUniversalString.java b/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
index 68be9a0..6e54934 100644
--- a/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
+++ b/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
@@ -26,11 +26,6 @@
             return (DERUniversalString)obj;
         }
 
-        if (obj instanceof ASN1OctetString)
-        {
-            return new DERUniversalString(((ASN1OctetString)obj).getOctets());
-        }
-
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
     }
 
@@ -47,7 +42,16 @@
         ASN1TaggedObject obj,
         boolean          explicit)
     {
-        return getInstance(obj.getObject());
+        DERObject o = obj.getObject();
+
+        if (explicit || o instanceof DERUniversalString)
+        {
+            return getInstance(o);
+        }
+        else
+        {
+            return new DERUniversalString(((ASN1OctetString)o).getOctets());
+        }
     }
 
     /**
diff --git a/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java b/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java
index 2a7f2e7..3785174 100644
--- a/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java
+++ b/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java
@@ -18,7 +18,7 @@
         InputStream in,
         int         length)
     {
-        super(in);
+        super(in, length);
 
         if (length < 0)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java b/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java
new file mode 100644
index 0000000..981ee1b
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public interface InMemoryRepresentable
+{
+    DERObject getLoadedObject()
+        throws IOException;
+}
diff --git a/src/main/java/org/bouncycastle/asn1/IndefiniteLengthInputStream.java b/src/main/java/org/bouncycastle/asn1/IndefiniteLengthInputStream.java
index d9eac06..353da3b 100644
--- a/src/main/java/org/bouncycastle/asn1/IndefiniteLengthInputStream.java
+++ b/src/main/java/org/bouncycastle/asn1/IndefiniteLengthInputStream.java
@@ -13,10 +13,11 @@
     private boolean _eofOn00 = true;
 
     IndefiniteLengthInputStream(
-        InputStream in)
+        InputStream in,
+        int         limit)
         throws IOException
     {
-        super(in);
+        super(in, limit);
 
         _b1 = in.read();
         _b2 = in.read();
diff --git a/src/main/java/org/bouncycastle/asn1/LazyDERSequence.java b/src/main/java/org/bouncycastle/asn1/LazyDERSequence.java
index da9e1b8..91074a6 100644
--- a/src/main/java/org/bouncycastle/asn1/LazyDERSequence.java
+++ b/src/main/java/org/bouncycastle/asn1/LazyDERSequence.java
@@ -29,7 +29,7 @@
         parsed = true;
     }
 
-    public DEREncodable getObjectAt(int index)
+    public synchronized DEREncodable getObjectAt(int index)
     {
         if (!parsed)
         {
@@ -39,7 +39,7 @@
         return super.getObjectAt(index);
     }
 
-    public Enumeration getObjects()
+    public synchronized Enumeration getObjects()
     {
         if (parsed)
         {
diff --git a/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java b/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java
index 5a93335..d94b0bd 100644
--- a/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java
+++ b/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java
@@ -6,13 +6,22 @@
         extends InputStream
 {
     protected final InputStream _in;
+    private int _limit;
 
     LimitedInputStream(
-        InputStream in)
+        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)
diff --git a/src/main/java/org/bouncycastle/asn1/OrderedTable.java b/src/main/java/org/bouncycastle/asn1/OrderedTable.java
deleted file mode 100644
index 8db8ab8..0000000
--- a/src/main/java/org/bouncycastle/asn1/OrderedTable.java
+++ /dev/null
@@ -1,281 +0,0 @@
-package org.bouncycastle.asn1;
-
-import java.util.Enumeration;
-import java.util.ConcurrentModificationException;
-
-// BEGIN android-note
-/*
- * This is a new class that was synthesized from the observed
- * requirement for a lookup table that preserves order. Since in
- * practice the element count is typically very low, we just use a
- * flat list rather than doing any hashing / bucketing.
- */
-// END android-note
-
-/**
- * Ordered lookup table. Instances of this class will keep up to four
- * key-value pairs directly, resorting to an external collection only
- * if more elements than that need to be stored.
- */
-public final class OrderedTable {
-    /** null-ok; key #0 */
-    private DERObjectIdentifier key0;
-    
-    /** null-ok; key #1 */
-    private DERObjectIdentifier key1;
-
-    /** null-ok; key #2 */
-    private DERObjectIdentifier key2;
-
-    /** null-ok; key #3 */
-    private DERObjectIdentifier key3;
-    
-    /** null-ok; value #0 */
-    private Object value0;
-    
-    /** null-ok; value #1 */
-    private Object value1;
-
-    /** null-ok; value #2 */
-    private Object value2;
-
-    /** null-ok; value #3 */
-    private Object value3;
-    
-    /**
-     * null-ok; array of additional keys and values, alternating
-     * key then value, etc. 
-     */
-    private Object[] rest;
-
-    /** &gt;= 0; number of elements in the list */
-    private int size;
-
-    // Note: Default public constructor.
-
-    /**
-     * Adds an element assuming no duplicate key.
-     * 
-     * @see #put
-     * 
-     * @param key non-null; the key
-     * @param value non-null; the value
-     */
-    public void add(DERObjectIdentifier key, Object value) {
-        if (key == null) {
-            throw new NullPointerException("key == null");
-        }
-
-        if (value == null) {
-            throw new NullPointerException("value == null");
-        }
-
-        int sz = size;
-
-        switch (sz) {
-            case 0: {
-                key0 = key;
-                value0 = value;
-                break;
-            }
-            case 1: {
-                key1 = key;
-                value1 = value;
-                break;
-            }
-            case 2: {
-                key2 = key;
-                value2 = value;
-                break;
-            }
-            case 3: {
-                key3 = key;
-                value3 = value;
-                break;
-            }
-            case 4: {
-                // Do initial allocation of rest.
-                rest = new Object[10];
-                rest[0] = key;
-                rest[1] = value;
-                break;
-            }
-            default: {
-                int index = (sz - 4) * 2;
-                int index1 = index + 1;
-                if (index1 >= rest.length) {
-                    // Grow rest.
-                    Object[] newRest = new Object[index1 * 2 + 10];
-                    System.arraycopy(rest, 0, newRest, 0, rest.length);
-                    rest = newRest;
-                }
-                rest[index] = key;
-                rest[index1] = value;
-                break;
-            }
-        }
-        
-        size = sz + 1;
-    }
-
-    /**
-     * Gets the number of elements in this instance.
-     */
-    public int size() {
-        return size;
-    }
-
-    /**
-     * Look up the given key, returning the associated value if found.
-     * 
-     * @param key non-null; the key to look up
-     * @return null-ok; the associated value
-     */
-    public Object get(DERObjectIdentifier key) {
-        int keyHash = key.hashCode();
-        int sz = size;
-
-        for (int i = 0; i < size; i++) {
-            DERObjectIdentifier probe = getKey(i);
-            if ((probe.hashCode() == keyHash) &&
-                    probe.equals(key)) {
-                return getValue(i);
-            }
-        }
-
-        return null;
-    }
-    
-    /**
-     * Replace a key if present, otherwise add
-     * 
-     * @see #add
-     * 
-     * @param key non-null; the key
-     * @param value non-null; the value
-     */
-    public void put(DERObjectIdentifier key, Object value) {
-        if (key == null) {
-            throw new NullPointerException("key == null");
-        }
-
-        if (value == null) {
-            throw new NullPointerException("value == null");
-        }
-
-        int keyHash = key.hashCode();
-        int sz = size;
-
-        for (int i = 0; i < size; i++) {
-            DERObjectIdentifier probe = getKey(i);
-            if ((probe.hashCode() == keyHash) &&
-                    probe.equals(key)) {
-                setValue(i, value);
-                return;
-            }
-        }
-
-        add(key, value);
-    }
-    
-    /**
-     * Gets the nth key.
-     * 
-     * @param n index
-     * @return non-null; the nth key
-     */
-    public DERObjectIdentifier getKey(int n) {
-        if ((n < 0) || (n >= size)) {
-            throw new IndexOutOfBoundsException(Integer.toString(n));
-        }
-
-        switch (n) {
-            case 0: return key0;
-            case 1: return key1;
-            case 2: return key2;
-            case 3: return key3;
-            default: return (DERObjectIdentifier) rest[(n - 4) * 2];
-        }
-    }
-
-    /**
-     * Gets the nth value.
-     * 
-     * @param n index
-     * @return non-null; the nth value
-     */
-    public Object getValue(int n) {
-        if ((n < 0) || (n >= size)) {
-            throw new IndexOutOfBoundsException(Integer.toString(n));
-        }
-
-        switch (n) {
-            case 0: return value0;
-            case 1: return value1;
-            case 2: return value2;
-            case 3: return value3;
-            default: return rest[((n - 4) * 2) + 1];
-        }
-    }
-
-    /**
-     * Sets the nth value.
-     * 
-     * @param n index
-     * @param value non-null object
-     */
-    public void setValue(int n, Object value) {
-        if ((n < 0) || (n >= size)) {
-            throw new IndexOutOfBoundsException(Integer.toString(n));
-        }
-        if (value == null) {
-            throw new NullPointerException("value == null");
-        }
-
-        switch (n) {
-            case 0: value0 = value; return;
-            case 1: value1 = value; return;
-            case 2: value2 = value; return;
-            case 3: value3 = value; return;
-            default: rest[((n - 4) * 2) + 1] = value; return;
-        }
-    }
-
-    /**
-     * Gets an enumeration of the keys, in order.
-     * 
-     * @return non-null; an enumeration of the keys
-     */
-    public Enumeration getKeys() {
-        return new KeyEnumeration();
-    }
-
-    /**
-     * Associated enumeration class.
-     */
-    private class KeyEnumeration implements Enumeration {
-        /** original size; used for modification detection */
-        private final int origSize = size;
-
-        /** &gt;= 0; current cursor */
-        private int at = 0;
-
-        /** {@inheritDoc} */
-        public boolean hasMoreElements() {
-            if (size != origSize) {
-                throw new ConcurrentModificationException();
-            }
-
-            return at < origSize;
-        }
-
-        /** {@inheritDoc} */
-        public Object nextElement() {
-            if (size != origSize) {
-                throw new ConcurrentModificationException();
-            }
-
-            return getKey(at++);
-        }
-    }
-}
diff --git a/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
deleted file mode 100644
index 88e7c18..0000000
--- a/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.bouncycastle.asn1.cms;
-
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-
-public interface CMSObjectIdentifiers
-{
-    static final DERObjectIdentifier    data = PKCSObjectIdentifiers.data;
-    static final DERObjectIdentifier    signedData = PKCSObjectIdentifiers.signedData;
-    static final DERObjectIdentifier    envelopedData = PKCSObjectIdentifiers.envelopedData;
-    static final DERObjectIdentifier    signedAndEnvelopedData = PKCSObjectIdentifiers.signedAndEnvelopedData;
-    static final DERObjectIdentifier    digestedData = PKCSObjectIdentifiers.digestedData;
-    static final DERObjectIdentifier    encryptedData = PKCSObjectIdentifiers.encryptedData;
-    static final DERObjectIdentifier    authenticatedData = PKCSObjectIdentifiers.id_ct_authData;
-    static final DERObjectIdentifier    compressedData = PKCSObjectIdentifiers.id_ct_compressedData;
-    static final DERObjectIdentifier    authEnvelopedData = PKCSObjectIdentifiers.id_ct_authEnvelopedData;
-}
diff --git a/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java b/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
index 8ab346d..f222d9e 100644
--- a/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
@@ -1,22 +1,22 @@
 package org.bouncycastle.asn1.cms;
 
-import java.util.Enumeration;
-
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.BERSequence;
 import org.bouncycastle.asn1.BERTaggedObject;
 import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DERObjectIdentifier;
 
 public class ContentInfo
     extends ASN1Encodable
-    implements CMSObjectIdentifiers
+    // BEGIN android-removed
+    // implements CMSObjectIdentifiers
+    // END android-removed
 {
-    private DERObjectIdentifier contentType;
+    private ASN1ObjectIdentifier contentType;
     private DEREncodable        content;
 
     public static ContentInfo getInstance(
@@ -37,25 +37,34 @@
     public ContentInfo(
         ASN1Sequence  seq)
     {
-        Enumeration   e = seq.getObjects();
-
-        contentType = (DERObjectIdentifier)e.nextElement();
-
-        if (e.hasMoreElements())
+        if (seq.size() < 1 || seq.size() > 2)
         {
-            content = ((ASN1TaggedObject)e.nextElement()).getObject();
+            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(
-        DERObjectIdentifier contentType,
+        ASN1ObjectIdentifier contentType,
         DEREncodable        content)
     {
         this.contentType = contentType;
         this.content = content;
     }
 
-    public DERObjectIdentifier getContentType()
+    public ASN1ObjectIdentifier getContentType()
     {
         return contentType;
     }
diff --git a/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
index 6faa597..e9ab8d6 100644
--- a/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.iana;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface IANAObjectIdentifiers
 {
@@ -8,13 +8,13 @@
     // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)}
     //
 
-    static final DERObjectIdentifier    isakmpOakley  = new DERObjectIdentifier("1.3.6.1.5.5.8.1");
+    static final ASN1ObjectIdentifier    isakmpOakley  = new ASN1ObjectIdentifier("1.3.6.1.5.5.8.1");
 
-    static final DERObjectIdentifier    hmacMD5       = new DERObjectIdentifier(isakmpOakley + ".1");
-    static final DERObjectIdentifier    hmacSHA1     = new DERObjectIdentifier(isakmpOakley + ".2");
+    static final ASN1ObjectIdentifier    hmacMD5       = new ASN1ObjectIdentifier(isakmpOakley + ".1");
+    static final ASN1ObjectIdentifier    hmacSHA1     = new ASN1ObjectIdentifier(isakmpOakley + ".2");
     
-    static final DERObjectIdentifier    hmacTIGER     = new DERObjectIdentifier(isakmpOakley + ".3");
+    static final ASN1ObjectIdentifier    hmacTIGER     = new ASN1ObjectIdentifier(isakmpOakley + ".3");
     
-    static final DERObjectIdentifier    hmacRIPEMD160 = new DERObjectIdentifier(isakmpOakley + ".4");
+    static final ASN1ObjectIdentifier    hmacRIPEMD160 = new ASN1ObjectIdentifier(isakmpOakley + ".4");
 
 }
diff --git a/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java
index c1b2356..bc2ac8d 100644
--- a/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java
@@ -1,13 +1,13 @@
 package org.bouncycastle.asn1.isismtt;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface ISISMTTObjectIdentifiers
 {
 
-    public static final DERObjectIdentifier id_isismtt = new DERObjectIdentifier("1.3.36.8");
+    static final ASN1ObjectIdentifier id_isismtt = new ASN1ObjectIdentifier("1.3.36.8");
 
-    public static final DERObjectIdentifier id_isismtt_cp = new DERObjectIdentifier(id_isismtt + ".1");
+    static final ASN1ObjectIdentifier id_isismtt_cp = id_isismtt.branch("1");
 
     /**
      * The id-isismtt-cp-accredited OID indicates that the certificate is a
@@ -16,9 +16,9 @@
      * Framework for Electronic Signatures, which additionally conforms the
      * special requirements of the SigG and has been issued by an accredited CA.
      */
-    public static final DERObjectIdentifier id_isismtt_cp_accredited = new DERObjectIdentifier(id_isismtt_cp + ".1");
+    static final ASN1ObjectIdentifier id_isismtt_cp_accredited = id_isismtt_cp.branch("1");
 
-    public static final DERObjectIdentifier id_isismtt_at = new DERObjectIdentifier(id_isismtt + ".3");
+    static final ASN1ObjectIdentifier id_isismtt_at = id_isismtt.branch("3");
 
     /**
      * Certificate extensionDate of certificate generation
@@ -27,19 +27,19 @@
      *                DateOfCertGenSyntax ::= GeneralizedTime
      * </pre>
      */
-    public static final DERObjectIdentifier id_isismtt_at_dateOfCertGen = new DERObjectIdentifier(id_isismtt_at + ".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.
      */
-    public static final DERObjectIdentifier id_isismtt_at_procuration = new DERObjectIdentifier(id_isismtt_at + ".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
      */
-    public static final DERObjectIdentifier id_isismtt_at_admission = new DERObjectIdentifier(id_isismtt_at + ".3");
+    static final ASN1ObjectIdentifier id_isismtt_at_admission = id_isismtt_at.branch("3");
 
     /**
      * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST
@@ -48,13 +48,13 @@
      * compatibility with certificates already in use, SigG conforming
      * components MUST support MonetaryLimit (as well as QcEuLimitValue).
      */
-    public static final DERObjectIdentifier id_isismtt_at_monetaryLimit = new DERObjectIdentifier(id_isismtt_at + ".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
      */
-    public static final DERObjectIdentifier id_isismtt_at_declarationOfMajority = new DERObjectIdentifier(id_isismtt_at + ".5");
+    static final ASN1ObjectIdentifier id_isismtt_at_declarationOfMajority = id_isismtt_at.branch("5");
 
     /**
      * 
@@ -64,7 +64,7 @@
      *                 ICCSNSyntax ::= OCTET STRING (SIZE(8..20))
      * </pre>
      */
-    public static final DERObjectIdentifier id_isismtt_at_iCCSN = new DERObjectIdentifier(id_isismtt_at + ".6");
+    static final ASN1ObjectIdentifier id_isismtt_at_iCCSN = id_isismtt_at.branch("6");
 
     /**
      * 
@@ -75,7 +75,7 @@
      *      PKReferenceSyntax ::= OCTET STRING (SIZE(20))
      * </pre>
      */
-    public static final DERObjectIdentifier id_isismtt_at_PKReference = new DERObjectIdentifier(id_isismtt_at + ".7");
+    static final ASN1ObjectIdentifier id_isismtt_at_PKReference = id_isismtt_at.branch("7");
 
     /**
      * Some other restriction regarding the usage of this certificate. May be
@@ -88,7 +88,7 @@
      * 
      * @see org.bouncycastle.asn1.isismtt.x509.Restriction
      */
-    public static final DERObjectIdentifier id_isismtt_at_restriction = new DERObjectIdentifier(id_isismtt_at + ".8");
+    static final ASN1ObjectIdentifier id_isismtt_at_restriction = id_isismtt_at.branch("8");
 
     /**
      * 
@@ -104,7 +104,7 @@
      *       
      * </pre>
      */
-    public static final DERObjectIdentifier id_isismtt_at_retrieveIfAllowed = new DERObjectIdentifier(id_isismtt_at + ".9");
+    static final ASN1ObjectIdentifier id_isismtt_at_retrieveIfAllowed = id_isismtt_at.branch("9");
 
     /**
      * SingleOCSPResponse extension: The certificate requested by the client by
@@ -113,12 +113,12 @@
      * 
      * @see org.bouncycastle.asn1.isismtt.ocsp.RequestedCertificate
      */
-    public static final DERObjectIdentifier id_isismtt_at_requestedCertificate = new DERObjectIdentifier(id_isismtt_at + ".10");
+    static final ASN1ObjectIdentifier id_isismtt_at_requestedCertificate = id_isismtt_at.branch("10");
 
     /**
      * Base ObjectIdentifier for naming authorities
      */
-    public static final DERObjectIdentifier id_isismtt_at_namingAuthorities = new DERObjectIdentifier(id_isismtt_at + ".11");
+    static final ASN1ObjectIdentifier id_isismtt_at_namingAuthorities = id_isismtt_at.branch("11");
 
     /**
      * SingleOCSPResponse extension: Date, when certificate has been published
@@ -130,14 +130,14 @@
      *      CertInDirSince ::= GeneralizedTime
      * </pre>
      */
-    public static final DERObjectIdentifier id_isismtt_at_certInDirSince = new DERObjectIdentifier(id_isismtt_at + ".12");
+    static final ASN1ObjectIdentifier id_isismtt_at_certInDirSince = id_isismtt_at.branch("12");
 
     /**
      * Hash of a certificate in OCSP.
      * 
      * @see org.bouncycastle.asn1.isismtt.ocsp.CertHash
      */
-    public static final DERObjectIdentifier id_isismtt_at_certHash = new DERObjectIdentifier(id_isismtt_at + ".13");
+    static final ASN1ObjectIdentifier id_isismtt_at_certHash = id_isismtt_at.branch("13");
 
     /**
      * <pre>
@@ -147,7 +147,7 @@
      * Used in
      * {@link org.bouncycastle.asn1.x509.SubjectDirectoryAttributes SubjectDirectoryAttributes}
      */
-    public static final DERObjectIdentifier id_isismtt_at_nameAtBirth = new DERObjectIdentifier(id_isismtt_at + ".14");
+    static final ASN1ObjectIdentifier id_isismtt_at_nameAtBirth = id_isismtt_at.branch("14");
 
     /**
      * Some other information of non-restrictive nature regarding the usage of
@@ -160,7 +160,7 @@
      * 
      * @see org.bouncycastle.asn1.isismtt.x509.AdditionalInformationSyntax
      */
-    public static final DERObjectIdentifier id_isismtt_at_additionalInformation = new DERObjectIdentifier(id_isismtt_at + ".15");
+    static final ASN1ObjectIdentifier id_isismtt_at_additionalInformation = id_isismtt_at.branch("15");
 
     /**
      * Indicates that an attribute certificate exists, which limits the
@@ -176,5 +176,5 @@
      *                   LiabilityLimitationFlagSyntax ::= BOOLEAN
      * </pre>
      */
-    public static final DERObjectIdentifier id_isismtt_at_liabilityLimitationFlag = new DERObjectIdentifier("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/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
index 11a03d5..debf268 100644
--- a/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.misc;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface MiscObjectIdentifiers
 {
@@ -8,39 +8,40 @@
     // Netscape
     //       iso/itu(2) joint-assign(16) us(840) uscompany(1) netscape(113730) cert-extensions(1) }
     //
-    static final String                 netscape                = "2.16.840.1.113730.1";
-    static final DERObjectIdentifier    netscapeCertType        = new DERObjectIdentifier(netscape + ".1");
-    static final DERObjectIdentifier    netscapeBaseURL         = new DERObjectIdentifier(netscape + ".2");
-    static final DERObjectIdentifier    netscapeRevocationURL   = new DERObjectIdentifier(netscape + ".3");
-    static final DERObjectIdentifier    netscapeCARevocationURL = new DERObjectIdentifier(netscape + ".4");
-    static final DERObjectIdentifier    netscapeRenewalURL      = new DERObjectIdentifier(netscape + ".7");
-    static final DERObjectIdentifier    netscapeCApolicyURL     = new DERObjectIdentifier(netscape + ".8");
-    static final DERObjectIdentifier    netscapeSSLServerName   = new DERObjectIdentifier(netscape + ".12");
-    static final DERObjectIdentifier    netscapeCertComment     = new DERObjectIdentifier(netscape + ".13");
+    static final ASN1ObjectIdentifier    netscape                = new ASN1ObjectIdentifier("2.16.840.1.113730.1");
+    static final ASN1ObjectIdentifier    netscapeCertType        = netscape.branch("1");
+    static final ASN1ObjectIdentifier    netscapeBaseURL         = netscape.branch("2");
+    static final ASN1ObjectIdentifier    netscapeRevocationURL   = netscape.branch("3");
+    static final ASN1ObjectIdentifier    netscapeCARevocationURL = netscape.branch("4");
+    static final ASN1ObjectIdentifier    netscapeRenewalURL      = netscape.branch("7");
+    static final ASN1ObjectIdentifier    netscapeCApolicyURL     = netscape.branch("8");
+    static final ASN1ObjectIdentifier    netscapeSSLServerName   = netscape.branch("12");
+    static final ASN1ObjectIdentifier    netscapeCertComment     = netscape.branch("13");
+    
     //
     // Verisign
     //       iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) }
     //
-    static final String                 verisign                = "2.16.840.1.113733.1";
+    static final ASN1ObjectIdentifier   verisign                = new ASN1ObjectIdentifier("2.16.840.1.113733.1");
 
     //
     // CZAG - country, zip, age, and gender
     //
-    static final DERObjectIdentifier    verisignCzagExtension   = new DERObjectIdentifier(verisign + ".6.3");
+    static final ASN1ObjectIdentifier    verisignCzagExtension   = verisign.branch("6.3");
     // D&B D-U-N-S number
-    static final DERObjectIdentifier    verisignDnbDunsNumber   = new DERObjectIdentifier(verisign + ".6.15");
+    static final ASN1ObjectIdentifier    verisignDnbDunsNumber   = verisign.branch("6.15");
 
     //
     // Novell
     //       iso/itu(2) country(16) us(840) organization(1) novell(113719)
     //
-    static final String                 novell                  = "2.16.840.1.113719";
-    static final DERObjectIdentifier    novellSecurityAttribs   = new DERObjectIdentifier(novell + ".1.9.4.1");
+    static final ASN1ObjectIdentifier    novell                  = new ASN1ObjectIdentifier("2.16.840.1.113719");
+    static final ASN1ObjectIdentifier    novellSecurityAttribs   = novell.branch("1.9.4.1");
 
     //
     // Entrust
     //       iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7)
     //
-    static final String                 entrust                 = "1.2.840.113533.7";
-    static final DERObjectIdentifier    entrustVersionExtension = new DERObjectIdentifier(entrust + ".65.0");
+    static final ASN1ObjectIdentifier    entrust                 = new ASN1ObjectIdentifier("1.2.840.113533.7");
+    static final ASN1ObjectIdentifier    entrustVersionExtension = entrust.branch("65.0");
 }
diff --git a/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
index a89d96d..258f269 100644
--- a/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.nist;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface NISTObjectIdentifiers
 {
@@ -11,46 +11,46 @@
     //
     // nistalgorithms(4)
     //
-    static final String                 nistAlgorithm          = "2.16.840.1.101.3.4";
+    static final ASN1ObjectIdentifier    nistAlgorithm          = new ASN1ObjectIdentifier("2.16.840.1.101.3.4");
 
-    static final DERObjectIdentifier    id_sha256               = new DERObjectIdentifier(nistAlgorithm + ".2.1");
-    static final DERObjectIdentifier    id_sha384               = new DERObjectIdentifier(nistAlgorithm + ".2.2");
-    static final DERObjectIdentifier    id_sha512               = new DERObjectIdentifier(nistAlgorithm + ".2.3");
-    static final DERObjectIdentifier    id_sha224               = new DERObjectIdentifier(nistAlgorithm + ".2.4");
+    static final ASN1ObjectIdentifier    id_sha256               = nistAlgorithm.branch("2.1");
+    static final ASN1ObjectIdentifier    id_sha384               = nistAlgorithm.branch("2.2");
+    static final ASN1ObjectIdentifier    id_sha512               = nistAlgorithm.branch("2.3");
+    static final ASN1ObjectIdentifier    id_sha224               = nistAlgorithm.branch("2.4");
     
-    static final String                 aes                     = nistAlgorithm + ".1";
+    static final ASN1ObjectIdentifier    aes                     =  nistAlgorithm.branch("1");
     
-    static final DERObjectIdentifier    id_aes128_ECB           = new DERObjectIdentifier(aes + ".1"); 
-    static final DERObjectIdentifier    id_aes128_CBC           = new DERObjectIdentifier(aes + ".2");
-    static final DERObjectIdentifier    id_aes128_OFB           = new DERObjectIdentifier(aes + ".3"); 
-    static final DERObjectIdentifier    id_aes128_CFB           = new DERObjectIdentifier(aes + ".4"); 
-    static final DERObjectIdentifier    id_aes128_wrap          = new DERObjectIdentifier(aes + ".5");
-    static final DERObjectIdentifier    id_aes128_GCM           = new DERObjectIdentifier(aes + ".6");
-    static final DERObjectIdentifier    id_aes128_CCM           = new DERObjectIdentifier(aes + ".7");
+    static final ASN1ObjectIdentifier    id_aes128_ECB           = aes.branch("1"); 
+    static final ASN1ObjectIdentifier    id_aes128_CBC           = aes.branch("2");
+    static final ASN1ObjectIdentifier    id_aes128_OFB           = aes.branch("3"); 
+    static final ASN1ObjectIdentifier    id_aes128_CFB           = aes.branch("4"); 
+    static final ASN1ObjectIdentifier    id_aes128_wrap          = aes.branch("5");
+    static final ASN1ObjectIdentifier    id_aes128_GCM           = aes.branch("6");
+    static final ASN1ObjectIdentifier    id_aes128_CCM           = aes.branch("7");
     
-    static final DERObjectIdentifier    id_aes192_ECB           = new DERObjectIdentifier(aes + ".21"); 
-    static final DERObjectIdentifier    id_aes192_CBC           = new DERObjectIdentifier(aes + ".22"); 
-    static final DERObjectIdentifier    id_aes192_OFB           = new DERObjectIdentifier(aes + ".23"); 
-    static final DERObjectIdentifier    id_aes192_CFB           = new DERObjectIdentifier(aes + ".24"); 
-    static final DERObjectIdentifier    id_aes192_wrap          = new DERObjectIdentifier(aes + ".25");
-    static final DERObjectIdentifier    id_aes192_GCM           = new DERObjectIdentifier(aes + ".26");
-    static final DERObjectIdentifier    id_aes192_CCM           = new DERObjectIdentifier(aes + ".27");
+    static final ASN1ObjectIdentifier    id_aes192_ECB           = aes.branch("21"); 
+    static final ASN1ObjectIdentifier    id_aes192_CBC           = aes.branch("22"); 
+    static final ASN1ObjectIdentifier    id_aes192_OFB           = aes.branch("23"); 
+    static final ASN1ObjectIdentifier    id_aes192_CFB           = aes.branch("24"); 
+    static final ASN1ObjectIdentifier    id_aes192_wrap          = aes.branch("25");
+    static final ASN1ObjectIdentifier    id_aes192_GCM           = aes.branch("26");
+    static final ASN1ObjectIdentifier    id_aes192_CCM           = aes.branch("27");
     
-    static final DERObjectIdentifier    id_aes256_ECB           = new DERObjectIdentifier(aes + ".41"); 
-    static final DERObjectIdentifier    id_aes256_CBC           = new DERObjectIdentifier(aes + ".42");
-    static final DERObjectIdentifier    id_aes256_OFB           = new DERObjectIdentifier(aes + ".43"); 
-    static final DERObjectIdentifier    id_aes256_CFB           = new DERObjectIdentifier(aes + ".44"); 
-    static final DERObjectIdentifier    id_aes256_wrap          = new DERObjectIdentifier(aes + ".45"); 
-    static final DERObjectIdentifier    id_aes256_GCM           = new DERObjectIdentifier(aes + ".46");
-    static final DERObjectIdentifier    id_aes256_CCM           = new DERObjectIdentifier(aes + ".47");
+    static final ASN1ObjectIdentifier    id_aes256_ECB           = aes.branch("41"); 
+    static final ASN1ObjectIdentifier    id_aes256_CBC           = aes.branch("42");
+    static final ASN1ObjectIdentifier    id_aes256_OFB           = aes.branch("43"); 
+    static final ASN1ObjectIdentifier    id_aes256_CFB           = aes.branch("44"); 
+    static final ASN1ObjectIdentifier    id_aes256_wrap          = aes.branch("45"); 
+    static final ASN1ObjectIdentifier    id_aes256_GCM           = aes.branch("46");
+    static final ASN1ObjectIdentifier    id_aes256_CCM           = aes.branch("47");
 
     //
     // signatures
     //
-    static final DERObjectIdentifier    id_dsa_with_sha2        = new DERObjectIdentifier(nistAlgorithm + ".3"); 
+    static final ASN1ObjectIdentifier    id_dsa_with_sha2        = nistAlgorithm.branch("3");
 
-    static final DERObjectIdentifier    dsa_with_sha224         = new DERObjectIdentifier(id_dsa_with_sha2 + ".1"); 
-    static final DERObjectIdentifier    dsa_with_sha256         = new DERObjectIdentifier(id_dsa_with_sha2 + ".2");
-    static final DERObjectIdentifier    dsa_with_sha384         = new DERObjectIdentifier(id_dsa_with_sha2 + ".3");
-    static final DERObjectIdentifier    dsa_with_sha512         = new DERObjectIdentifier(id_dsa_with_sha2 + ".4"); 
+    static final ASN1ObjectIdentifier    dsa_with_sha224         = id_dsa_with_sha2.branch("1");
+    static final ASN1ObjectIdentifier    dsa_with_sha256         = id_dsa_with_sha2.branch("2");
+    static final ASN1ObjectIdentifier    dsa_with_sha384         = id_dsa_with_sha2.branch("3");
+    static final ASN1ObjectIdentifier    dsa_with_sha512         = id_dsa_with_sha2.branch("4");
 }
diff --git a/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
index d9690ec..c8ce26b 100644
--- a/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
@@ -1,31 +1,31 @@
 package org.bouncycastle.asn1.oiw;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface OIWObjectIdentifiers
 {
     // id-SHA1 OBJECT IDENTIFIER ::=    
     //   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //
-    static final DERObjectIdentifier    md4WithRSA              = new DERObjectIdentifier("1.3.14.3.2.2");
-    static final DERObjectIdentifier    md5WithRSA              = new DERObjectIdentifier("1.3.14.3.2.3");
-    static final DERObjectIdentifier    md4WithRSAEncryption    = new DERObjectIdentifier("1.3.14.3.2.4");
+    static final ASN1ObjectIdentifier    md4WithRSA              = new ASN1ObjectIdentifier("1.3.14.3.2.2");
+    static final ASN1ObjectIdentifier    md5WithRSA              = new ASN1ObjectIdentifier("1.3.14.3.2.3");
+    static final ASN1ObjectIdentifier    md4WithRSAEncryption    = new ASN1ObjectIdentifier("1.3.14.3.2.4");
     
-    static final DERObjectIdentifier    desECB                  = new DERObjectIdentifier("1.3.14.3.2.6");
-    static final DERObjectIdentifier    desCBC                  = new DERObjectIdentifier("1.3.14.3.2.7");
-    static final DERObjectIdentifier    desOFB                  = new DERObjectIdentifier("1.3.14.3.2.8");
-    static final DERObjectIdentifier    desCFB                  = new DERObjectIdentifier("1.3.14.3.2.9");
+    static final ASN1ObjectIdentifier    desECB                  = new ASN1ObjectIdentifier("1.3.14.3.2.6");
+    static final ASN1ObjectIdentifier    desCBC                  = new ASN1ObjectIdentifier("1.3.14.3.2.7");
+    static final ASN1ObjectIdentifier    desOFB                  = new ASN1ObjectIdentifier("1.3.14.3.2.8");
+    static final ASN1ObjectIdentifier    desCFB                  = new ASN1ObjectIdentifier("1.3.14.3.2.9");
 
-    static final DERObjectIdentifier    desEDE                  = new DERObjectIdentifier("1.3.14.3.2.17");
+    static final ASN1ObjectIdentifier    desEDE                  = new ASN1ObjectIdentifier("1.3.14.3.2.17");
     
-    static final DERObjectIdentifier    idSHA1                  = new DERObjectIdentifier("1.3.14.3.2.26");
+    static final ASN1ObjectIdentifier    idSHA1                  = new ASN1ObjectIdentifier("1.3.14.3.2.26");
 
-    static final DERObjectIdentifier    dsaWithSHA1             = new DERObjectIdentifier("1.3.14.3.2.27");
+    static final ASN1ObjectIdentifier    dsaWithSHA1             = new ASN1ObjectIdentifier("1.3.14.3.2.27");
 
-    static final DERObjectIdentifier    sha1WithRSA             = new DERObjectIdentifier("1.3.14.3.2.29");
+    static final ASN1ObjectIdentifier    sha1WithRSA             = new ASN1ObjectIdentifier("1.3.14.3.2.29");
     
     // ElGamal Algorithm OBJECT IDENTIFIER ::=    
     // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }
     //
-    static final DERObjectIdentifier    elGamalAlgorithm        = new DERObjectIdentifier("1.3.14.7.2.1.1");
+    static final ASN1ObjectIdentifier    elGamalAlgorithm        = new ASN1ObjectIdentifier("1.3.14.7.2.1.1");
 
 }
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java b/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java
index 23772ce..73c2e94 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java
@@ -32,12 +32,12 @@
             return (CertificationRequest)o;
         }
 
-        if (o instanceof ASN1Sequence)
+        if (o != null)
         {
-            return new CertificationRequest((ASN1Sequence)o);
+            return new CertificationRequest(ASN1Sequence.getInstance(o));
         }
 
-        throw new IllegalArgumentException("Invalid object: " + o.getClass().getName());
+        return null;
     }
 
     protected CertificationRequest()
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java b/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
index 4b737ea..bf3b0a8 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
@@ -8,6 +8,7 @@
 import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.asn1.x509.X509Name;
 
@@ -53,6 +54,21 @@
     }
 
     public CertificationRequestInfo(
+        X500Name subject,
+        SubjectPublicKeyInfo    pkInfo,
+        ASN1Set                 attributes)
+    {
+        this.subject = X509Name.getInstance(subject.getDERObject());
+        this.subjectPKInfo = pkInfo;
+        this.attributes = attributes;
+
+        if ((subject == null) || (version == null) || (subjectPKInfo == null))
+        {
+            throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator.");
+        }
+    }
+
+    public CertificationRequestInfo(
         X509Name                subject,
         SubjectPublicKeyInfo    pkInfo,
         ASN1Set                 attributes)
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java
index 75b81b4..7fa8e08 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java
@@ -1,6 +1,16 @@
 package org.bouncycastle.asn1.pkcs;
 
-import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.BERTaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
 /**
@@ -86,7 +96,7 @@
         {
             DERTaggedObject o = (DERTaggedObject)data.getObjectAt(2);
 
-            return ASN1OctetString.getInstance(o.getObject());
+            return ASN1OctetString.getInstance(o, false);
         }
 
         return null;
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
index eb9b326..8f06c23 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
@@ -2,36 +2,53 @@
 
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
 public class EncryptionScheme
     extends AlgorithmIdentifier
-{   
-    DERObject   objectId;
-    DERObject   obj;
+{
+    public EncryptionScheme(
+        DERObjectIdentifier objectId,
+        DEREncodable parameters)
+    {
+        super(objectId, parameters);
+    }
 
     EncryptionScheme(
         ASN1Sequence  seq)
     {   
-        super(seq);
-        
-        objectId = (DERObject)seq.getObjectAt(0);
-        obj = (DERObject)seq.getObjectAt(1);
+        this((DERObjectIdentifier)seq.getObjectAt(0), seq.getObjectAt(1));
+    }
+
+    public static final AlgorithmIdentifier getInstance(Object obj)
+    {
+        if (obj instanceof EncryptionScheme)
+        {
+            return (EncryptionScheme)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new EncryptionScheme((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
     }
 
     public DERObject getObject()
     {
-        return obj;
+        return (DERObject)getParameters();
     }
 
     public DERObject getDERObject()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
-        v.add(objectId);
-        v.add(obj);
+        v.add(getObjectId());
+        v.add(getParameters());
 
         return new DERSequence(v);
     }
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java b/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
index 50c9ef2..08dd94f 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
@@ -14,7 +14,7 @@
         super(seq);
     }
     
-    KeyDerivationFunc(
+    public KeyDerivationFunc(
         DERObjectIdentifier id,
         ASN1Encodable       params)
     {
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java b/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java
new file mode 100644
index 0000000..f24cd9a
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java
@@ -0,0 +1,73 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+public class PBEParameter
+    extends ASN1Encodable
+{
+    DERInteger      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 DERInteger(iterations);
+    }
+
+    public PBEParameter(
+        ASN1Sequence  seq)
+    {
+        salt = (ASN1OctetString)seq.getObjectAt(0);
+        iterations = (DERInteger)seq.getObjectAt(1);
+    }
+
+    public static PBEParameter getInstance(
+        Object  obj)
+    {
+        if (obj instanceof PBEParameter)
+        {
+            return (PBEParameter)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new PBEParameter((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+    }
+
+    public BigInteger getIterationCount()
+    {
+        return iterations.getValue();
+    }
+
+    public byte[] getSalt()
+    {
+        return salt.getOctets();
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(salt);
+        v.add(iterations);
+
+        return new DERSequence(v);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java b/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
index 57c773c..c96d169 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
@@ -5,6 +5,7 @@
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
@@ -15,11 +16,27 @@
     private KeyDerivationFunc   func;
     private EncryptionScheme    scheme;
 
+    public static PBES2Parameters getInstance(
+        Object  obj)
+    {
+        if (obj== null || obj instanceof PBES2Parameters)
+        {
+            return (PBES2Parameters)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new PBES2Parameters((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+    }
+
     public PBES2Parameters(
         ASN1Sequence  obj)
     {
         Enumeration e = obj.getObjects();
-        ASN1Sequence  funcSeq = (ASN1Sequence)e.nextElement();
+        ASN1Sequence  funcSeq = ASN1Sequence.getInstance(((DEREncodable)e.nextElement()).getDERObject());
 
         if (funcSeq.getObjectAt(0).equals(id_PBKDF2))
         {
@@ -30,7 +47,7 @@
             func = new KeyDerivationFunc(funcSeq);
         }
 
-        scheme = new EncryptionScheme((ASN1Sequence)e.nextElement());
+        scheme = (EncryptionScheme)EncryptionScheme.getInstance(e.nextElement());
     }
 
     public KeyDerivationFunc getKeyDerivationFunc()
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
index a49b0b3..7bec34b 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.pkcs;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface PKCSObjectIdentifiers
 {
@@ -8,213 +8,221 @@
     // pkcs-1 OBJECT IDENTIFIER ::= {
     //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
     //
-    static final String                 pkcs_1                    = "1.2.840.113549.1.1";
-    static final DERObjectIdentifier    rsaEncryption             = new DERObjectIdentifier(pkcs_1 + ".1");
+    static final ASN1ObjectIdentifier    pkcs_1                    = new ASN1ObjectIdentifier("1.2.840.113549.1.1");
+    static final ASN1ObjectIdentifier    rsaEncryption             = pkcs_1.branch("1");
     // BEGIN android-removed
-    // Dropping MD2
-    // static final DERObjectIdentifier    md2WithRSAEncryption      = new DERObjectIdentifier(pkcs_1 + ".2");
+    // static final ASN1ObjectIdentifier    md2WithRSAEncryption      = pkcs_1.branch("2");
+    // static final ASN1ObjectIdentifier    md4WithRSAEncryption      = pkcs_1.branch("3");
     // END android-removed
-    static final DERObjectIdentifier    md4WithRSAEncryption      = new DERObjectIdentifier(pkcs_1 + ".3");
-    static final DERObjectIdentifier    md5WithRSAEncryption      = new DERObjectIdentifier(pkcs_1 + ".4");
-    static final DERObjectIdentifier    sha1WithRSAEncryption     = new DERObjectIdentifier(pkcs_1 + ".5");
-    static final DERObjectIdentifier    srsaOAEPEncryptionSET     = new DERObjectIdentifier(pkcs_1 + ".6");
-    static final DERObjectIdentifier    id_RSAES_OAEP             = new DERObjectIdentifier(pkcs_1 + ".7");
-    static final DERObjectIdentifier    id_mgf1                   = new DERObjectIdentifier(pkcs_1 + ".8");
-    static final DERObjectIdentifier    id_pSpecified             = new DERObjectIdentifier(pkcs_1 + ".9");
-    static final DERObjectIdentifier    id_RSASSA_PSS             = new DERObjectIdentifier(pkcs_1 + ".10");
-    static final DERObjectIdentifier    sha256WithRSAEncryption   = new DERObjectIdentifier(pkcs_1 + ".11");
-    static final DERObjectIdentifier    sha384WithRSAEncryption   = new DERObjectIdentifier(pkcs_1 + ".12");
-    static final DERObjectIdentifier    sha512WithRSAEncryption   = new DERObjectIdentifier(pkcs_1 + ".13");
-    static final DERObjectIdentifier    sha224WithRSAEncryption   = new DERObjectIdentifier(pkcs_1 + ".14");
+    static final ASN1ObjectIdentifier    md5WithRSAEncryption      = pkcs_1.branch("4");
+    static final ASN1ObjectIdentifier    sha1WithRSAEncryption     = pkcs_1.branch("5");
+    static final ASN1ObjectIdentifier    srsaOAEPEncryptionSET     = pkcs_1.branch("6");
+    static final ASN1ObjectIdentifier    id_RSAES_OAEP             = pkcs_1.branch("7");
+    static final ASN1ObjectIdentifier    id_mgf1                   = pkcs_1.branch("8");
+    static final ASN1ObjectIdentifier    id_pSpecified             = pkcs_1.branch("9");
+    static final ASN1ObjectIdentifier    id_RSASSA_PSS             = pkcs_1.branch("10");
+    static final ASN1ObjectIdentifier    sha256WithRSAEncryption   = pkcs_1.branch("11");
+    static final ASN1ObjectIdentifier    sha384WithRSAEncryption   = pkcs_1.branch("12");
+    static final ASN1ObjectIdentifier    sha512WithRSAEncryption   = pkcs_1.branch("13");
+    // BEGIN android-removed
+    // static final ASN1ObjectIdentifier    sha224WithRSAEncryption   = pkcs_1.branch("14");
+    // END android-removed
 
     //
     // pkcs-3 OBJECT IDENTIFIER ::= {
     //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 }
     //
-    static final String                 pkcs_3                  = "1.2.840.113549.1.3";
-    static final DERObjectIdentifier    dhKeyAgreement          = new DERObjectIdentifier(pkcs_3 + ".1");
+    static final ASN1ObjectIdentifier    pkcs_3                  = new ASN1ObjectIdentifier("1.2.840.113549.1.3");
+    static final ASN1ObjectIdentifier    dhKeyAgreement          = pkcs_3.branch("1");
 
     //
     // pkcs-5 OBJECT IDENTIFIER ::= {
     //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 }
     //
-    static final String                 pkcs_5                  = "1.2.840.113549.1.5";
+    static final ASN1ObjectIdentifier    pkcs_5                  = new ASN1ObjectIdentifier("1.2.840.113549.1.5");
 
-    static final DERObjectIdentifier    pbeWithMD2AndDES_CBC    = new DERObjectIdentifier(pkcs_5 + ".1");
-    static final DERObjectIdentifier    pbeWithMD2AndRC2_CBC    = new DERObjectIdentifier(pkcs_5 + ".4");
-    static final DERObjectIdentifier    pbeWithMD5AndDES_CBC    = new DERObjectIdentifier(pkcs_5 + ".3");
-    static final DERObjectIdentifier    pbeWithMD5AndRC2_CBC    = new DERObjectIdentifier(pkcs_5 + ".6");
-    static final DERObjectIdentifier    pbeWithSHA1AndDES_CBC   = new DERObjectIdentifier(pkcs_5 + ".10");
-    static final DERObjectIdentifier    pbeWithSHA1AndRC2_CBC   = new DERObjectIdentifier(pkcs_5 + ".11");
+    static final ASN1ObjectIdentifier    pbeWithMD2AndDES_CBC    = pkcs_5.branch("1");
+    static final ASN1ObjectIdentifier    pbeWithMD2AndRC2_CBC    = pkcs_5.branch("4");
+    static final ASN1ObjectIdentifier    pbeWithMD5AndDES_CBC    = pkcs_5.branch("3");
+    static final ASN1ObjectIdentifier    pbeWithMD5AndRC2_CBC    = pkcs_5.branch("6");
+    static final ASN1ObjectIdentifier    pbeWithSHA1AndDES_CBC   = pkcs_5.branch("10");
+    static final ASN1ObjectIdentifier    pbeWithSHA1AndRC2_CBC   = pkcs_5.branch("11");
 
-    static final DERObjectIdentifier    id_PBES2                = new DERObjectIdentifier(pkcs_5 + ".13");
+    static final ASN1ObjectIdentifier    id_PBES2                = pkcs_5.branch("13");
 
-    static final DERObjectIdentifier    id_PBKDF2               = new DERObjectIdentifier(pkcs_5 + ".12");
+    static final ASN1ObjectIdentifier    id_PBKDF2               = pkcs_5.branch("12");
 
     //
     // encryptionAlgorithm OBJECT IDENTIFIER ::= {
     //       iso(1) member-body(2) us(840) rsadsi(113549) 3 }
     //
-    static final String                 encryptionAlgorithm     = "1.2.840.113549.3";
+    static final ASN1ObjectIdentifier    encryptionAlgorithm     = new ASN1ObjectIdentifier("1.2.840.113549.3");
 
-    static final DERObjectIdentifier    des_EDE3_CBC            = new DERObjectIdentifier(encryptionAlgorithm + ".7");
-    static final DERObjectIdentifier    RC2_CBC                 = new DERObjectIdentifier(encryptionAlgorithm + ".2");
+    static final ASN1ObjectIdentifier    des_EDE3_CBC            = encryptionAlgorithm.branch("7");
+    static final ASN1ObjectIdentifier    RC2_CBC                 = encryptionAlgorithm.branch("2");
 
     //
     // object identifiers for digests
     //
-    static final String                 digestAlgorithm     = "1.2.840.113549.2";
+    static final 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
-    // Dropping MD2
-    // static final DERObjectIdentifier    md2                     = new DERObjectIdentifier(digestAlgorithm + ".2");
+    // static final ASN1ObjectIdentifier    md2                    = digestAlgorithm.branch("2");
     // END android-removed
 
     //
     // md4 OBJECT IDENTIFIER ::=
     //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4}
     //
-    static final DERObjectIdentifier    md4 = new DERObjectIdentifier(digestAlgorithm + ".4");
+    // BEGIN android-removed
+    // static final ASN1ObjectIdentifier    md4 = digestAlgorithm.branch("4");
+    // END android-removed
 
     //
     // md5 OBJECT IDENTIFIER ::=
     //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}
     //
-    static final DERObjectIdentifier    md5                     = new DERObjectIdentifier(digestAlgorithm + ".5");
+    static final ASN1ObjectIdentifier    md5                     = digestAlgorithm.branch("5");
 
-    static final DERObjectIdentifier    id_hmacWithSHA1         = new DERObjectIdentifier(digestAlgorithm + ".7");
-    static final DERObjectIdentifier    id_hmacWithSHA224       = new DERObjectIdentifier(digestAlgorithm + ".8");
-    static final DERObjectIdentifier    id_hmacWithSHA256       = new DERObjectIdentifier(digestAlgorithm + ".9");
-    static final DERObjectIdentifier    id_hmacWithSHA384       = new DERObjectIdentifier(digestAlgorithm + ".10");
-    static final DERObjectIdentifier    id_hmacWithSHA512       = new DERObjectIdentifier(digestAlgorithm + ".11");
+    static final ASN1ObjectIdentifier    id_hmacWithSHA1         = digestAlgorithm.branch("7");
+    // BEGIN android-removed
+    // static final ASN1ObjectIdentifier    id_hmacWithSHA224       = digestAlgorithm.branch("8");
+    // END android-removed
+    static final ASN1ObjectIdentifier    id_hmacWithSHA256       = digestAlgorithm.branch("9");
+    static final ASN1ObjectIdentifier    id_hmacWithSHA384       = digestAlgorithm.branch("10");
+    static final ASN1ObjectIdentifier    id_hmacWithSHA512       = digestAlgorithm.branch("11");
 
     //
     // pkcs-7 OBJECT IDENTIFIER ::= {
     //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 }
     //
     static final String                 pkcs_7                  = "1.2.840.113549.1.7";
-    static final DERObjectIdentifier    data                    = new DERObjectIdentifier(pkcs_7 + ".1");
-    static final DERObjectIdentifier    signedData              = new DERObjectIdentifier(pkcs_7 + ".2");
-    static final DERObjectIdentifier    envelopedData           = new DERObjectIdentifier(pkcs_7 + ".3");
-    static final DERObjectIdentifier    signedAndEnvelopedData  = new DERObjectIdentifier(pkcs_7 + ".4");
-    static final DERObjectIdentifier    digestedData            = new DERObjectIdentifier(pkcs_7 + ".5");
-    static final DERObjectIdentifier    encryptedData           = new DERObjectIdentifier(pkcs_7 + ".6");
+    static final ASN1ObjectIdentifier    data                    = new ASN1ObjectIdentifier(pkcs_7 + ".1");
+    static final ASN1ObjectIdentifier    signedData              = new ASN1ObjectIdentifier(pkcs_7 + ".2");
+    static final ASN1ObjectIdentifier    envelopedData           = new ASN1ObjectIdentifier(pkcs_7 + ".3");
+    static final ASN1ObjectIdentifier    signedAndEnvelopedData  = new ASN1ObjectIdentifier(pkcs_7 + ".4");
+    static final ASN1ObjectIdentifier    digestedData            = new ASN1ObjectIdentifier(pkcs_7 + ".5");
+    static final ASN1ObjectIdentifier    encryptedData           = new ASN1ObjectIdentifier(pkcs_7 + ".6");
 
     //
     // pkcs-9 OBJECT IDENTIFIER ::= {
     //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
     //
-    static final String                 pkcs_9                  = "1.2.840.113549.1.9";
+    static final ASN1ObjectIdentifier    pkcs_9                  = new ASN1ObjectIdentifier("1.2.840.113549.1.9");
 
-    static final DERObjectIdentifier    pkcs_9_at_emailAddress  = new DERObjectIdentifier(pkcs_9 + ".1");
-    static final DERObjectIdentifier    pkcs_9_at_unstructuredName = new DERObjectIdentifier(pkcs_9 + ".2");
-    static final DERObjectIdentifier    pkcs_9_at_contentType = new DERObjectIdentifier(pkcs_9 + ".3");
-    static final DERObjectIdentifier    pkcs_9_at_messageDigest = new DERObjectIdentifier(pkcs_9 + ".4");
-    static final DERObjectIdentifier    pkcs_9_at_signingTime = new DERObjectIdentifier(pkcs_9 + ".5");
-    static final DERObjectIdentifier    pkcs_9_at_counterSignature = new DERObjectIdentifier(pkcs_9 + ".6");
-    static final DERObjectIdentifier    pkcs_9_at_challengePassword = new DERObjectIdentifier(pkcs_9 + ".7");
-    static final DERObjectIdentifier    pkcs_9_at_unstructuredAddress = new DERObjectIdentifier(pkcs_9 + ".8");
-    static final DERObjectIdentifier    pkcs_9_at_extendedCertificateAttributes = new DERObjectIdentifier(pkcs_9 + ".9");
+    static final ASN1ObjectIdentifier    pkcs_9_at_emailAddress  = pkcs_9.branch("1");
+    static final ASN1ObjectIdentifier    pkcs_9_at_unstructuredName = pkcs_9.branch("2");
+    static final ASN1ObjectIdentifier    pkcs_9_at_contentType = pkcs_9.branch("3");
+    static final ASN1ObjectIdentifier    pkcs_9_at_messageDigest = pkcs_9.branch("4");
+    static final ASN1ObjectIdentifier    pkcs_9_at_signingTime = pkcs_9.branch("5");
+    static final ASN1ObjectIdentifier    pkcs_9_at_counterSignature = pkcs_9.branch("6");
+    static final ASN1ObjectIdentifier    pkcs_9_at_challengePassword = pkcs_9.branch("7");
+    static final ASN1ObjectIdentifier    pkcs_9_at_unstructuredAddress = pkcs_9.branch("8");
+    static final ASN1ObjectIdentifier    pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9");
 
-    static final DERObjectIdentifier    pkcs_9_at_signingDescription = new DERObjectIdentifier(pkcs_9 + ".13");
-    static final DERObjectIdentifier    pkcs_9_at_extensionRequest = new DERObjectIdentifier(pkcs_9 + ".14");
-    static final DERObjectIdentifier    pkcs_9_at_smimeCapabilities = new DERObjectIdentifier(pkcs_9 + ".15");
+    static final ASN1ObjectIdentifier    pkcs_9_at_signingDescription = pkcs_9.branch("13");
+    static final ASN1ObjectIdentifier    pkcs_9_at_extensionRequest = pkcs_9.branch("14");
+    static final ASN1ObjectIdentifier    pkcs_9_at_smimeCapabilities = pkcs_9.branch("15");
 
-    static final DERObjectIdentifier    pkcs_9_at_friendlyName  = new DERObjectIdentifier(pkcs_9 + ".20");
-    static final DERObjectIdentifier    pkcs_9_at_localKeyId    = new DERObjectIdentifier(pkcs_9 + ".21");
+    static final ASN1ObjectIdentifier    pkcs_9_at_friendlyName  = pkcs_9.branch("20");
+    static final ASN1ObjectIdentifier    pkcs_9_at_localKeyId    = pkcs_9.branch("21");
 
     /** @deprecated use x509Certificate instead */
-    static final DERObjectIdentifier    x509certType            = new DERObjectIdentifier(pkcs_9 + ".22.1");
+    static final ASN1ObjectIdentifier    x509certType            = pkcs_9.branch("22.1");
 
-    static final String                 certTypes               = pkcs_9 + ".22";
-    static final DERObjectIdentifier    x509Certificate         = new DERObjectIdentifier(certTypes + ".1");
-    static final DERObjectIdentifier    sdsiCertificate         = new DERObjectIdentifier(certTypes + ".2");
+    static final ASN1ObjectIdentifier    certTypes               = pkcs_9.branch("22");
+    static final ASN1ObjectIdentifier    x509Certificate         = certTypes.branch("1");
+    static final ASN1ObjectIdentifier    sdsiCertificate         = certTypes.branch("2");
 
-    static final String                 crlTypes                = pkcs_9 + ".23";
-    static final DERObjectIdentifier    x509Crl                 = new DERObjectIdentifier(crlTypes + ".1");
+    static final ASN1ObjectIdentifier    crlTypes                = pkcs_9.branch("23");
+    static final ASN1ObjectIdentifier    x509Crl                 = crlTypes.branch("1");
 
-    static final DERObjectIdentifier    id_alg_PWRI_KEK    = new DERObjectIdentifier(pkcs_9 + ".16.3.9");
+    static final ASN1ObjectIdentifier    id_alg_PWRI_KEK    = pkcs_9.branch("16.3.9");
 
     //
     // SMIME capability sub oids.
     //
-    static final DERObjectIdentifier    preferSignedData        = new DERObjectIdentifier(pkcs_9 + ".15.1");
-    static final DERObjectIdentifier    canNotDecryptAny        = new DERObjectIdentifier(pkcs_9 + ".15.2");
-    static final DERObjectIdentifier    sMIMECapabilitiesVersions = new DERObjectIdentifier(pkcs_9 + ".15.3");
+    static final ASN1ObjectIdentifier    preferSignedData        = pkcs_9.branch("15.1");
+    static final ASN1ObjectIdentifier    canNotDecryptAny        = pkcs_9.branch("15.2");
+    static final 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)}
     //
-    static String id_ct = "1.2.840.113549.1.9.16.1";
+    static final ASN1ObjectIdentifier    id_ct = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1");
 
-    static final DERObjectIdentifier    id_ct_authData          = new DERObjectIdentifier(id_ct + ".2");
-    static final DERObjectIdentifier    id_ct_TSTInfo           = new DERObjectIdentifier(id_ct + ".4");
-    static final DERObjectIdentifier    id_ct_compressedData    = new DERObjectIdentifier(id_ct + ".9");
-    static final DERObjectIdentifier    id_ct_authEnvelopedData = new DERObjectIdentifier(id_ct + ".23");
+    static final ASN1ObjectIdentifier    id_ct_authData          = id_ct.branch("2");
+    static final ASN1ObjectIdentifier    id_ct_TSTInfo           = id_ct.branch("4");
+    static final ASN1ObjectIdentifier    id_ct_compressedData    = id_ct.branch("9");
+    static final ASN1ObjectIdentifier    id_ct_authEnvelopedData = id_ct.branch("23");
+    static final ASN1ObjectIdentifier    id_ct_timestampedData   = id_ct.branch("31");
 
     //
     // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
     // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)}
     //
-    static String id_cti = "1.2.840.113549.1.9.16.6";
+    static final ASN1ObjectIdentifier    id_cti = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.6");
     
-    static final DERObjectIdentifier    id_cti_ets_proofOfOrigin  = new DERObjectIdentifier(id_cti + ".1");
-    static final DERObjectIdentifier    id_cti_ets_proofOfReceipt = new DERObjectIdentifier(id_cti + ".2");
-    static final DERObjectIdentifier    id_cti_ets_proofOfDelivery = new DERObjectIdentifier(id_cti + ".3");
-    static final DERObjectIdentifier    id_cti_ets_proofOfSender = new DERObjectIdentifier(id_cti + ".4");
-    static final DERObjectIdentifier    id_cti_ets_proofOfApproval = new DERObjectIdentifier(id_cti + ".5");
-    static final DERObjectIdentifier    id_cti_ets_proofOfCreation = new DERObjectIdentifier(id_cti + ".6");
+    static final ASN1ObjectIdentifier    id_cti_ets_proofOfOrigin  = id_cti.branch("1");
+    static final ASN1ObjectIdentifier    id_cti_ets_proofOfReceipt = id_cti.branch("2");
+    static final ASN1ObjectIdentifier    id_cti_ets_proofOfDelivery = id_cti.branch("3");
+    static final ASN1ObjectIdentifier    id_cti_ets_proofOfSender = id_cti.branch("4");
+    static final ASN1ObjectIdentifier    id_cti_ets_proofOfApproval = id_cti.branch("5");
+    static final 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)}
     //
-    static String id_aa = "1.2.840.113549.1.9.16.2";
+    static final ASN1ObjectIdentifier    id_aa = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.2");
 
-    static final DERObjectIdentifier id_aa_receiptRequest = new DERObjectIdentifier(id_aa + ".1");
+
+    static final ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch("1");
     
-    static final DERObjectIdentifier id_aa_contentHint = new DERObjectIdentifier(id_aa + ".4"); // See RFC 2634
+    static final ASN1ObjectIdentifier id_aa_contentHint = id_aa.branch("4"); // See RFC 2634
+    static final ASN1ObjectIdentifier id_aa_msgSigDigest = id_aa.branch("5");
+    static final ASN1ObjectIdentifier id_aa_contentReference = id_aa.branch("10");
     /*
      * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11}
      * 
      */
-    static final DERObjectIdentifier id_aa_encrypKeyPref = new DERObjectIdentifier(id_aa + ".11");
-    static final DERObjectIdentifier id_aa_signingCertificate = new DERObjectIdentifier(id_aa + ".12");
-    static final DERObjectIdentifier id_aa_signingCertificateV2 = new DERObjectIdentifier(id_aa + ".47");
+    static final ASN1ObjectIdentifier id_aa_encrypKeyPref = id_aa.branch("11");
+    static final ASN1ObjectIdentifier id_aa_signingCertificate = id_aa.branch("12");
+    static final ASN1ObjectIdentifier id_aa_signingCertificateV2 = id_aa.branch("47");
 
-    static final DERObjectIdentifier id_aa_contentIdentifier = new DERObjectIdentifier(id_aa + ".7"); // See RFC 2634
+    static final ASN1ObjectIdentifier id_aa_contentIdentifier = id_aa.branch("7"); // See RFC 2634
 
     /*
      * RFC 3126
      */
-    static final DERObjectIdentifier id_aa_signatureTimeStampToken = new DERObjectIdentifier(id_aa + ".14");
+    static final ASN1ObjectIdentifier id_aa_signatureTimeStampToken = id_aa.branch("14");
     
-    static final DERObjectIdentifier id_aa_ets_sigPolicyId = new DERObjectIdentifier(id_aa + ".15");
-    static final DERObjectIdentifier id_aa_ets_commitmentType = new DERObjectIdentifier(id_aa + ".16");
-    static final DERObjectIdentifier id_aa_ets_signerLocation = new DERObjectIdentifier(id_aa + ".17");
-    static final DERObjectIdentifier id_aa_ets_signerAttr = new DERObjectIdentifier(id_aa + ".18");
-    static final DERObjectIdentifier id_aa_ets_otherSigCert = new DERObjectIdentifier(id_aa + ".19");
-    static final DERObjectIdentifier id_aa_ets_contentTimestamp = new DERObjectIdentifier(id_aa + ".20");
-    static final DERObjectIdentifier id_aa_ets_certificateRefs = new DERObjectIdentifier(id_aa + ".21");
-    static final DERObjectIdentifier id_aa_ets_revocationRefs = new DERObjectIdentifier(id_aa + ".22");
-    static final DERObjectIdentifier id_aa_ets_certValues = new DERObjectIdentifier(id_aa + ".23");
-    static final DERObjectIdentifier id_aa_ets_revocationValues = new DERObjectIdentifier(id_aa + ".24");
-    static final DERObjectIdentifier id_aa_ets_escTimeStamp = new DERObjectIdentifier(id_aa + ".25");
-    static final DERObjectIdentifier id_aa_ets_certCRLTimestamp = new DERObjectIdentifier(id_aa + ".26");
-    static final DERObjectIdentifier id_aa_ets_archiveTimestamp = new DERObjectIdentifier(id_aa + ".27");
+    static final ASN1ObjectIdentifier id_aa_ets_sigPolicyId = id_aa.branch("15");
+    static final ASN1ObjectIdentifier id_aa_ets_commitmentType = id_aa.branch("16");
+    static final ASN1ObjectIdentifier id_aa_ets_signerLocation = id_aa.branch("17");
+    static final ASN1ObjectIdentifier id_aa_ets_signerAttr = id_aa.branch("18");
+    static final ASN1ObjectIdentifier id_aa_ets_otherSigCert = id_aa.branch("19");
+    static final ASN1ObjectIdentifier id_aa_ets_contentTimestamp = id_aa.branch("20");
+    static final ASN1ObjectIdentifier id_aa_ets_certificateRefs = id_aa.branch("21");
+    static final ASN1ObjectIdentifier id_aa_ets_revocationRefs = id_aa.branch("22");
+    static final ASN1ObjectIdentifier id_aa_ets_certValues = id_aa.branch("23");
+    static final ASN1ObjectIdentifier id_aa_ets_revocationValues = id_aa.branch("24");
+    static final ASN1ObjectIdentifier id_aa_ets_escTimeStamp = id_aa.branch("25");
+    static final ASN1ObjectIdentifier id_aa_ets_certCRLTimestamp = id_aa.branch("26");
+    static final ASN1ObjectIdentifier id_aa_ets_archiveTimestamp = id_aa.branch("27");
 
     /** @deprecated use id_aa_ets_sigPolicyId instead */
-    static final DERObjectIdentifier id_aa_sigPolicyId = id_aa_ets_sigPolicyId;
+    static final ASN1ObjectIdentifier id_aa_sigPolicyId = id_aa_ets_sigPolicyId;
     /** @deprecated use id_aa_ets_commitmentType instead */
-    static final DERObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType;
+    static final ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType;
     /** @deprecated use id_aa_ets_signerLocation instead */
-    static final DERObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation;
+    static final ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation;
     /** @deprecated use id_aa_ets_otherSigCert instead */
-    static final DERObjectIdentifier id_aa_otherSigCert = id_aa_ets_otherSigCert;
+    static final ASN1ObjectIdentifier id_aa_otherSigCert = id_aa_ets_otherSigCert;
     
     //
     // id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
@@ -222,33 +230,33 @@
     //
     final String id_spq = "1.2.840.113549.1.9.16.5";
 
-    static final DERObjectIdentifier id_spq_ets_uri = new DERObjectIdentifier(id_spq + ".1");
-    static final DERObjectIdentifier id_spq_ets_unotice = new DERObjectIdentifier(id_spq + ".2");
+    static final ASN1ObjectIdentifier id_spq_ets_uri = new ASN1ObjectIdentifier(id_spq + ".1");
+    static final 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 }
     //
-    static final String                 pkcs_12                  = "1.2.840.113549.1.12";
-    static final String                 bagtypes                 = pkcs_12 + ".10.1";
+    static final ASN1ObjectIdentifier   pkcs_12                  = new ASN1ObjectIdentifier("1.2.840.113549.1.12");
+    static final ASN1ObjectIdentifier   bagtypes                 = pkcs_12.branch("10.1");
 
-    static final DERObjectIdentifier    keyBag                  = new DERObjectIdentifier(bagtypes + ".1");
-    static final DERObjectIdentifier    pkcs8ShroudedKeyBag     = new DERObjectIdentifier(bagtypes + ".2");
-    static final DERObjectIdentifier    certBag                 = new DERObjectIdentifier(bagtypes + ".3");
-    static final DERObjectIdentifier    crlBag                  = new DERObjectIdentifier(bagtypes + ".4");
-    static final DERObjectIdentifier    secretBag               = new DERObjectIdentifier(bagtypes + ".5");
-    static final DERObjectIdentifier    safeContentsBag         = new DERObjectIdentifier(bagtypes + ".6");
+    static final ASN1ObjectIdentifier    keyBag                  = bagtypes.branch("1");
+    static final ASN1ObjectIdentifier    pkcs8ShroudedKeyBag     = bagtypes.branch("2");
+    static final ASN1ObjectIdentifier    certBag                 = bagtypes.branch("3");
+    static final ASN1ObjectIdentifier    crlBag                  = bagtypes.branch("4");
+    static final ASN1ObjectIdentifier    secretBag               = bagtypes.branch("5");
+    static final ASN1ObjectIdentifier    safeContentsBag         = bagtypes.branch("6");
 
-    static final String pkcs_12PbeIds  = pkcs_12 + ".1";
+    static final ASN1ObjectIdentifier    pkcs_12PbeIds  = pkcs_12.branch("1");
 
-    static final DERObjectIdentifier    pbeWithSHAAnd128BitRC4 = new DERObjectIdentifier(pkcs_12PbeIds + ".1");
-    static final DERObjectIdentifier    pbeWithSHAAnd40BitRC4  = new DERObjectIdentifier(pkcs_12PbeIds + ".2");
-    static final DERObjectIdentifier    pbeWithSHAAnd3_KeyTripleDES_CBC = new DERObjectIdentifier(pkcs_12PbeIds + ".3");
-    static final DERObjectIdentifier    pbeWithSHAAnd2_KeyTripleDES_CBC = new DERObjectIdentifier(pkcs_12PbeIds + ".4");
-    static final DERObjectIdentifier    pbeWithSHAAnd128BitRC2_CBC = new DERObjectIdentifier(pkcs_12PbeIds + ".5");
-    static final DERObjectIdentifier    pbewithSHAAnd40BitRC2_CBC = new DERObjectIdentifier(pkcs_12PbeIds + ".6");
+    static final ASN1ObjectIdentifier    pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch("1");
+    static final ASN1ObjectIdentifier    pbeWithSHAAnd40BitRC4  = pkcs_12PbeIds.branch("2");
+    static final ASN1ObjectIdentifier    pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch("3");
+    static final ASN1ObjectIdentifier    pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch("4");
+    static final ASN1ObjectIdentifier    pbeWithSHAAnd128BitRC2_CBC = pkcs_12PbeIds.branch("5");
+    static final ASN1ObjectIdentifier    pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6");
 
-    static final DERObjectIdentifier    id_alg_CMS3DESwrap = new DERObjectIdentifier("1.2.840.113549.1.9.16.3.6");
-    static final DERObjectIdentifier    id_alg_CMSRC2wrap = new DERObjectIdentifier("1.2.840.113549.1.9.16.3.7");
+    static final ASN1ObjectIdentifier    id_alg_CMS3DESwrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6");
+    static final ASN1ObjectIdentifier    id_alg_CMSRC2wrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7");
 }
 
diff --git a/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java b/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
index a7fff2f..9e84499 100644
--- a/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
@@ -1,5 +1,9 @@
 package org.bouncycastle.asn1.pkcs;
 
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1InputStream;
@@ -14,10 +18,6 @@
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
-import java.io.IOException;
-import java.math.BigInteger;
-import java.util.Enumeration;
-
 public class PrivateKeyInfo
     extends ASN1Encodable
 {
@@ -39,12 +39,12 @@
         {
             return (PrivateKeyInfo)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new PrivateKeyInfo((ASN1Sequence)obj);
+            return new PrivateKeyInfo(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
         
     public PrivateKeyInfo(
diff --git a/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
index fe066f1..8b19cd6 100644
--- a/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.sec;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 
 public interface SECObjectIdentifiers
@@ -10,41 +10,41 @@
      *        iso(1) identified-organization(3) certicom(132) curve(0)
      *  }
      */
-    static final DERObjectIdentifier ellipticCurve = new DERObjectIdentifier("1.3.132.0");
+    static final ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier("1.3.132.0");
 
-    static final DERObjectIdentifier sect163k1 = new DERObjectIdentifier(ellipticCurve + ".1");
-    static final DERObjectIdentifier sect163r1 = new DERObjectIdentifier(ellipticCurve + ".2");
-    static final DERObjectIdentifier sect239k1 = new DERObjectIdentifier(ellipticCurve + ".3");
-    static final DERObjectIdentifier sect113r1 = new DERObjectIdentifier(ellipticCurve + ".4");
-    static final DERObjectIdentifier sect113r2 = new DERObjectIdentifier(ellipticCurve + ".5");
-    static final DERObjectIdentifier secp112r1 = new DERObjectIdentifier(ellipticCurve + ".6");
-    static final DERObjectIdentifier secp112r2 = new DERObjectIdentifier(ellipticCurve + ".7");
-    static final DERObjectIdentifier secp160r1 = new DERObjectIdentifier(ellipticCurve + ".8");
-    static final DERObjectIdentifier secp160k1 = new DERObjectIdentifier(ellipticCurve + ".9");
-    static final DERObjectIdentifier secp256k1 = new DERObjectIdentifier(ellipticCurve + ".10");
-    static final DERObjectIdentifier sect163r2 = new DERObjectIdentifier(ellipticCurve + ".15");
-    static final DERObjectIdentifier sect283k1 = new DERObjectIdentifier(ellipticCurve + ".16");
-    static final DERObjectIdentifier sect283r1 = new DERObjectIdentifier(ellipticCurve + ".17");
-    static final DERObjectIdentifier sect131r1 = new DERObjectIdentifier(ellipticCurve + ".22");
-    static final DERObjectIdentifier sect131r2 = new DERObjectIdentifier(ellipticCurve + ".23");
-    static final DERObjectIdentifier sect193r1 = new DERObjectIdentifier(ellipticCurve + ".24");
-    static final DERObjectIdentifier sect193r2 = new DERObjectIdentifier(ellipticCurve + ".25");
-    static final DERObjectIdentifier sect233k1 = new DERObjectIdentifier(ellipticCurve + ".26");
-    static final DERObjectIdentifier sect233r1 = new DERObjectIdentifier(ellipticCurve + ".27");
-    static final DERObjectIdentifier secp128r1 = new DERObjectIdentifier(ellipticCurve + ".28");
-    static final DERObjectIdentifier secp128r2 = new DERObjectIdentifier(ellipticCurve + ".29");
-    static final DERObjectIdentifier secp160r2 = new DERObjectIdentifier(ellipticCurve + ".30");
-    static final DERObjectIdentifier secp192k1 = new DERObjectIdentifier(ellipticCurve + ".31");
-    static final DERObjectIdentifier secp224k1 = new DERObjectIdentifier(ellipticCurve + ".32");
-    static final DERObjectIdentifier secp224r1 = new DERObjectIdentifier(ellipticCurve + ".33");
-    static final DERObjectIdentifier secp384r1 = new DERObjectIdentifier(ellipticCurve + ".34");
-    static final DERObjectIdentifier secp521r1 = new DERObjectIdentifier(ellipticCurve + ".35");
-    static final DERObjectIdentifier sect409k1 = new DERObjectIdentifier(ellipticCurve + ".36");
-    static final DERObjectIdentifier sect409r1 = new DERObjectIdentifier(ellipticCurve + ".37");
-    static final DERObjectIdentifier sect571k1 = new DERObjectIdentifier(ellipticCurve + ".38");
-    static final DERObjectIdentifier sect571r1 = new DERObjectIdentifier(ellipticCurve + ".39");
+    static final ASN1ObjectIdentifier sect163k1 = ellipticCurve.branch("1");
+    static final ASN1ObjectIdentifier sect163r1 = ellipticCurve.branch("2");
+    static final ASN1ObjectIdentifier sect239k1 = ellipticCurve.branch("3");
+    static final ASN1ObjectIdentifier sect113r1 = ellipticCurve.branch("4");
+    static final ASN1ObjectIdentifier sect113r2 = ellipticCurve.branch("5");
+    static final ASN1ObjectIdentifier secp112r1 = ellipticCurve.branch("6");
+    static final ASN1ObjectIdentifier secp112r2 = ellipticCurve.branch("7");
+    static final ASN1ObjectIdentifier secp160r1 = ellipticCurve.branch("8");
+    static final ASN1ObjectIdentifier secp160k1 = ellipticCurve.branch("9");
+    static final ASN1ObjectIdentifier secp256k1 = ellipticCurve.branch("10");
+    static final ASN1ObjectIdentifier sect163r2 = ellipticCurve.branch("15");
+    static final ASN1ObjectIdentifier sect283k1 = ellipticCurve.branch("16");
+    static final ASN1ObjectIdentifier sect283r1 = ellipticCurve.branch("17");
+    static final ASN1ObjectIdentifier sect131r1 = ellipticCurve.branch("22");
+    static final ASN1ObjectIdentifier sect131r2 = ellipticCurve.branch("23");
+    static final ASN1ObjectIdentifier sect193r1 = ellipticCurve.branch("24");
+    static final ASN1ObjectIdentifier sect193r2 = ellipticCurve.branch("25");
+    static final ASN1ObjectIdentifier sect233k1 = ellipticCurve.branch("26");
+    static final ASN1ObjectIdentifier sect233r1 = ellipticCurve.branch("27");
+    static final ASN1ObjectIdentifier secp128r1 = ellipticCurve.branch("28");
+    static final ASN1ObjectIdentifier secp128r2 = ellipticCurve.branch("29");
+    static final ASN1ObjectIdentifier secp160r2 = ellipticCurve.branch("30");
+    static final ASN1ObjectIdentifier secp192k1 = ellipticCurve.branch("31");
+    static final ASN1ObjectIdentifier secp224k1 = ellipticCurve.branch("32");
+    static final ASN1ObjectIdentifier secp224r1 = ellipticCurve.branch("33");
+    static final ASN1ObjectIdentifier secp384r1 = ellipticCurve.branch("34");
+    static final ASN1ObjectIdentifier secp521r1 = ellipticCurve.branch("35");
+    static final ASN1ObjectIdentifier sect409k1 = ellipticCurve.branch("36");
+    static final ASN1ObjectIdentifier sect409r1 = ellipticCurve.branch("37");
+    static final ASN1ObjectIdentifier sect571k1 = ellipticCurve.branch("38");
+    static final ASN1ObjectIdentifier sect571r1 = ellipticCurve.branch("39");
 
-    static final DERObjectIdentifier secp192r1 = X9ObjectIdentifiers.prime192v1;
-    static final DERObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1;
+    static final ASN1ObjectIdentifier secp192r1 = X9ObjectIdentifiers.prime192v1;
+    static final ASN1ObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1;
 
 }
diff --git a/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
index 32a2ed6..df9a0ff 100644
--- a/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
@@ -1,42 +1,42 @@
 package org.bouncycastle.asn1.teletrust;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface TeleTrusTObjectIdentifiers
 {
-    static final String teleTrusTAlgorithm = "1.3.36.3";
+    static final ASN1ObjectIdentifier teleTrusTAlgorithm = new ASN1ObjectIdentifier("1.3.36.3");
 
-    static final DERObjectIdentifier    ripemd160           = new DERObjectIdentifier(teleTrusTAlgorithm + ".2.1");
-    static final DERObjectIdentifier    ripemd128           = new DERObjectIdentifier(teleTrusTAlgorithm + ".2.2");
-    static final DERObjectIdentifier    ripemd256           = new DERObjectIdentifier(teleTrusTAlgorithm + ".2.3");
+    static final ASN1ObjectIdentifier    ripemd160           = teleTrusTAlgorithm.branch("2.1");
+    static final ASN1ObjectIdentifier    ripemd128           = teleTrusTAlgorithm.branch("2.2");
+    static final ASN1ObjectIdentifier    ripemd256           = teleTrusTAlgorithm.branch("2.3");
 
-    static final String teleTrusTRSAsignatureAlgorithm = teleTrusTAlgorithm + ".3.1";
+    static final ASN1ObjectIdentifier teleTrusTRSAsignatureAlgorithm = teleTrusTAlgorithm.branch("3.1");
 
-    static final DERObjectIdentifier    rsaSignatureWithripemd160           = new DERObjectIdentifier(teleTrusTRSAsignatureAlgorithm + ".2");
-    static final DERObjectIdentifier    rsaSignatureWithripemd128           = new DERObjectIdentifier(teleTrusTRSAsignatureAlgorithm + ".3");
-    static final DERObjectIdentifier    rsaSignatureWithripemd256           = new DERObjectIdentifier(teleTrusTRSAsignatureAlgorithm + ".4");
+    static final ASN1ObjectIdentifier    rsaSignatureWithripemd160           = teleTrusTRSAsignatureAlgorithm.branch("2");
+    static final ASN1ObjectIdentifier    rsaSignatureWithripemd128           = teleTrusTRSAsignatureAlgorithm.branch("3");
+    static final ASN1ObjectIdentifier    rsaSignatureWithripemd256           = teleTrusTRSAsignatureAlgorithm.branch("4");
 
-    static final DERObjectIdentifier    ecSign = new DERObjectIdentifier(teleTrusTAlgorithm + ".3.2");
+    static final ASN1ObjectIdentifier    ecSign = teleTrusTAlgorithm.branch("3.2");
 
-    static final DERObjectIdentifier    ecSignWithSha1  = new DERObjectIdentifier(ecSign + ".1");
-    static final DERObjectIdentifier    ecSignWithRipemd160  = new DERObjectIdentifier(ecSign + ".2");
+    static final ASN1ObjectIdentifier    ecSignWithSha1  = ecSign.branch("1");
+    static final ASN1ObjectIdentifier    ecSignWithRipemd160  = ecSign.branch("2");
 
-    static final DERObjectIdentifier ecc_brainpool = new DERObjectIdentifier(teleTrusTAlgorithm + ".3.2.8");
-    static final DERObjectIdentifier ellipticCurve = new DERObjectIdentifier(ecc_brainpool + ".1");
-    static final DERObjectIdentifier versionOne = new DERObjectIdentifier(ellipticCurve + ".1");    
+    static final ASN1ObjectIdentifier ecc_brainpool = teleTrusTAlgorithm.branch("3.2.8");
+    static final ASN1ObjectIdentifier ellipticCurve = ecc_brainpool.branch("1");
+    static final ASN1ObjectIdentifier versionOne = ellipticCurve.branch("1");
 
-    static final DERObjectIdentifier brainpoolP160r1 = new DERObjectIdentifier(versionOne + ".1");
-    static final DERObjectIdentifier brainpoolP160t1 = new DERObjectIdentifier(versionOne + ".2");
-    static final DERObjectIdentifier brainpoolP192r1 = new DERObjectIdentifier(versionOne + ".3");
-    static final DERObjectIdentifier brainpoolP192t1 = new DERObjectIdentifier(versionOne + ".4");
-    static final DERObjectIdentifier brainpoolP224r1 = new DERObjectIdentifier(versionOne + ".5");
-    static final DERObjectIdentifier brainpoolP224t1 = new DERObjectIdentifier(versionOne + ".6");
-    static final DERObjectIdentifier brainpoolP256r1 = new DERObjectIdentifier(versionOne + ".7");
-    static final DERObjectIdentifier brainpoolP256t1 = new DERObjectIdentifier(versionOne + ".8");
-    static final DERObjectIdentifier brainpoolP320r1 = new DERObjectIdentifier(versionOne + ".9");
-    static final DERObjectIdentifier brainpoolP320t1 = new DERObjectIdentifier(versionOne+".10");
-    static final DERObjectIdentifier brainpoolP384r1 = new DERObjectIdentifier(versionOne+".11");
-    static final DERObjectIdentifier brainpoolP384t1 = new DERObjectIdentifier(versionOne+".12");
-    static final DERObjectIdentifier brainpoolP512r1 = new DERObjectIdentifier(versionOne+".13");
-    static final DERObjectIdentifier brainpoolP512t1 = new DERObjectIdentifier(versionOne+".14");
+    static final ASN1ObjectIdentifier brainpoolP160r1 = versionOne.branch("1");
+    static final ASN1ObjectIdentifier brainpoolP160t1 = versionOne.branch("2");
+    static final ASN1ObjectIdentifier brainpoolP192r1 = versionOne.branch("3");
+    static final ASN1ObjectIdentifier brainpoolP192t1 = versionOne.branch("4");
+    static final ASN1ObjectIdentifier brainpoolP224r1 = versionOne.branch("5");
+    static final ASN1ObjectIdentifier brainpoolP224t1 = versionOne.branch("6");
+    static final ASN1ObjectIdentifier brainpoolP256r1 = versionOne.branch("7");
+    static final ASN1ObjectIdentifier brainpoolP256t1 = versionOne.branch("8");
+    static final ASN1ObjectIdentifier brainpoolP320r1 = versionOne.branch("9");
+    static final ASN1ObjectIdentifier brainpoolP320t1 = versionOne.branch("10");
+    static final ASN1ObjectIdentifier brainpoolP384r1 = versionOne.branch("11");
+    static final ASN1ObjectIdentifier brainpoolP384t1 = versionOne.branch("12");
+    static final ASN1ObjectIdentifier brainpoolP512r1 = versionOne.branch("13");
+    static final ASN1ObjectIdentifier brainpoolP512t1 = versionOne.branch("14");
 }
diff --git a/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java b/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
index 7d4f999..272f374 100644
--- a/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
+++ b/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
@@ -8,7 +8,6 @@
 import org.bouncycastle.asn1.ASN1Set;
 import org.bouncycastle.asn1.BERApplicationSpecific;
 import org.bouncycastle.asn1.BERConstructedOctetString;
-import org.bouncycastle.asn1.BERConstructedSequence;
 import org.bouncycastle.asn1.BERSequence;
 import org.bouncycastle.asn1.BERSet;
 import org.bouncycastle.asn1.BERTaggedObject;
@@ -16,8 +15,6 @@
 import org.bouncycastle.asn1.DERBMPString;
 import org.bouncycastle.asn1.DERBitString;
 import org.bouncycastle.asn1.DERBoolean;
-import org.bouncycastle.asn1.DERConstructedSequence;
-import org.bouncycastle.asn1.DERConstructedSet;
 import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DEREnumerated;
 import org.bouncycastle.asn1.DERExternal;
@@ -63,15 +60,7 @@
             String          tab = indent + TAB;
 
             buf.append(indent);
-            if (obj instanceof BERConstructedSequence)
-            {
-                buf.append("BER ConstructedSequence");
-            }
-            else if (obj instanceof DERConstructedSequence)
-            {
-                buf.append("DER ConstructedSequence");
-            }
-            else if (obj instanceof BERSequence)
+            if (obj instanceof BERSequence)
             {
                 buf.append("BER Sequence");
             }
@@ -145,35 +134,6 @@
                 _dumpAsString(tab, verbose, o.getObject(), buf);
             }
         }
-        else if (obj instanceof DERConstructedSet)
-        {
-            Enumeration     e = ((ASN1Set)obj).getObjects();
-            String          tab = indent + TAB;
-
-            buf.append(indent);
-            buf.append("ConstructedSet");
-            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 DERObject)
-                {
-                    _dumpAsString(tab, verbose, (DERObject)o, buf);
-                }
-                else
-                {
-                    _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
-                }
-            }
-        }
         else if (obj instanceof BERSet)
         {
             Enumeration     e = ((ASN1Set)obj).getObjects();
diff --git a/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java b/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java
new file mode 100644
index 0000000..bbe2171
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java
@@ -0,0 +1,71 @@
+package org.bouncycastle.asn1.x500;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class AttributeTypeAndValue
+    extends ASN1Encodable
+{
+    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 DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(type);
+        v.add(value);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java b/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java
new file mode 100644
index 0000000..b76155c
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java
@@ -0,0 +1,125 @@
+package org.bouncycastle.asn1.x500;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1String;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBMPString;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERPrintableString;
+import org.bouncycastle.asn1.DERT61String;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.DERUniversalString;
+
+public class DirectoryString
+    extends ASN1Encodable
+    implements ASN1Choice, ASN1String
+{
+    private ASN1String string;
+
+    public static DirectoryString getInstance(Object o)
+    {
+        if (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 DERObject toASN1Object()
+    {
+        return ((DEREncodable)string).getDERObject();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x500/RDN.java b/src/main/java/org/bouncycastle/asn1/x500/RDN.java
new file mode 100644
index 0000000..700a918
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x500/RDN.java
@@ -0,0 +1,106 @@
+package org.bouncycastle.asn1.x500;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERSet;
+
+public class RDN
+    extends ASN1Encodable
+{
+    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
+     * @param 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.
+     */
+    public RDN(AttributeTypeAndValue[] aAndVs)
+    {
+        this.values = new DERSet(aAndVs);
+    }
+
+    public boolean isMultiValued()
+    {
+        return this.values.size() > 1;
+    }
+
+    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
+     */
+    public DERObject toASN1Object()
+    {
+        return values;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x500/X500Name.java b/src/main/java/org/bouncycastle/asn1/x500/X500Name.java
new file mode 100644
index 0000000..3166463
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x500/X500Name.java
@@ -0,0 +1,274 @@
+package org.bouncycastle.asn1.x500;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.asn1.x509.X509Name;
+
+/**
+ * <pre>
+ *     Name ::= CHOICE {
+ *                       RDNSequence }
+ *
+ *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+ *
+ *     AttributeTypeAndValue ::= SEQUENCE {
+ *                                   type  OBJECT IDENTIFIER,
+ *                                   value ANY }
+ * </pre>
+ */
+public class X500Name
+    extends ASN1Encodable
+    implements ASN1Choice
+{
+    private static X500NameStyle    defaultStyle = BCStyle.INSTANCE;
+
+    private boolean                 isHashCodeCalculated;
+    private int                     hashCodeValue;
+
+    private X500NameStyle style;
+    private RDN[] rdns;
+
+    public X500Name(X500NameStyle style, X500Name name)
+    {
+        this.rdns = name.rdns;
+        this.style = style;
+    }
+
+    /**
+     * 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 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 instanceof X509Name)
+        {
+            return new X500Name(ASN1Sequence.getInstance(((X509Name)obj).getDERObject()));
+        }
+        else if (obj != null)
+        {
+            return new X500Name(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 = 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 RDNs containing the attribute type given by OID in structure order.
+     *
+     * @param oid the type OID we are looking for.
+     * @return an array, possibly zero length, of RDN objects.
+     */
+    public RDN[] getRDNs(ASN1ObjectIdentifier oid)
+    {
+        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(oid))
+                    {
+                        res[count++] = rdn;
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                if (rdn.getFirst().getType().equals(oid))
+                {
+                    res[count++] = rdn;
+                }
+            }
+        }
+
+        RDN[] tmp = new RDN[count];
+
+        System.arraycopy(res, 0, tmp, 0, tmp.length);
+
+        return tmp;
+    }
+
+    public DERObject toASN1Object()
+    {
+        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;
+        }
+        
+        DERObject derO = ((DEREncodable)obj).getDERObject();
+
+        if (this.getDERObject().equals(derO))
+        {
+            return true;
+        }
+
+        try
+        {
+            return style.areEqual(this, new X500Name(ASN1Sequence.getInstance(((DEREncodable)obj).getDERObject())));
+        }
+        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/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java b/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java
new file mode 100644
index 0000000..30e871c
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java
@@ -0,0 +1,81 @@
+package org.bouncycastle.asn1.x500;
+
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public class X500NameBuilder
+{
+    private X500NameStyle template;
+    private Vector rdns = new Vector();
+
+    public X500NameBuilder(X500NameStyle template)
+    {
+        this.template = template;
+    }
+
+    public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, String value)
+    {
+        this.addRDN(oid, template.stringToValue(oid, value));
+
+        return this;
+    }
+
+    public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, ASN1Encodable value)
+    {
+        rdns.addElement(new RDN(oid, value));
+
+        return this;
+    }
+
+    public X500NameBuilder addRDN(AttributeTypeAndValue attrTAndV)
+    {
+        rdns.addElement(new RDN(attrTAndV));
+
+        return this;
+    }
+
+    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);
+    }
+
+    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);
+    }
+
+    public X500NameBuilder addMultiValuedRDN(AttributeTypeAndValue[] attrTAndVs)
+    {
+        rdns.addElement(new RDN(attrTAndVs));
+
+        return this;
+    }
+
+    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);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java b/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java
new file mode 100644
index 0000000..7a7c837
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java
@@ -0,0 +1,34 @@
+package org.bouncycastle.asn1.x500;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * 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 X500Name class
+ * will produce UTF8Strings in line with the current recommendations (RFC 3280).
+ * <p>
+ */
+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);
+
+    ASN1ObjectIdentifier attrNameToOID(String attrName);
+
+    boolean areEqual(X500Name name1, X500Name name2);
+
+    RDN[] fromString(String dirName);
+
+    int calculateHashCode(X500Name name);
+
+    String toString(X500Name name);
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x500/style/BCStrictStyle.java b/src/main/java/org/bouncycastle/asn1/x500/style/BCStrictStyle.java
new file mode 100644
index 0000000..af10fef
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x500/style/BCStrictStyle.java
@@ -0,0 +1,33 @@
+package org.bouncycastle.asn1.x500.style;
+
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * Variation of BCStyle that insists on strict ordering for equality
+ * and hashCode comparisons
+ */
+public class BCStrictStyle
+    extends BCStyle
+{
+    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/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java b/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
new file mode 100644
index 0000000..32f93ff
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
@@ -0,0 +1,544 @@
+package org.bouncycastle.asn1.x500.style;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERPrintableString;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.X500NameStyle;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+
+public class BCStyle
+    implements X500NameStyle
+{
+    public static final X500NameStyle INSTANCE = new BCStyle();
+
+    /**
+     * country code - StringType(SIZE(2))
+     */
+    public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6");
+
+    /**
+     * organization - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10");
+
+    /**
+     * organizational unit name - StringType(SIZE(1..64))
+     */
+    public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11");
+
+    /**
+     * Title
+     */
+    public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12");
+
+    /**
+     * common name - StringType(SIZE(1..64))
+     */
+    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.
+     */
+    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");
+
+        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);
+    }
+
+    protected BCStyle()
+    {
+
+    }
+    
+    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 RuntimeException("can't recode value for oid " + oid.getId());
+            }
+        }
+        else
+        {
+            if (value.length() != 0 && value.charAt(0) == '\\')
+            {
+                value = value.substring(1);
+            }
+            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 DERGeneralizedTime(value);
+            }
+            else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER)
+                || oid.equals(TELEPHONE_NUMBER))
+            {
+                return new DERPrintableString(value);
+            }
+        }
+
+        return new DERUTF8String(value);
+    }
+
+    public ASN1ObjectIdentifier attrNameToOID(String attrName)
+    {
+        return IETFUtils.decodeAttrName(attrName, DefaultLookUp);
+    }
+
+    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)
+    {
+        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 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;
+    }
+
+    public RDN[] fromString(String dirName)
+    {
+        return IETFUtils.rDNsFromString(dirName, this);
+    }
+
+    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;
+    }
+
+    private int calcHashCode(ASN1Encodable enc)
+    {
+        String value = IETFUtils.valueToString(enc);
+
+        value = IETFUtils.canonicalize(value);
+
+        return value.hashCode();
+    }
+
+    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(',');
+            }
+
+            if (rdns[i].isMultiValued())
+            {
+                AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
+                boolean firstAtv = true;
+
+                for (int j = 0; j != atv.length; j++)
+                {
+                    if (firstAtv)
+                    {
+                        firstAtv = false;
+                    }
+                    else
+                    {
+                        buf.append('+');
+                    }
+                    
+                    IETFUtils.appendTypeAndValue(buf, atv[j], DefaultSymbols);
+                }
+            }
+            else
+            {
+                IETFUtils.appendTypeAndValue(buf, rdns[i].getFirst(), DefaultSymbols);
+            }
+        }
+
+        return buf.toString();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java b/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
new file mode 100644
index 0000000..5803042
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
@@ -0,0 +1,294 @@
+package org.bouncycastle.asn1.x500.style;
+
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1String;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERUniversalString;
+import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500NameBuilder;
+import org.bouncycastle.asn1.x500.X500NameStyle;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+public class IETFUtils
+{
+    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();
+            int     index = token.indexOf('=');
+
+            if (index == -1)
+            {
+                throw new IllegalArgumentException("badly formated directory string");
+            }
+
+            String               attr = token.substring(0, index);
+            String               value = token.substring(index + 1);
+            ASN1ObjectIdentifier oid = x500Style.attrNameToOID(attr);
+
+            if (value.indexOf('+') > 0)
+            {
+                X500NameTokenizer   vTok = new X500NameTokenizer(value, '+');
+                String  v = vTok.nextToken();
+
+                Vector oids = new Vector();
+                Vector values = new Vector();
+
+                oids.addElement(oid);
+                values.addElement(v);
+
+                while (vTok.hasMoreTokens())
+                {
+                    String  sv = vTok.nextToken();
+                    int     ndx = sv.indexOf('=');
+
+                    String  nm = sv.substring(0, ndx);
+                    String  vl = sv.substring(ndx + 1);
+
+                    oids.addElement(x500Style.attrNameToOID(nm));
+                    values.addElement(vl);
+                }
+
+                builder.addMultiValuedRDN(toOIDArray(oids), toValueArray(values));
+            }
+            else
+            {
+                builder.addRDN(oid, 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 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
+    {
+        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);
+            }
+        }
+
+        return ASN1Object.fromByteArray(data);
+    }
+
+    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
+        {
+            vBuf.append("#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded())));
+        }
+
+        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++;
+        }
+
+        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.trim());
+
+        if (value.length() > 0 && value.charAt(0) == '#')
+        {
+            DERObject obj = decodeObject(value);
+
+            if (obj instanceof ASN1String)
+            {
+                value = Strings.toLowerCase(((ASN1String)obj).getString().trim());
+            }
+        }
+
+        value = stripInternalSpaces(value);
+
+        return value;
+    }
+
+    private static ASN1Object decodeObject(String oValue)
+    {
+        try
+        {
+            return ASN1Object.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();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java b/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
new file mode 100644
index 0000000..63f1a25
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
@@ -0,0 +1,443 @@
+package org.bouncycastle.asn1.x500.style;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERPrintableString;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.X500NameStyle;
+
+public class RFC4519Style
+    implements X500NameStyle
+{
+    public static final X500NameStyle INSTANCE = new RFC4519Style();
+
+    public static final ASN1ObjectIdentifier businessCategory = new ASN1ObjectIdentifier("2.5.4.15");
+    public static final ASN1ObjectIdentifier c = new ASN1ObjectIdentifier("2.5.4.6");
+    public static final ASN1ObjectIdentifier cn = new ASN1ObjectIdentifier("2.5.4.3");
+    public static final ASN1ObjectIdentifier dc = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25");
+    public static final ASN1ObjectIdentifier description = new ASN1ObjectIdentifier("2.5.4.13");
+    public static final ASN1ObjectIdentifier destinationIndicator = new ASN1ObjectIdentifier("2.5.4.27");
+    public static final ASN1ObjectIdentifier distinguishedName = new ASN1ObjectIdentifier("2.5.4.49");
+    public static final ASN1ObjectIdentifier dnQualifier = new ASN1ObjectIdentifier("2.5.4.46");
+    public static final ASN1ObjectIdentifier enhancedSearchGuide = new ASN1ObjectIdentifier("2.5.4.47");
+    public static final ASN1ObjectIdentifier facsimileTelephoneNumber = new ASN1ObjectIdentifier("2.5.4.23");
+    public static final ASN1ObjectIdentifier generationQualifier = new ASN1ObjectIdentifier("2.5.4.44");
+    public static final ASN1ObjectIdentifier givenName = new ASN1ObjectIdentifier("2.5.4.42");
+    public static final ASN1ObjectIdentifier houseIdentifier = new ASN1ObjectIdentifier("2.5.4.51");
+    public static final ASN1ObjectIdentifier initials = new ASN1ObjectIdentifier("2.5.4.43");
+    public static final ASN1ObjectIdentifier internationalISDNNumber = new ASN1ObjectIdentifier("2.5.4.25");
+    public static final ASN1ObjectIdentifier l = new ASN1ObjectIdentifier("2.5.4.7");
+    public static final ASN1ObjectIdentifier member = new ASN1ObjectIdentifier("2.5.4.31");
+    public static final ASN1ObjectIdentifier name = new ASN1ObjectIdentifier("2.5.4.41");
+    public static final ASN1ObjectIdentifier o = new ASN1ObjectIdentifier("2.5.4.10");
+    public static final ASN1ObjectIdentifier ou = new ASN1ObjectIdentifier("2.5.4.11");
+    public static final ASN1ObjectIdentifier owner = new ASN1ObjectIdentifier("2.5.4.32");
+    public static final ASN1ObjectIdentifier physicalDeliveryOfficeName = new ASN1ObjectIdentifier("2.5.4.19");
+    public static final ASN1ObjectIdentifier postalAddress = new ASN1ObjectIdentifier("2.5.4.16");
+    public static final ASN1ObjectIdentifier postalCode = new ASN1ObjectIdentifier("2.5.4.17");
+    public static final ASN1ObjectIdentifier postOfficeBox = new ASN1ObjectIdentifier("2.5.4.18");
+    public static final ASN1ObjectIdentifier preferredDeliveryMethod = new ASN1ObjectIdentifier("2.5.4.28");
+    public static final ASN1ObjectIdentifier registeredAddress = new ASN1ObjectIdentifier("2.5.4.26");
+    public static final ASN1ObjectIdentifier roleOccupant = new ASN1ObjectIdentifier("2.5.4.33");
+    public static final ASN1ObjectIdentifier searchGuide = new ASN1ObjectIdentifier("2.5.4.14");
+    public static final ASN1ObjectIdentifier seeAlso = new ASN1ObjectIdentifier("2.5.4.34");
+    public static final ASN1ObjectIdentifier serialNumber = new ASN1ObjectIdentifier("2.5.4.5");
+    public static final ASN1ObjectIdentifier sn = new ASN1ObjectIdentifier("2.5.4.4");
+    public static final ASN1ObjectIdentifier st = new ASN1ObjectIdentifier("2.5.4.8");
+    public static final ASN1ObjectIdentifier street = new ASN1ObjectIdentifier("2.5.4.9");
+    public static final ASN1ObjectIdentifier telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20");
+    public static final ASN1ObjectIdentifier teletexTerminalIdentifier = new ASN1ObjectIdentifier("2.5.4.22");
+    public static final ASN1ObjectIdentifier telexNumber = new ASN1ObjectIdentifier("2.5.4.21");
+    public static final ASN1ObjectIdentifier title = new ASN1ObjectIdentifier("2.5.4.12");
+    public static final ASN1ObjectIdentifier uid = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1");
+    public static final ASN1ObjectIdentifier uniqueMember = new ASN1ObjectIdentifier("2.5.4.50");
+    public static final ASN1ObjectIdentifier userPassword = new ASN1ObjectIdentifier("2.5.4.35");
+    public static final ASN1ObjectIdentifier x121Address = new ASN1ObjectIdentifier("2.5.4.24");
+    public static final ASN1ObjectIdentifier x500UniqueIdentifier = new ASN1ObjectIdentifier("2.5.4.45");
+
+    /**
+     * 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.
+    }
+
+    protected RFC4519Style()
+    {
+
+    }
+
+    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 RuntimeException("can't recode value for oid " + oid.getId());
+            }
+        }
+        else
+        {
+            if (value.length() != 0 && value.charAt(0) == '\\')
+            {
+                value = value.substring(1);
+            }
+            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 new DERUTF8String(value);
+    }
+
+    public ASN1ObjectIdentifier attrNameToOID(String attrName)
+    {
+        return IETFUtils.decodeAttrName(attrName, DefaultLookUp);
+    }
+
+    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)
+    {
+        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 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;
+    }
+
+    // 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;
+    }
+
+    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;
+    }
+
+    private int calcHashCode(ASN1Encodable enc)
+    {
+        String value = IETFUtils.valueToString(enc);
+
+        value = IETFUtils.canonicalize(value);
+
+        return value.hashCode();
+    }
+
+    // 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(',');
+            }
+
+            if (rdns[i].isMultiValued())
+            {
+                AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
+                boolean firstAtv = true;
+
+                for (int j = 0; j != atv.length; j++)
+                {
+                    if (firstAtv)
+                    {
+                        firstAtv = false;
+                    }
+                    else
+                    {
+                        buf.append('+');
+                    }
+
+                    IETFUtils.appendTypeAndValue(buf, atv[j], DefaultSymbols);
+                }
+            }
+            else
+            {
+                IETFUtils.appendTypeAndValue(buf, rdns[i].getFirst(), DefaultSymbols);
+            }
+        }
+
+        return buf.toString();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java b/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java
new file mode 100644
index 0000000..7549a72
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java
@@ -0,0 +1,99 @@
+package 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.
+ */
+class X500NameTokenizer
+{
+    private String          value;
+    private int             index;
+    private char            seperator;
+    private StringBuffer    buf = new StringBuffer();
+
+    public X500NameTokenizer(
+        String  oid)
+    {
+        this(oid, ',');
+    }
+    
+    public X500NameTokenizer(
+        String  oid,
+        char    seperator)
+    {
+        this.value = oid;
+        this.index = -1;
+        this.seperator = seperator;
+    }
+
+    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;
+                }
+                else
+                {
+                    buf.append(c);
+                }
+                escaped = false;
+            }
+            else
+            {
+                if (escaped || quoted)
+                {
+                    if (c == '#' && buf.charAt(buf.length() - 1) == '=')
+                    {
+                        buf.append('\\');
+                    }
+                    else if (c == '+' && seperator != '+')
+                    {
+                        buf.append('\\');
+                    }
+                    buf.append(c);
+                    escaped = false;
+                }
+                else if (c == '\\')
+                {
+                    escaped = true;
+                }
+                else if (c == seperator)
+                {
+                    break;
+                }
+                else
+                {
+                    buf.append(c);
+                }
+            }
+            end++;
+        }
+
+        index = end;
+        return buf.toString().trim();
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
index d581967..7288d38 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
@@ -2,9 +2,11 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERNull;
 import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
@@ -92,6 +94,15 @@
         }
     }
 
+    public ASN1ObjectIdentifier getAlgorithm()
+    {
+        return new ASN1ObjectIdentifier(objectId.getId());
+    }
+
+    /**
+     * @deprecated use getAlgorithm
+     * @return
+     */
     public DERObjectIdentifier getObjectId()
     {
         return objectId;
@@ -118,7 +129,14 @@
 
         if (parametersDefined)
         {
-            v.add(parameters);
+            if (parameters != null)
+            {
+                v.add(parameters);
+            }
+            else
+            {
+                v.add(DERNull.INSTANCE);
+            }
         }
 
         return new DERSequence(v);
diff --git a/src/main/java/org/bouncycastle/asn1/x509/Attribute.java b/src/main/java/org/bouncycastle/asn1/x509/Attribute.java
index c102e15..56df178 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/Attribute.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/Attribute.java
@@ -2,6 +2,7 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1Set;
 import org.bouncycastle.asn1.DERObject;
@@ -56,11 +57,16 @@
         this.attrValues = attrValues;
     }
 
-    public DERObjectIdentifier getAttrType()
+    public ASN1ObjectIdentifier getAttrType()
     {
-        return attrType;
+        return new ASN1ObjectIdentifier(attrType.getId());
     }
-    
+
+    public ASN1Encodable[] getAttributeValues()
+    {
+        return attrValues.toArray();
+    }
+
     public ASN1Set getAttrValues()
     {
         return attrValues;
diff --git a/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java b/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
index cf00230..9e79e89 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
@@ -24,12 +24,12 @@
         {
             return (AttributeCertificate)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new AttributeCertificate((ASN1Sequence)obj);
+            return new AttributeCertificate(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
     
     public AttributeCertificate(
diff --git a/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java b/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
index 66c9630..40c49c6 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
@@ -1,6 +1,8 @@
 
 package org.bouncycastle.asn1.x509;
 
+import java.util.Enumeration;
+
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1Sequence;
@@ -9,8 +11,6 @@
 import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERSequence;
 
-import java.util.Enumeration;
-
 /**
  * PKIX RFC-2459
  *
@@ -45,12 +45,12 @@
         {
             return (CertificateList)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new CertificateList((ASN1Sequence)obj);
+            return new CertificateList(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
     public CertificateList(
diff --git a/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java b/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
index a59f105..b6a294e 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
@@ -13,7 +13,7 @@
  * <pre>
  * DistributionPointName ::= CHOICE {
  *     fullName                 [0] GeneralNames,
- *     nameRelativeToCRLIssuer  [1] RelativeDistinguishedName
+ *     nameRelativeToCRLIssuer  [1] RDN
  * }
  * </pre>
  */
diff --git a/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java b/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
index c657c7b..29fdd72 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
@@ -1,9 +1,11 @@
 package org.bouncycastle.asn1.x509;
 
+import java.io.IOException;
 import java.util.StringTokenizer;
 
 import org.bouncycastle.asn1.ASN1Choice;
 import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1OctetString;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
@@ -13,6 +15,7 @@
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.util.IPAddress;
 
 /**
@@ -64,6 +67,13 @@
         this.tag = 4;
     }
 
+    public GeneralName(
+        X500Name dirName)
+    {
+        this.obj = dirName;
+        this.tag = 4;
+    }
+
     /**
      * @deprecated this constructor seems the wrong way round! Use GeneralName(tag, name).
      */
@@ -204,6 +214,18 @@
             }
         }
 
+        if (obj instanceof byte[])
+        {
+            try
+            {
+                return getInstance(ASN1Object.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());
     }
 
diff --git a/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java b/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java
index 326ee20..2a4b1f1 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java
@@ -1,5 +1,7 @@
 package org.bouncycastle.asn1.x509;
 
+import java.math.BigInteger;
+
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1Sequence;
@@ -9,8 +11,6 @@
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 
-import java.math.BigInteger;
-
 /**
  * Class for containing a restriction object subtrees in NameConstraints. See
  * RFC 3280.
@@ -64,9 +64,27 @@
             }
             break;
         case 3:
-            minimum = DERInteger.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(1)));
-            maximum = DERInteger.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(2)));
+        {
+            {
+                ASN1TaggedObject oMin = ASN1TaggedObject.getInstance(seq.getObjectAt(1));
+                if (oMin.getTagNo() != 0)
+                {
+                    throw new IllegalArgumentException("Bad tag number for 'minimum': " + oMin.getTagNo());
+                }
+                minimum = DERInteger.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 = DERInteger.getInstance(oMax, false);
+            }
+
             break;
+        }
         default:
             throw new IllegalArgumentException("Bad sequence size: "
                     + seq.size());
diff --git a/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java b/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
index d122327..9af439d 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
@@ -39,12 +39,12 @@
         {
             return (SubjectPublicKeyInfo)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new SubjectPublicKeyInfo((ASN1Sequence)obj);
+            return new SubjectPublicKeyInfo(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
     public SubjectPublicKeyInfo(
diff --git a/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java b/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
index f14e9bb..128a1a1 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
@@ -1,5 +1,7 @@
 package org.bouncycastle.asn1.x509;
 
+import java.util.Enumeration;
+
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
@@ -9,8 +11,6 @@
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.DERUTCTime;
 
-import java.util.Enumeration;
-
 /**
  * PKIX RFC-2459 - TBSCertList object.
  * <pre>
@@ -35,7 +35,7 @@
 public class TBSCertList
     extends ASN1Encodable
 {
-    public class CRLEntry
+    public static class CRLEntry
         extends ASN1Encodable
     {
         ASN1Sequence  seq;
diff --git a/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java b/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
index f1a6cfd..36425d7 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
@@ -60,12 +60,12 @@
         {
             return (TBSCertificateStructure)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new TBSCertificateStructure((ASN1Sequence)obj);
+            return new TBSCertificateStructure(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
     public TBSCertificateStructure(
@@ -80,7 +80,7 @@
         //
         if (seq.getObjectAt(0) instanceof DERTaggedObject)
         {
-            version = DERInteger.getInstance(seq.getObjectAt(0));
+            version = DERInteger.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);
         }
         else
         {
diff --git a/src/main/java/org/bouncycastle/asn1/x509/Time.java b/src/main/java/org/bouncycastle/asn1/x509/Time.java
index c05c65d..d51209d 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/Time.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/Time.java
@@ -66,7 +66,7 @@
     public static Time getInstance(
         Object  obj)
     {
-        if (obj instanceof Time)
+        if (obj == null || obj instanceof Time)
         {
             return (Time)obj;
         }
diff --git a/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java b/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
index 53505d1..1c3016d 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
@@ -5,6 +5,7 @@
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.DERUTCTime;
+import org.bouncycastle.asn1.x500.X500Name;
 
 /**
  * Generator for Version 1 TBSCertificateStructures.
@@ -54,6 +55,12 @@
         this.issuer = issuer;
     }
 
+    public void setIssuer(
+        X500Name issuer)
+    {
+        this.issuer = X509Name.getInstance(issuer.getDERObject());
+    }
+
     public void setStartDate(
         Time startDate)
     {
@@ -84,6 +91,12 @@
         this.subject = subject;
     }
 
+    public void setSubject(
+        X500Name subject)
+    {
+        this.subject = X509Name.getInstance(subject.getDERObject());
+    }
+
     public void setSubjectPublicKeyInfo(
         SubjectPublicKeyInfo    pubKeyInfo)
     {
diff --git a/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java b/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
index 9d8ba05..6fccbd0 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
@@ -6,6 +6,7 @@
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.DERUTCTime;
+import org.bouncycastle.asn1.x500.X500Name;
 
 /**
  * Generator for Version 3 TBSCertificateStructures.
@@ -63,6 +64,12 @@
         this.issuer = issuer;
     }
 
+    public void setIssuer(
+        X500Name issuer)
+    {
+        this.issuer = X509Name.getInstance(issuer.getDERObject());
+    }
+    
     public void setStartDate(
         DERUTCTime startDate)
     {
@@ -93,6 +100,12 @@
         this.subject = subject;
     }
 
+    public void setSubject(
+        X500Name subject)
+    {
+        this.subject = X509Name.getInstance(subject.getDERObject());
+    }
+
     public void setIssuerUniqueID(
         DERBitString uniqueID)
     {
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java b/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java
index 347b661..8559b69 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java
@@ -41,17 +41,12 @@
         {
             return (X509CertificateStructure)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj != null)
         {
-            return new X509CertificateStructure((ASN1Sequence)obj);
+            return new X509CertificateStructure(ASN1Sequence.getInstance(obj));
         }
 
-        if (obj != null)
-        {
-            throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
-        }
-
-        throw new IllegalArgumentException("null object in factory");
+        return null;
     }
 
     public X509CertificateStructure(
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java b/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
index 02ac76b..8c2cab4 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
@@ -1,16 +1,173 @@
 package org.bouncycastle.asn1.x509;
 
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
 import org.bouncycastle.asn1.DERBoolean;
 
-import java.io.IOException;
-
 /**
  * an object for the elements in the X.509 V3 extension block.
  */
 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;
 
@@ -40,6 +197,11 @@
         return value;
     }
 
+    public ASN1Encodable getParsedValue()
+    {
+        return convertValueToObject(this);
+    }
+
     public int hashCode()
     {
         if (this.isCritical())
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java b/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
index 58d9504..a9819f4 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
@@ -1,7 +1,12 @@
 package org.bouncycastle.asn1.x509;
 
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1OctetString;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
@@ -9,175 +14,198 @@
 import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
-// BEGIN android-added
-import org.bouncycastle.asn1.OrderedTable;
-// END android-added
-
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Vector;
 
 public class X509Extensions
     extends ASN1Encodable
 {
     /**
      * Subject Directory Attributes
+     * @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier SubjectDirectoryAttributes = new DERObjectIdentifier("2.5.29.9");
+    public static final ASN1ObjectIdentifier SubjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9");
     
     /**
-     * Subject Key Identifier 
+     * Subject Key Identifier
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier SubjectKeyIdentifier = new DERObjectIdentifier("2.5.29.14");
+    public static final ASN1ObjectIdentifier SubjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14");
 
     /**
-     * Key Usage 
+     * Key Usage
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier KeyUsage = new DERObjectIdentifier("2.5.29.15");
+    public static final ASN1ObjectIdentifier KeyUsage = new ASN1ObjectIdentifier("2.5.29.15");
 
     /**
-     * Private Key Usage Period 
+     * Private Key Usage Period
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier PrivateKeyUsagePeriod = new DERObjectIdentifier("2.5.29.16");
+    public static final ASN1ObjectIdentifier PrivateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16");
 
     /**
-     * Subject Alternative Name 
+     * Subject Alternative Name
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier SubjectAlternativeName = new DERObjectIdentifier("2.5.29.17");
+    public static final ASN1ObjectIdentifier SubjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17");
 
     /**
-     * Issuer Alternative Name 
+     * Issuer Alternative Name
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier IssuerAlternativeName = new DERObjectIdentifier("2.5.29.18");
+    public static final ASN1ObjectIdentifier IssuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18");
 
     /**
-     * Basic Constraints 
+     * Basic Constraints
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier BasicConstraints = new DERObjectIdentifier("2.5.29.19");
+    public static final ASN1ObjectIdentifier BasicConstraints = new ASN1ObjectIdentifier("2.5.29.19");
 
     /**
-     * CRL Number 
+     * CRL Number
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier CRLNumber = new DERObjectIdentifier("2.5.29.20");
+    public static final ASN1ObjectIdentifier CRLNumber = new ASN1ObjectIdentifier("2.5.29.20");
 
     /**
-     * Reason code 
+     * Reason code
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier ReasonCode = new DERObjectIdentifier("2.5.29.21");
+    public static final ASN1ObjectIdentifier ReasonCode = new ASN1ObjectIdentifier("2.5.29.21");
 
     /**
-     * Hold Instruction Code 
+     * Hold Instruction Code
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier InstructionCode = new DERObjectIdentifier("2.5.29.23");
+    public static final ASN1ObjectIdentifier InstructionCode = new ASN1ObjectIdentifier("2.5.29.23");
 
     /**
-     * Invalidity Date 
+     * Invalidity Date
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier InvalidityDate = new DERObjectIdentifier("2.5.29.24");
+    public static final ASN1ObjectIdentifier InvalidityDate = new ASN1ObjectIdentifier("2.5.29.24");
 
     /**
-     * Delta CRL indicator 
+     * Delta CRL indicator
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier DeltaCRLIndicator = new DERObjectIdentifier("2.5.29.27");
+    public static final ASN1ObjectIdentifier DeltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27");
 
     /**
-     * Issuing Distribution Point 
+     * Issuing Distribution Point
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier IssuingDistributionPoint = new DERObjectIdentifier("2.5.29.28");
+    public static final ASN1ObjectIdentifier IssuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28");
 
     /**
-     * Certificate Issuer 
+     * Certificate Issuer
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier CertificateIssuer = new DERObjectIdentifier("2.5.29.29");
+    public static final ASN1ObjectIdentifier CertificateIssuer = new ASN1ObjectIdentifier("2.5.29.29");
 
     /**
-     * Name Constraints 
+     * Name Constraints
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier NameConstraints = new DERObjectIdentifier("2.5.29.30");
+    public static final ASN1ObjectIdentifier NameConstraints = new ASN1ObjectIdentifier("2.5.29.30");
 
     /**
-     * CRL Distribution Points 
+     * CRL Distribution Points
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier CRLDistributionPoints = new DERObjectIdentifier("2.5.29.31");
+    public static final ASN1ObjectIdentifier CRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31");
 
     /**
-     * Certificate Policies 
+     * Certificate Policies
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier CertificatePolicies = new DERObjectIdentifier("2.5.29.32");
+    public static final ASN1ObjectIdentifier CertificatePolicies = new ASN1ObjectIdentifier("2.5.29.32");
 
     /**
-     * Policy Mappings 
+     * Policy Mappings
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier PolicyMappings = new DERObjectIdentifier("2.5.29.33");
+    public static final ASN1ObjectIdentifier PolicyMappings = new ASN1ObjectIdentifier("2.5.29.33");
 
     /**
-     * Authority Key Identifier 
+     * Authority Key Identifier
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier AuthorityKeyIdentifier = new DERObjectIdentifier("2.5.29.35");
+    public static final ASN1ObjectIdentifier AuthorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35");
 
     /**
-     * Policy Constraints 
+     * Policy Constraints
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier PolicyConstraints = new DERObjectIdentifier("2.5.29.36");
+    public static final ASN1ObjectIdentifier PolicyConstraints = new ASN1ObjectIdentifier("2.5.29.36");
 
     /**
-     * Extended Key Usage 
+     * Extended Key Usage
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier ExtendedKeyUsage = new DERObjectIdentifier("2.5.29.37");
+    public static final ASN1ObjectIdentifier ExtendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37");
 
     /**
      * Freshest CRL
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier FreshestCRL = new DERObjectIdentifier("2.5.29.46");
+    public static final ASN1ObjectIdentifier FreshestCRL = new ASN1ObjectIdentifier("2.5.29.46");
      
     /**
      * Inhibit Any Policy
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier InhibitAnyPolicy = new DERObjectIdentifier("2.5.29.54");
+    public static final ASN1ObjectIdentifier InhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54");
 
     /**
      * Authority Info Access
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier AuthorityInfoAccess = new DERObjectIdentifier("1.3.6.1.5.5.7.1.1");
+    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 DERObjectIdentifier SubjectInfoAccess = new DERObjectIdentifier("1.3.6.1.5.5.7.1.11");
+    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 DERObjectIdentifier LogoType = new DERObjectIdentifier("1.3.6.1.5.5.7.1.12");
+    public static final ASN1ObjectIdentifier LogoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12");
 
     /**
      * BiometricInfo
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier BiometricInfo = new DERObjectIdentifier("1.3.6.1.5.5.7.1.2");
+    public static final ASN1ObjectIdentifier BiometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2");
     
     /**
      * QCStatements
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier QCStatements = new DERObjectIdentifier("1.3.6.1.5.5.7.1.3");
+    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 DERObjectIdentifier AuditIdentity = new DERObjectIdentifier("1.3.6.1.5.5.7.1.4");
+    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 DERObjectIdentifier NoRevAvail = new DERObjectIdentifier("2.5.29.56");
+    public static final ASN1ObjectIdentifier NoRevAvail = new ASN1ObjectIdentifier("2.5.29.56");
 
     /**
      * TargetInformation extension in attribute certificates.
+     *  @deprecated use X509Extension value.
      */
-    public static final DERObjectIdentifier TargetInformation = new DERObjectIdentifier("2.5.29.55");
+    public static final ASN1ObjectIdentifier TargetInformation = new ASN1ObjectIdentifier("2.5.29.55");
     
-    // BEGIN android-changed
-    private OrderedTable table = new OrderedTable();
-    // END android-changed
+    private Hashtable               extensions = new Hashtable();
+    private Vector                  ordering = new Vector();
 
     public static X509Extensions getInstance(
         ASN1TaggedObject obj,
@@ -221,26 +249,20 @@
         {
             ASN1Sequence            s = ASN1Sequence.getInstance(e.nextElement());
 
-            // BEGIN android-changed
-            int sSize = s.size();
-            DERObjectIdentifier key = (DERObjectIdentifier) s.getObjectAt(0);
-            Object value;
-            
-            if (sSize == 3)
+            if (s.size() == 3)
             {
-                value = new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2)));
+                extensions.put(s.getObjectAt(0), new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2))));
             }
-            else if (sSize == 2)
+            else if (s.size() == 2)
             {
-                value = new X509Extension(false, ASN1OctetString.getInstance(s.getObjectAt(1)));
+                extensions.put(s.getObjectAt(0), new X509Extension(false, ASN1OctetString.getInstance(s.getObjectAt(1))));
             }
             else
             {
-                throw new IllegalArgumentException("Bad sequence size: " + sSize);
+                throw new IllegalArgumentException("Bad sequence size: " + s.size());
             }
 
-            table.add(key, value);
-            // END android-changed
+            ordering.addElement(s.getObjectAt(0));
         }
     }
 
@@ -275,14 +297,20 @@
             e = ordering.elements();
         }
 
-        // BEGIN android-changed
         while (e.hasMoreElements())
         {
-            DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
-            X509Extension           ext = (X509Extension)extensions.get(oid);
-            table.add(oid, ext);
+            this.ordering.addElement(new ASN1ObjectIdentifier(((DERObjectIdentifier)e.nextElement()).getId())); 
         }
-        // END android-changed
+
+        e = this.ordering.elements();
+
+        while (e.hasMoreElements())
+        {
+            ASN1ObjectIdentifier     oid = new ASN1ObjectIdentifier(((DERObjectIdentifier)e.nextElement()).getId());
+            X509Extension           ext = (X509Extension)extensions.get(oid);
+
+            this.extensions.put(oid, ext);
+        }
     }
 
     /**
@@ -297,18 +325,23 @@
     {
         Enumeration e = objectIDs.elements();
 
-        // BEGIN android-changed
-        int count = 0;
-        
         while (e.hasMoreElements())
         {
-            DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
+            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);
 
-            table.add(oid, ext);
+            this.extensions.put(oid, ext);
             count++;
         }
-        // END android-changed
     }
     
     /**
@@ -316,9 +349,7 @@
      */
     public Enumeration oids()
     {
-        // BEGIN android-changed
-        return table.getKeys();
-        // END android-changed
+        return ordering.elements();
     }
 
     /**
@@ -328,11 +359,20 @@
      * @return the extension if it's present, null otherwise.
      */
     public X509Extension getExtension(
+        ASN1ObjectIdentifier oid)
+    {
+        return (X509Extension)extensions.get(oid);
+    }
+
+    /**
+     * @deprecated
+     * @param oid
+     * @return
+     */
+    public X509Extension getExtension(
         DERObjectIdentifier oid)
     {
-        // BEGIN android-changed
-        return (X509Extension)table.get(oid);
-        // END android-changed
+        return (X509Extension)extensions.get(oid);
     }
 
     /**
@@ -348,14 +388,12 @@
     public DERObject toASN1Object()
     {
         ASN1EncodableVector     vec = new ASN1EncodableVector();
-        // BEGIN android-changed
-        int                     size = table.size();
+        Enumeration             e = ordering.elements();
 
-        for (int i = 0; i < size; i++)
+        while (e.hasMoreElements())
         {
-            DERObjectIdentifier     oid = table.getKey(i);
-            X509Extension           ext = (X509Extension)table.getValue(i);
-            // END android-changed
+            ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)e.nextElement();
+            X509Extension           ext = (X509Extension)extensions.get(oid);
             ASN1EncodableVector     v = new ASN1EncodableVector();
 
             v.add(oid);
@@ -378,24 +416,18 @@
     public boolean equivalent(
         X509Extensions other)
     {
-        // BEGIN android-changed
-        if (table.size() != other.table.size())
-        // END android-changed
+        if (extensions.size() != other.extensions.size())
         {
             return false;
         }
 
-        // BEGIN android-changed
-        Enumeration     e1 = table.getKeys();
-        // END android-changed
+        Enumeration     e1 = extensions.keys();
 
         while (e1.hasMoreElements())
         {
-            // BEGIN android-changed
-            DERObjectIdentifier  key = (DERObjectIdentifier)e1.nextElement();
+            Object  key = e1.nextElement();
 
-            if (!table.get(key).equals(other.table.get(key)))
-            // END android-changed
+            if (!extensions.get(key).equals(other.extensions.get(key)))
             {
                 return false;
             }
@@ -403,4 +435,47 @@
 
         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/src/main/java/org/bouncycastle/asn1/x509/X509Name.java b/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
index ea221b6..89638dd 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
@@ -19,6 +19,7 @@
 import org.bouncycastle.asn1.DERString;
 import org.bouncycastle.asn1.DERUniversalString;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x500.X500Name;
 import org.bouncycastle.util.Strings;
 import org.bouncycastle.util.encoders.Hex;
 
@@ -32,6 +33,7 @@
  *                                   type  OBJECT IDENTIFIER,
  *                                   value ANY }
  * </pre>
+ * @deprecated use org.bouncycastle.asn1.x500.X500Name.
  */
 public class X509Name
     extends ASN1Encodable
@@ -247,10 +249,10 @@
      */
     public static final Hashtable SymbolLookUp = DefaultLookUp;
 
-    // BEGIN android-removed
-    //private static final Boolean TRUE = new Boolean(true); // for J2ME compatibility
-    //private static final Boolean FALSE = new Boolean(false);
-    // END android-removed
+    // BEGIN android-changed
+    private static final Boolean TRUE = Boolean.TRUE;
+    private static final Boolean FALSE = Boolean.FALSE;
+    // END android-changed
 
     static
     {
@@ -342,9 +344,9 @@
     }
 
     private X509NameEntryConverter  converter = null;
-    // BEGIN android-changed
-    private X509NameElementList     elems = new X509NameElementList();
-    // END android-changed
+    private Vector                  ordering = new Vector();
+    private Vector                  values = new Vector();
+    private Vector                  added = new Vector();
 
     private ASN1Sequence            seq;
 
@@ -372,14 +374,22 @@
         {
             return (X509Name)obj;
         }
-        else if (obj instanceof ASN1Sequence)
+        else if (obj instanceof X500Name)
         {
-            return new X509Name((ASN1Sequence)obj);
+            return new X509Name(ASN1Sequence.getInstance(((X500Name)obj).getDERObject()));
+        }
+        else if (obj != null)
+        {
+            return new X509Name(ASN1Sequence.getInstance(obj));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+        return null;
     }
 
+    protected X509Name()
+    {
+        // constructure use by new X500 Name class
+    }
     /**
      * Constructor from ASN1Sequence
      *
@@ -394,7 +404,7 @@
 
         while (e.hasMoreElements())
         {
-            ASN1Set         set = ASN1Set.getInstance(e.nextElement());
+            ASN1Set         set = ASN1Set.getInstance(((DEREncodable)e.nextElement()).getDERObject());
 
             for (int i = 0; i < set.size(); i++) 
             {
@@ -405,29 +415,27 @@
                        throw new IllegalArgumentException("badly sized pair");
                    }
 
-                   // BEGIN android-changed
-                   DERObjectIdentifier key = DERObjectIdentifier.getInstance(s.getObjectAt(0));
+                   ordering.addElement(DERObjectIdentifier.getInstance(s.getObjectAt(0)));
                    
                    DEREncodable value = s.getObjectAt(1);
-                   String valueStr;
                    if (value instanceof DERString && !(value instanceof DERUniversalString))
                    {
                        String v = ((DERString)value).getString();
                        if (v.length() > 0 && v.charAt(0) == '#')
                        {
-                           valueStr = "\\" + v;
+                           values.addElement("\\" + v);
                        }
                        else
                        {
-                           valueStr = v;
+                           values.addElement(v);
                        }
                    }
                    else
                    {
-                       valueStr = "#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded()));
+                       values.addElement("#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded())));
                    }
-                   boolean added = (i != 0);  // to allow earlier JDK compatibility
-                   elems.add(key, valueStr, added);
+                   // BEGIN android-changed
+                   added.addElement(Boolean.valueOf(i != 0));
                    // END android-changed
             }
         }
@@ -482,23 +490,14 @@
         Hashtable                attributes,
         X509NameEntryConverter   converter)
     {
-        // BEGIN android-changed
-        DERObjectIdentifier problem = null;
         this.converter = converter;
 
         if (ordering != null)
         {
             for (int i = 0; i != ordering.size(); i++)
             {
-                DERObjectIdentifier key =
-                    (DERObjectIdentifier) ordering.elementAt(i);
-                String value = (String) attributes.get(key);
-                if (value == null)
-                {
-                    problem = key;
-                    break;
-                }
-                elems.add(key, value);
+                this.ordering.addElement(ordering.elementAt(i));
+                this.added.addElement(FALSE);
             }
         }
         else
@@ -507,23 +506,22 @@
 
             while (e.hasMoreElements())
             {
-                DERObjectIdentifier key =
-                    (DERObjectIdentifier) e.nextElement();
-                String value = (String) attributes.get(key);
-                if (value == null)
-                {
-                    problem = key;
-                    break;
-                }
-                elems.add(key, value);
+                this.ordering.addElement(e.nextElement());
+                this.added.addElement(FALSE);
             }
         }
 
-        if (problem != null)
+        for (int i = 0; i != this.ordering.size(); i++)
         {
-            throw new IllegalArgumentException("No attribute for object id - " + problem.getId() + " - passed to distinguished name");
+            DERObjectIdentifier     oid = (DERObjectIdentifier)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
         }
-        // END android-changed
     }
 
     /**
@@ -556,10 +554,9 @@
 
         for (int i = 0; i < oids.size(); i++)
         {
-            // BEGIN android-changed
-            elems.add((DERObjectIdentifier) oids.elementAt(i),
-                    (String) values.elementAt(i));
-            // END android-changed
+            this.ordering.addElement(oids.elementAt(i));
+            this.values.addElement(values.elementAt(i));
+            this.added.addElement(FALSE);
         }
     }
 
@@ -696,7 +693,9 @@
 
             if (index == -1)
             {
+                // BEGIN android-changed
                 throw new IllegalArgumentException("badly formatted directory string");
+                // END android-changed
             }
 
             String              name = token.substring(0, index);
@@ -708,9 +707,9 @@
                 X509NameTokenizer   vTok = new X509NameTokenizer(value, '+');
                 String  v = vTok.nextToken();
 
-                // BEGIN android-changed
-                this.elems.add(oid, v);
-                // END android-changed
+                this.ordering.addElement(oid);
+                this.values.addElement(v);
+                this.added.addElement(FALSE);
 
                 while (vTok.hasMoreTokens())
                 {
@@ -719,24 +718,48 @@
 
                     String  nm = sv.substring(0, ndx);
                     String  vl = sv.substring(ndx + 1);
-                    // BEGIN android-changed
-                    this.elems.add(decodeOID(nm, lookUp), vl, true);
-                    // END android-changed
+                    this.ordering.addElement(decodeOID(nm, lookUp));
+                    this.values.addElement(vl);
+                    this.added.addElement(TRUE);
                 }
             }
             else
             {
-                // BEGIN android-changed
-                this.elems.add(oid, value);
-                // END android-changed
+                this.ordering.addElement(oid);
+                this.values.addElement(value);
+                this.added.addElement(FALSE);
             }
         }
 
         if (reverse)
         {
-            // BEGIN android-changed
-            this.elems = this.elems.reverse();
-            // END android-changed
+            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;
         }
     }
 
@@ -745,17 +768,14 @@
      */
     public Vector getOIDs()
     {
-        // BEGIN android-changed
         Vector  v = new Vector();
-        int     size = elems.size();
 
-        for (int i = 0; i < size; i++)
+        for (int i = 0; i != ordering.size(); i++)
         {
-            v.addElement(elems.getKey(i));
+            v.addElement(ordering.elementAt(i));
         }
 
         return v;
-        // END android-changed
     }
 
     /**
@@ -765,14 +785,11 @@
     public Vector getValues()
     {
         Vector  v = new Vector();
-        // BEGIN android-changed
-        int     size = elems.size();
 
-        for (int i = 0; i != size; i++)
+        for (int i = 0; i != values.size(); i++)
         {
-            v.addElement(elems.getValue(i));
+            v.addElement(values.elementAt(i));
         }
-        // END android-changed
 
         return v;
     }
@@ -785,14 +802,12 @@
         DERObjectIdentifier oid)
     {
         Vector  v = new Vector();
-        int     size = elems.size();
-        // BEGIN android-changed
 
-        for (int i = 0; i != size; i++)
+        for (int i = 0; i != values.size(); i++)
         {
-            if (elems.getKey(i).equals(oid))
+            if (ordering.elementAt(i).equals(oid))
             {
-                String val = elems.getValue(i);
+                String val = (String)values.elementAt(i);
 
                 if (val.length() > 2 && val.charAt(0) == '\\' && val.charAt(1) == '#')
                 {
@@ -804,7 +819,6 @@
                 }
             }
         }
-        // END android-changed
 
         return v;
     }
@@ -816,23 +830,20 @@
             ASN1EncodableVector  vec = new ASN1EncodableVector();
             ASN1EncodableVector  sVec = new ASN1EncodableVector();
             DERObjectIdentifier  lstOid = null;
-            // BEGIN android-changed
-            int                  size = elems.size();
             
-            for (int i = 0; i != size; i++)
+            for (int i = 0; i != ordering.size(); i++)
             {
                 ASN1EncodableVector     v = new ASN1EncodableVector();
-                DERObjectIdentifier     oid = elems.getKey(i);
+                DERObjectIdentifier     oid = (DERObjectIdentifier)ordering.elementAt(i);
 
                 v.add(oid);
 
-                String  str = elems.getValue(i);
+                String  str = (String)values.elementAt(i);
 
                 v.add(converter.getConvertedValue(oid, str));
  
                 if (lstOid == null 
-                    || this.elems.getAdded(i))
-                // END android-changed
+                    || ((Boolean)this.added.elementAt(i)).booleanValue())
                 {
                     sVec.add(new DERSequence(v));
                 }
@@ -850,7 +861,6 @@
             vec.add(new DERSet(sVec));
             
             seq = new DERSequence(vec);
-            // END android-changed
         }
 
         return seq;
@@ -895,28 +905,22 @@
             return false;
         }
 
-        // BEGIN android-changed
-        int      orderingSize = elems.size();
+        int      orderingSize = ordering.size();
 
-        if (orderingSize != other.elems.size())
-        // END android-changed
+        if (orderingSize != other.ordering.size())
         {
             return false;
         }
 
         for (int i = 0; i < orderingSize; i++)
         {
-            // BEGIN android-changed
-            DERObjectIdentifier  oid = elems.getKey(i);
-            DERObjectIdentifier  oOid = other.elems.getKey(i);
-            // END android-changed
+            DERObjectIdentifier  oid = (DERObjectIdentifier)ordering.elementAt(i);
+            DERObjectIdentifier  oOid = (DERObjectIdentifier)other.ordering.elementAt(i);
 
             if (oid.equals(oOid))
             {
-                // BEGIN android-changed
-                String value = elems.getValue(i);
-                String oValue = other.elems.getValue(i);
-                // END android-changed
+                String value = (String)values.elementAt(i);
+                String oValue = (String)other.values.elementAt(i);
 
                 if (!equivalentStrings(value, oValue))
                 {
@@ -942,13 +946,14 @@
         isHashCodeCalculated = true;
 
         // this needs to be order independent, like equals
-        for (int i = 0; i != elems.size(); i += 1)
+        for (int i = 0; i != ordering.size(); i += 1)
         {
-            String value = (String)elems.getValue(i);
+            String value = (String)values.elementAt(i);
 
             value = canonicalize(value);
             value = stripInternalSpaces(value);
 
+            hashCodeValue ^= ordering.elementAt(i).hashCode();
             hashCodeValue ^= value.hashCode();
         }
 
@@ -988,11 +993,9 @@
             return false;
         }
 
-        // BEGIN android-changed
-        int      orderingSize = elems.size();
+        int      orderingSize = ordering.size();
 
-        if (orderingSize != other.elems.size())
-            // END android-changed
+        if (orderingSize != other.ordering.size())
         {
             return false;
         }
@@ -1000,9 +1003,7 @@
         boolean[] indexes = new boolean[orderingSize];
         int       start, end, delta;
 
-        // BEGIN android-changed
-        if (elems.getKey(0).equals(other.elems.getKey(0)))   // guess forward
-        // END android-changed
+        if (ordering.elementAt(0).equals(other.ordering.elementAt(0)))   // guess forward
         {
             start = 0;
             end = orderingSize;
@@ -1018,10 +1019,8 @@
         for (int i = start; i != end; i += delta)
         {
             boolean              found = false;
-            // BEGIN android-changed
-            DERObjectIdentifier  oid = elems.getKey(i);
-            String               value = elems.getValue(i);
-            // END android-changed
+            DERObjectIdentifier  oid = (DERObjectIdentifier)ordering.elementAt(i);
+            String               value = (String)values.elementAt(i);
 
             for (int j = 0; j < orderingSize; j++)
             {
@@ -1030,15 +1029,11 @@
                     continue;
                 }
 
-                // BEGIN android-changed
-                DERObjectIdentifier oOid = other.elems.getKey(j);
-                // END android-changed
+                DERObjectIdentifier oOid = (DERObjectIdentifier)other.ordering.elementAt(j);
 
                 if (oid.equals(oOid))
                 {
-                    // BEGIN android-changed
-                    String oValue = other.elems.getValue(j);
-                    // END android-changed
+                    String oValue = (String)other.values.elementAt(j);
 
                     if (equivalentStrings(value, oValue))
                     {
@@ -1203,36 +1198,28 @@
 
         StringBuffer ava = null;
 
-        // BEGIN android-changed
-        for (int i = 0; i < elems.size(); i++)
-        // END android-changed
+        for (int i = 0; i < ordering.size(); i++)
         {
-            if (elems.getAdded(i))
+            if (((Boolean)added.elementAt(i)).booleanValue())
             {
                 ava.append('+');
                 appendValue(ava, oidSymbols,
-                    // BEGIN android-changed
-                    elems.getKey(i),
-                    elems.getValue(i));
-                    // END android-changed
+                    (DERObjectIdentifier)ordering.elementAt(i),
+                    (String)values.elementAt(i));
             }
             else
             {
                 ava = new StringBuffer();
                 appendValue(ava, oidSymbols,
-                    // BEGIN android-changed
-                    elems.getKey(i),
-                    elems.getValue(i));
-                    // END android-changed
+                    (DERObjectIdentifier)ordering.elementAt(i),
+                    (String)values.elementAt(i));
                 components.addElement(ava);
             }
         }
 
         if (reverse)
         {
-            // BEGIN android-changed
-            for (int i = elems.size() - 1; i >= 0; i--)
-            // END android-changed
+            for (int i = components.size() - 1; i >= 0; i--)
             {
                 if (first)
                 {
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509NameElementList.java b/src/main/java/org/bouncycastle/asn1/x509/X509NameElementList.java
deleted file mode 100644
index 377fb8c..0000000
--- a/src/main/java/org/bouncycastle/asn1/x509/X509NameElementList.java
+++ /dev/null
@@ -1,206 +0,0 @@
-package org.bouncycastle.asn1.x509;
-
-import java.util.ArrayList;
-import java.util.BitSet;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-
-// BEGIN android-note
-// This class was extracted from X509Name as a way to keep the element
-// list in a more controlled fashion.
-// END android-note
-
-/**
- * List of elements of an X509 name. Each element has a key, a value, and
- * an "added" flag.
- */
-public class X509NameElementList {
-    /** null-ok; key #0 */
-    private DERObjectIdentifier key0;
-    
-    /** null-ok; key #1 */
-    private DERObjectIdentifier key1;
-
-    /** null-ok; key #2 */
-    private DERObjectIdentifier key2;
-
-    /** null-ok; key #3 */
-    private DERObjectIdentifier key3;
-    
-    /** null-ok; value #0 */
-    private String value0;
-    
-    /** null-ok; value #1 */
-    private String value1;
-
-    /** null-ok; value #2 */
-    private String value2;
-
-    /** null-ok; value #3 */
-    private String value3;
-    
-    /**
-     * null-ok; array of additional keys and values, alternating
-     * key then value, etc. 
-     */
-    private ArrayList<Object> rest;
-
-    /** bit vector for all the "added" bits */
-    private BitSet added = new BitSet();
-
-    /** &gt;= 0; number of elements in the list */
-    private int size;
-
-    // Note: Default public constructor.
-    
-    /**
-     * Adds an element. The "added" flag is set to false for the element.
-     * 
-     * @param key non-null; the key
-     * @param value non-null; the value
-     */
-    public void add(DERObjectIdentifier key, String value) {
-        add(key, value, false);
-    }
-
-    /**
-     * Adds an element.
-     * 
-     * @param key non-null; the key
-     * @param value non-null; the value
-     * @param added the added bit
-     */
-    public void add(DERObjectIdentifier key, String value, boolean added) {
-        if (key == null) {
-            throw new NullPointerException("key == null");
-        }
-
-        if (value == null) {
-            throw new NullPointerException("value == null");
-        }
-
-        int sz = size;
-
-        switch (sz) {
-            case 0: {
-                key0 = key;
-                value0 = value;
-                break;
-            }
-            case 1: {
-                key1 = key;
-                value1 = value;
-                break;
-            }
-            case 2: {
-                key2 = key;
-                value2 = value;
-                break;
-            }
-            case 3: {
-                key3 = key;
-                value3 = value;
-                break;
-            }
-            case 4: {
-                // Do initial allocation of rest.
-                rest = new ArrayList<Object>();
-                // Fall through...
-            }
-            default: {
-                rest.add(key);
-                rest.add(value);
-                break;
-            }
-        }
-
-        if (added) {
-            this.added.set(sz);
-        }
-        
-        size = sz + 1;
-    }
-
-    /**
-     * Sets the "added" flag on the most recently added element.
-     */
-    public void setLastAddedFlag() {
-        added.set(size - 1);
-    }
-
-    /**
-     * Gets the number of elements in this instance.
-     */
-    public int size() {
-        return size;
-    }
-    
-    /**
-     * Gets the nth key.
-     * 
-     * @param n index
-     * @return non-null; the nth key
-     */
-    public DERObjectIdentifier getKey(int n) {
-        if ((n < 0) || (n >= size)) {
-            throw new IndexOutOfBoundsException(Integer.toString(n));
-        }
-
-        switch (n) {
-            case 0: return key0;
-            case 1: return key1;
-            case 2: return key2;
-            case 3: return key3;
-            default: return (DERObjectIdentifier) rest.get((n - 4) * 2);
-        }
-    }
-
-    /**
-     * Gets the nth value.
-     * 
-     * @param n index
-     * @return non-null; the nth value
-     */
-    public String getValue(int n) {
-        if ((n < 0) || (n >= size)) {
-            throw new IndexOutOfBoundsException(Integer.toString(n));
-        }
-
-        switch (n) {
-            case 0: return value0;
-            case 1: return value1;
-            case 2: return value2;
-            case 3: return value3;
-            default: return (String) rest.get(((n - 4) * 2) + 1);
-        }
-    }
-
-    /**
-     * Gets the nth added flag bit.
-     * 
-     * @param n index
-     * @return the nth added flag bit
-     */
-    public boolean getAdded(int n) {
-        if ((n < 0) || (n >= size)) {
-            throw new IndexOutOfBoundsException(Integer.toString(n));
-        }
-
-        return added.get(n);
-    }
-
-    /**
-     * Constructs and returns a new instance which consists of the
-     * elements of this one in reverse order
-     * 
-     * @return non-null; the reversed instance
-     */
-    public X509NameElementList reverse() {
-        X509NameElementList result = new X509NameElementList();
-            
-        for (int i = size - 1; i >= 0; i--) {
-            result.add(getKey(i), getValue(i), getAdded(i));
-        }
-
-        return result;
-    }
-}
diff --git a/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
index cbf7b76..b1e0ed1 100644
--- a/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.x509;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface X509ObjectIdentifiers
 {
@@ -9,54 +9,54 @@
     //
     static final String                 id                      = "2.5.4";
 
-    static final DERObjectIdentifier    commonName              = new DERObjectIdentifier(id + ".3");
-    static final DERObjectIdentifier    countryName             = new DERObjectIdentifier(id + ".6");
-    static final DERObjectIdentifier    localityName            = new DERObjectIdentifier(id + ".7");
-    static final DERObjectIdentifier    stateOrProvinceName     = new DERObjectIdentifier(id + ".8");
-    static final DERObjectIdentifier    organization            = new DERObjectIdentifier(id + ".10");
-    static final DERObjectIdentifier    organizationalUnitName  = new DERObjectIdentifier(id + ".11");
+    static final ASN1ObjectIdentifier    commonName              = new ASN1ObjectIdentifier(id + ".3");
+    static final ASN1ObjectIdentifier    countryName             = new ASN1ObjectIdentifier(id + ".6");
+    static final ASN1ObjectIdentifier    localityName            = new ASN1ObjectIdentifier(id + ".7");
+    static final ASN1ObjectIdentifier    stateOrProvinceName     = new ASN1ObjectIdentifier(id + ".8");
+    static final ASN1ObjectIdentifier    organization            = new ASN1ObjectIdentifier(id + ".10");
+    static final ASN1ObjectIdentifier    organizationalUnitName  = new ASN1ObjectIdentifier(id + ".11");
 
-    static final DERObjectIdentifier    id_at_telephoneNumber   = new DERObjectIdentifier("2.5.4.20");
-    static final DERObjectIdentifier    id_at_name              = new DERObjectIdentifier(id + ".41");
+    static final ASN1ObjectIdentifier    id_at_telephoneNumber   = new ASN1ObjectIdentifier("2.5.4.20");
+    static final ASN1ObjectIdentifier    id_at_name              = new ASN1ObjectIdentifier(id + ".41");
 
     // id-SHA1 OBJECT IDENTIFIER ::=    
     //   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //
-    static final DERObjectIdentifier    id_SHA1                 = new DERObjectIdentifier("1.3.14.3.2.26");
+    static final ASN1ObjectIdentifier    id_SHA1                 = new ASN1ObjectIdentifier("1.3.14.3.2.26");
 
     //
     // ripemd160 OBJECT IDENTIFIER ::=
     //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)}
     //
-    static final DERObjectIdentifier    ripemd160               = new DERObjectIdentifier("1.3.36.3.2.1");
+    static final ASN1ObjectIdentifier    ripemd160               = new ASN1ObjectIdentifier("1.3.36.3.2.1");
 
     //
     // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=
     //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }
     //
-    static final DERObjectIdentifier    ripemd160WithRSAEncryption = new DERObjectIdentifier("1.3.36.3.3.1.2");
+    static final ASN1ObjectIdentifier    ripemd160WithRSAEncryption = new ASN1ObjectIdentifier("1.3.36.3.3.1.2");
 
 
-    static final DERObjectIdentifier    id_ea_rsa = new DERObjectIdentifier("2.5.8.1.1");
+    static final ASN1ObjectIdentifier    id_ea_rsa = new ASN1ObjectIdentifier("2.5.8.1.1");
     
     // id-pkix
-    static final DERObjectIdentifier id_pkix = new DERObjectIdentifier("1.3.6.1.5.5.7");
+    static final ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7");
 
     //
     // private internet extensions
     //
-    static final DERObjectIdentifier  id_pe = new DERObjectIdentifier(id_pkix + ".1");
+    static final ASN1ObjectIdentifier  id_pe = new ASN1ObjectIdentifier(id_pkix + ".1");
 
     //
     // authority information access
     //
-    static final DERObjectIdentifier  id_ad = new DERObjectIdentifier(id_pkix + ".48");
-    static final DERObjectIdentifier  id_ad_caIssuers = new DERObjectIdentifier(id_ad + ".2");
-    static final DERObjectIdentifier  id_ad_ocsp = new DERObjectIdentifier(id_ad + ".1");
+    static final ASN1ObjectIdentifier  id_ad = new ASN1ObjectIdentifier(id_pkix + ".48");
+    static final ASN1ObjectIdentifier  id_ad_caIssuers = new ASN1ObjectIdentifier(id_ad + ".2");
+    static final ASN1ObjectIdentifier  id_ad_ocsp = new ASN1ObjectIdentifier(id_ad + ".1");
 
     //
     //    OID for ocsp and crl uri in AuthorityInformationAccess extension
     //
-    static final DERObjectIdentifier ocspAccessMethod = id_ad_ocsp;
-    static final DERObjectIdentifier crlAccessMethod = id_ad_caIssuers;
+    static final ASN1ObjectIdentifier ocspAccessMethod = id_ad_ocsp;
+    static final ASN1ObjectIdentifier crlAccessMethod = id_ad_caIssuers;
 }
 
diff --git a/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java b/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java
new file mode 100644
index 0000000..7867090
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java
@@ -0,0 +1,139 @@
+package org.bouncycastle.asn1.x9;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class DHDomainParameters
+    extends ASN1Encodable
+{
+    private DERInteger 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(DERInteger p, DERInteger g, DERInteger q, DERInteger 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 = DERInteger.getInstance(e.nextElement());
+        this.g = DERInteger.getInstance(e.nextElement());
+        this.q = DERInteger.getInstance(e.nextElement());
+
+        DEREncodable next = getNext(e);
+
+        if (next != null && next instanceof DERInteger)
+        {
+            this.j = DERInteger.getInstance(next);
+            next = getNext(e);
+        }
+
+        if (next != null)
+        {
+            this.validationParms = DHValidationParms.getInstance(next.getDERObject());
+        }
+    }
+
+    private static DEREncodable getNext(Enumeration e)
+    {
+        return e.hasMoreElements() ? (DEREncodable)e.nextElement() : null;
+    }
+
+    public DERInteger getP()
+    {
+        return this.p;
+    }
+
+    public DERInteger getG()
+    {
+        return this.g;
+    }
+
+    public DERInteger getQ()
+    {
+        return this.q;
+    }
+
+    public DERInteger getJ()
+    {
+        return this.j;
+    }
+
+    public DHValidationParms getValidationParms()
+    {
+        return this.validationParms;
+    }
+
+    public DERObject toASN1Object()
+    {
+        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/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java b/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java
new file mode 100644
index 0000000..daafbeb
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+
+public class DHPublicKey
+    extends ASN1Encodable
+{
+    private DERInteger y;
+
+    public static DHPublicKey getInstance(ASN1TaggedObject obj, boolean explicit)
+    {
+        return getInstance(DERInteger.getInstance(obj, explicit));
+    }
+
+    public static DHPublicKey getInstance(Object obj)
+    {
+        if (obj == null || obj instanceof DHPublicKey)
+        {
+            return (DHPublicKey)obj;
+        }
+
+        if (obj instanceof DERInteger)
+        {
+            return new DHPublicKey((DERInteger)obj);
+        }
+
+        throw new IllegalArgumentException("Invalid DHPublicKey: " + obj.getClass().getName());
+    }
+
+    public DHPublicKey(DERInteger y)
+    {
+        if (y == null)
+        {
+            throw new IllegalArgumentException("'y' cannot be null");
+        }
+
+        this.y = y;
+    }
+
+    public DERInteger getY()
+    {
+        return this.y;
+    }
+
+    public DERObject toASN1Object()
+    {
+        return this.y;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java b/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java
new file mode 100644
index 0000000..e801e1c
--- /dev/null
+++ b/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java
@@ -0,0 +1,80 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class DHValidationParms extends ASN1Encodable
+{
+    private DERBitString seed;
+    private DERInteger pgenCounter;
+
+    public static DHValidationParms getInstance(ASN1TaggedObject obj, boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static DHValidationParms getInstance(Object obj)
+    {
+        if (obj == null || obj instanceof DHDomainParameters)
+        {
+            return (DHValidationParms)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new DHValidationParms((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("Invalid DHValidationParms: " + obj.getClass().getName());
+    }
+
+    public DHValidationParms(DERBitString seed, DERInteger 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 = DERInteger.getInstance(seq.getObjectAt(1));
+    }
+
+    public DERBitString getSeed()
+    {
+        return this.seed;
+    }
+
+    public DERInteger getPgenCounter()
+    {
+        return this.pgenCounter;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        v.add(this.seed);
+        v.add(this.pgenCounter);
+        return new DERSequence(v);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java b/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
index 5473d48..6c1fcd7 100644
--- a/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
+++ b/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
@@ -1,6 +1,6 @@
 package org.bouncycastle.asn1.x9;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface X9ObjectIdentifiers
 {
@@ -10,92 +10,107 @@
     // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
     //            us(840) ansi-x962(10045) }
     //
-    static final String    ansi_X9_62 = "1.2.840.10045";
-    static final String    id_fieldType = ansi_X9_62 + ".1";
+    static final ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045");
+    static final ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1");
 
-    static final DERObjectIdentifier    prime_field
-                    = new DERObjectIdentifier(id_fieldType + ".1");
+    static final ASN1ObjectIdentifier prime_field = id_fieldType.branch("1");
 
-    static final DERObjectIdentifier    characteristic_two_field
-                    = new DERObjectIdentifier(id_fieldType + ".2");
+    static final ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2");
 
-    static final DERObjectIdentifier    gnBasis
-                    = new DERObjectIdentifier(id_fieldType + ".2.3.1");
+    static final ASN1ObjectIdentifier gnBasis = id_fieldType.branch("2.3.1");
 
-    static final DERObjectIdentifier    tpBasis
-                    = new DERObjectIdentifier(id_fieldType + ".2.3.2");
+    static final ASN1ObjectIdentifier tpBasis = id_fieldType.branch("2.3.2");
 
-    static final DERObjectIdentifier    ppBasis
-                    = new DERObjectIdentifier(id_fieldType + ".2.3.3");
+    static final ASN1ObjectIdentifier ppBasis = id_fieldType.branch("2.3.3");
 
-    static final String    id_ecSigType = ansi_X9_62 + ".4";
+    static final ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4");
 
-    static final DERObjectIdentifier    ecdsa_with_SHA1
-                    = new DERObjectIdentifier(id_ecSigType + ".1");
+    static final ASN1ObjectIdentifier ecdsa_with_SHA1 = new ASN1ObjectIdentifier(id_ecSigType + ".1");
 
-    static final String    id_publicKeyType = ansi_X9_62 + ".2";
+    static final ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2");
 
-    static final DERObjectIdentifier    id_ecPublicKey
-                    = new DERObjectIdentifier(id_publicKeyType + ".1");
+    static final ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1");
 
-    static final DERObjectIdentifier    ecdsa_with_SHA2
-                    = new DERObjectIdentifier(id_ecSigType + ".3");
+    static final ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3");
 
-    static final DERObjectIdentifier    ecdsa_with_SHA224
-                    = new DERObjectIdentifier(ecdsa_with_SHA2 + ".1");
+    static final ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1");
 
-    static final DERObjectIdentifier    ecdsa_with_SHA256
-                    = new DERObjectIdentifier(ecdsa_with_SHA2 + ".2");
+    static final ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2");
 
-    static final DERObjectIdentifier    ecdsa_with_SHA384
-                    = new DERObjectIdentifier(ecdsa_with_SHA2 + ".3");
+    static final ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3");
 
-    static final DERObjectIdentifier    ecdsa_with_SHA512
-                    = new DERObjectIdentifier(ecdsa_with_SHA2 + ".4");
+    static final ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4");
 
     //
     // named curves
     //
-    static final String     ellipticCurve = ansi_X9_62 + ".3";
+    static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3");
 
     //
     // Two Curves
     //
-    static final String     cTwoCurve = ellipticCurve + ".0";
-    
-    static final DERObjectIdentifier    c2pnb163v1 = new DERObjectIdentifier(cTwoCurve + ".1");
-    static final DERObjectIdentifier    c2pnb163v2 = new DERObjectIdentifier(cTwoCurve + ".2");
-    static final DERObjectIdentifier    c2pnb163v3 = new DERObjectIdentifier(cTwoCurve + ".3");
-    static final DERObjectIdentifier    c2pnb176w1 = new DERObjectIdentifier(cTwoCurve + ".4");
-    static final DERObjectIdentifier    c2tnb191v1 = new DERObjectIdentifier(cTwoCurve + ".5");
-    static final DERObjectIdentifier    c2tnb191v2 = new DERObjectIdentifier(cTwoCurve + ".6");
-    static final DERObjectIdentifier    c2tnb191v3 = new DERObjectIdentifier(cTwoCurve + ".7");
-    static final DERObjectIdentifier    c2onb191v4 = new DERObjectIdentifier(cTwoCurve + ".8");
-    static final DERObjectIdentifier    c2onb191v5 = new DERObjectIdentifier(cTwoCurve + ".9");
-    static final DERObjectIdentifier    c2pnb208w1 = new DERObjectIdentifier(cTwoCurve + ".10");
-    static final DERObjectIdentifier    c2tnb239v1 = new DERObjectIdentifier(cTwoCurve + ".11");
-    static final DERObjectIdentifier    c2tnb239v2 = new DERObjectIdentifier(cTwoCurve + ".12");
-    static final DERObjectIdentifier    c2tnb239v3 = new DERObjectIdentifier(cTwoCurve + ".13");
-    static final DERObjectIdentifier    c2onb239v4 = new DERObjectIdentifier(cTwoCurve + ".14");
-    static final DERObjectIdentifier    c2onb239v5 = new DERObjectIdentifier(cTwoCurve + ".15");
-    static final DERObjectIdentifier    c2pnb272w1 = new DERObjectIdentifier(cTwoCurve + ".16");
-    static final DERObjectIdentifier    c2pnb304w1 = new DERObjectIdentifier(cTwoCurve + ".17");
-    static final DERObjectIdentifier    c2tnb359v1 = new DERObjectIdentifier(cTwoCurve + ".18");
-    static final DERObjectIdentifier    c2pnb368w1 = new DERObjectIdentifier(cTwoCurve + ".19");
-    static final DERObjectIdentifier    c2tnb431r1 = new DERObjectIdentifier(cTwoCurve + ".20");
-    
+    static final ASN1ObjectIdentifier  cTwoCurve = ellipticCurve.branch("0");
+
+    static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1");
+    static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2");
+    static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3");
+    static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4");
+    static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5");
+    static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6");
+    static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7");
+    static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8");
+    static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9");
+    static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10");
+    static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11");
+    static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12");
+    static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13");
+    static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14");
+    static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15");
+    static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16");
+    static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17");
+    static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18");
+    static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19");
+    static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20");
+
     //
     // Prime
     //
-    static final String     primeCurve = ellipticCurve + ".1";
+    static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1");
 
-    static final DERObjectIdentifier    prime192v1 = new DERObjectIdentifier(primeCurve + ".1");
-    static final DERObjectIdentifier    prime192v2 = new DERObjectIdentifier(primeCurve + ".2");
-    static final DERObjectIdentifier    prime192v3 = new DERObjectIdentifier(primeCurve + ".3");
-    static final DERObjectIdentifier    prime239v1 = new DERObjectIdentifier(primeCurve + ".4");
-    static final DERObjectIdentifier    prime239v2 = new DERObjectIdentifier(primeCurve + ".5");
-    static final DERObjectIdentifier    prime239v3 = new DERObjectIdentifier(primeCurve + ".6");
-    static final DERObjectIdentifier    prime256v1 = new DERObjectIdentifier(primeCurve + ".7");
+    static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1");
+    static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2");
+    static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3");
+    static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4");
+    static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5");
+    static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6");
+    static final ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7");
+
+    //
+    // DSA
+    //
+    // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+    //            us(840) ansi-x957(10040) number-type(4) 1 }
+    static final ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1");
+
+    /**
+     * id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57
+     * (10040) x9cm(4) 3 }
+     */
+    public static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3");
+
+    /**
+     * X9.63
+     */
+    public static final ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0");
+    public static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2");
+    public static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3");
+    public static final ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch("16");
+
+    /**
+     * X9.42
+     */
+
+    static final ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046");
 
     //
     // Diffie-Hellman
@@ -103,40 +118,15 @@
     // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
     //            us(840) ansi-x942(10046) number-type(2) 1 }
     //
-    static final DERObjectIdentifier    dhpublicnumber = new DERObjectIdentifier("1.2.840.10046.2.1");
+    public static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1");
 
-    //
-    // DSA
-    //
-    // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
-    //            us(840) ansi-x957(10040) number-type(4) 1 }
-    static final DERObjectIdentifier    id_dsa = new DERObjectIdentifier("1.2.840.10040.4.1");
-
-    /**
-     *   id-dsa-with-sha1 OBJECT IDENTIFIER ::=  { iso(1) member-body(2)
-     *         us(840) x9-57 (10040) x9cm(4) 3 }
-     */
-    public static final DERObjectIdentifier id_dsa_with_sha1 = new DERObjectIdentifier("1.2.840.10040.4.3");
-
-    /**
-     * X9.63
-     */
-    public static final DERObjectIdentifier x9_63_scheme = new DERObjectIdentifier("1.3.133.16.840.63.0");
-    public static final DERObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = new DERObjectIdentifier(x9_63_scheme + ".2");
-    public static final DERObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = new DERObjectIdentifier(x9_63_scheme + ".3");
-    public static final DERObjectIdentifier mqvSinglePass_sha1kdf_scheme = new DERObjectIdentifier(x9_63_scheme + ".16");
-
-    /**
-     * X9.42
-     */
-    public static final DERObjectIdentifier x9_42_schemes = new DERObjectIdentifier("1.2.840.10046.3");
-    public static final DERObjectIdentifier dhStatic = new DERObjectIdentifier(x9_42_schemes + ".1");
-    public static final DERObjectIdentifier dhEphem = new DERObjectIdentifier(x9_42_schemes + ".2");
-    public static final DERObjectIdentifier dhOneFlow = new DERObjectIdentifier(x9_42_schemes + ".3");
-    public static final DERObjectIdentifier dhHybrid1 = new DERObjectIdentifier(x9_42_schemes + ".4");
-    public static final DERObjectIdentifier dhHybrid2 = new DERObjectIdentifier(x9_42_schemes + ".5");
-    public static final DERObjectIdentifier dhHybridOneFlow = new DERObjectIdentifier(x9_42_schemes + ".6");
-    public static final DERObjectIdentifier mqv2 = new DERObjectIdentifier(x9_42_schemes + ".7");
-    public static final DERObjectIdentifier mqv1 = new DERObjectIdentifier(x9_42_schemes + ".8");
+    public static final ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3");
+    public static final ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch("1");
+    public static final ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch("2");
+    public static final ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch("3");
+    public static final ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch("4");
+    public static final ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch("5");
+    public static final ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6");
+    public static final ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7");
+    public static final ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8");
 }
-
diff --git a/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java b/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
index 7f8adec..4878786 100644
--- a/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
+++ b/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
@@ -259,28 +259,34 @@
         int     outOff)
         throws DataLengthException, IllegalStateException, InvalidCipherTextException
     {
-        int resultLen = 0;
-
-        if (outOff + bufOff > out.length)
+        try
         {
-            throw new DataLengthException("output buffer too short for doFinal()");
-        }
+            int resultLen = 0;
 
-        if (bufOff != 0 && partialBlockOkay)
+            if (outOff + bufOff > out.length)
+            {
+                throw new DataLengthException("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
         {
-            cipher.processBlock(buf, 0, buf, 0);
-            resultLen = bufOff;
-            bufOff = 0;
-            System.arraycopy(buf, 0, out, outOff, resultLen);
+            reset();
         }
-        else if (bufOff != 0)
-        {
-            throw new DataLengthException("data not block size aligned");
-        }
-
-        reset();
-
-        return resultLen;
     }
 
     /**
diff --git a/src/main/java/org/bouncycastle/crypto/SignerWithRecovery.java b/src/main/java/org/bouncycastle/crypto/SignerWithRecovery.java
index 5a1e204..452b367 100644
--- a/src/main/java/org/bouncycastle/crypto/SignerWithRecovery.java
+++ b/src/main/java/org/bouncycastle/crypto/SignerWithRecovery.java
@@ -20,4 +20,15 @@
      * @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/src/main/java/org/bouncycastle/jce/provider/util/NullDigest.java b/src/main/java/org/bouncycastle/crypto/digests/NullDigest.java
similarity index 94%
rename from src/main/java/org/bouncycastle/jce/provider/util/NullDigest.java
rename to src/main/java/org/bouncycastle/crypto/digests/NullDigest.java
index 820ad1b..6cb0d4a 100644
--- a/src/main/java/org/bouncycastle/jce/provider/util/NullDigest.java
+++ b/src/main/java/org/bouncycastle/crypto/digests/NullDigest.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.jce.provider.util;
+package org.bouncycastle.crypto.digests;
 
 import java.io.ByteArrayOutputStream;
 
diff --git a/src/main/java/org/bouncycastle/crypto/encodings/ISO9796d1Encoding.java b/src/main/java/org/bouncycastle/crypto/encodings/ISO9796d1Encoding.java
index b4d84c6..ec91e1a 100644
--- a/src/main/java/org/bouncycastle/crypto/encodings/ISO9796d1Encoding.java
+++ b/src/main/java/org/bouncycastle/crypto/encodings/ISO9796d1Encoding.java
@@ -1,5 +1,7 @@
 package org.bouncycastle.crypto.encodings;
 
+import java.math.BigInteger;
+
 import org.bouncycastle.crypto.AsymmetricBlockCipher;
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.InvalidCipherTextException;
@@ -9,13 +11,16 @@
 /**
  * ISO 9796-1 padding. Note in the light of recent results you should
  * only use this with RSA (rather than the "simpler" Rabin keys) and you
- * should never use it with anything other than a hash (ie. even if the 
+ * should never use it with anything other than a hash (ie. even if the
  * message is small don't sign the message, sign it's hash) or some "random"
  * value. See your favorite search engine for details.
  */
 public class ISO9796d1Encoding
     implements AsymmetricBlockCipher
 {
+    private static final BigInteger SIXTEEN = BigInteger.valueOf(16L);
+    private static final BigInteger SIX     = BigInteger.valueOf(6L);
+
     private static byte[]    shadows = { 0xe, 0x3, 0x5, 0x8, 0x9, 0x4, 0x2, 0xf,
                                     0x0, 0xd, 0xb, 0x6, 0x7, 0xa, 0xc, 0x1 };
     private static byte[]    inverse = { 0x8, 0xf, 0x6, 0x1, 0x5, 0x2, 0xb, 0xc,
@@ -25,12 +30,13 @@
     private boolean                 forEncryption;
     private int                     bitSize;
     private int                     padBits = 0;
+    private BigInteger              modulus;
 
     public ISO9796d1Encoding(
         AsymmetricBlockCipher   cipher)
     {
         this.engine = cipher;
-    }   
+    }
 
     public AsymmetricBlockCipher getUnderlyingCipher()
     {
@@ -56,14 +62,15 @@
 
         engine.init(forEncryption, param);
 
-        bitSize = kParam.getModulus().bitLength();
+        modulus = kParam.getModulus();
+        bitSize = modulus.bitLength();
 
         this.forEncryption = forEncryption;
     }
 
     /**
      * return the input block size. The largest message we can process
-     * is (key_size_in_bits + 3)/16, which in our world comes to 
+     * is (key_size_in_bits + 3)/16, which in our world comes to
      * key_size_in_bytes / 2.
      */
     public int getInputBlockSize()
@@ -98,7 +105,7 @@
     }
 
     /**
-     * set the number of bits in the next message to be treated as 
+     * set the number of bits in the next message to be treated as
      * pad bits.
      */
     public void setPadBits(
@@ -163,7 +170,7 @@
         for (int i = block.length - 2 * t; i != block.length; i += 2)
         {
             byte    val = block[block.length - t + i / 2];
-            
+
             block[i] = (byte)((shadows[(val & 0xff) >>> 4] << 4)
                                                 | shadows[val & 0x0f]);
             block[i + 1] = val;
@@ -203,7 +210,24 @@
         int     r = 1;
         int     t = (bitSize + 13) / 16;
 
-        if ((block[block.length - 1] & 0x0f) != 0x6)
+        BigInteger iS = new BigInteger(1, block);
+        BigInteger iR;
+        if (iS.mod(SIXTEEN).equals(SIX))
+        {
+            iR = iS;
+        }
+        else if ((modulus.subtract(iS)).mod(SIXTEEN).equals(SIX))
+        {
+            iR = modulus.subtract(iS);
+        }
+        else
+        {
+            throw new InvalidCipherTextException("resulting integer iS or (modulus - iS) is not congruent to 6 mod 16");
+        }
+
+        block = convertOutputDecryptOnly(iR);
+
+        if ((block[block.length - 1] & 0x0f) != 0x6 )
         {
             throw new InvalidCipherTextException("invalid forcing byte in block");
         }
@@ -214,12 +238,12 @@
 
         boolean boundaryFound = false;
         int     boundary = 0;
-        
+
         for (int i = block.length - 1; i >= block.length - 2 * t; i -= 2)
         {
             int val = ((shadows[(block[i] & 0xff) >>> 4] << 4)
                                         | shadows[block[i] & 0x0f]);
-            
+
             if (((block[i - 1] ^ val) & 0xff) != 0)
             {
                 if (!boundaryFound)
@@ -248,4 +272,16 @@
 
         return nblock;
     }
+
+    private static byte[] convertOutputDecryptOnly(BigInteger result)
+    {
+        byte[] output = result.toByteArray();
+        if (output[0] == 0) // 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;
+        }
+        return output;
+    }
 }
diff --git a/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java b/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java
index 2554c30..05c7839 100644
--- a/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java
+++ b/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java
@@ -3,67 +3,90 @@
 import java.math.BigInteger;
 import java.security.SecureRandom;
 
+// BEGIN android-added
+import java.util.logging.Logger;
+// END android-added
 import org.bouncycastle.util.BigIntegers;
 
 class DHParametersHelper
 {
+    // BEGIN android-added
+    private static final Logger logger = Logger.getLogger(DHParametersHelper.class.getName());
+    // END android-added
+
     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}
-    static BigInteger[] generateSafePrimes(
-        int             size,
-        int             certainty,
-        SecureRandom    random)
+    /*
+     * 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
+        logger.info("Generating safe primes. This may take a long time.");
+        long start = System.currentTimeMillis();
+        int tries = 0;
+        // END android-added
         BigInteger p, q;
         int qLength = size - 1;
 
         for (;;)
         {
+            // BEGIN android-added
+            tries++;
+            // END android-added
             q = new BigInteger(qLength, 2, random);
 
             // p <- 2q + 1
             p = q.shiftLeft(1).add(ONE);
 
-            if (p.isProbablePrime(certainty)
-                && (certainty <= 2 || q.isProbablePrime(certainty)))
+            if (p.isProbablePrime(certainty) && (certainty <= 2 || q.isProbablePrime(certainty)))
             {
-                    break;
+                break;
             }
         }
+        // BEGIN android-added
+        long end = System.currentTimeMillis();
+        long duration = end - start;
+        logger.info("Generated safe primes: " + tries + " tries took " + duration + "ms");
+        // END android-added
 
         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
-    static BigInteger selectGenerator(
-        BigInteger      p,
-        BigInteger      q,
-        SecureRandom    random)
+    /*
+     * 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;
 
-        // Handbook of Applied Cryptography 4.86
-        do
-        {
-            g = BigIntegers.createRandomInRange(TWO, pMinusTwo, random);
-        }
-        while (g.modPow(TWO, p).equals(ONE)
-            || g.modPow(q, p).equals(ONE));
+        /*
+         * (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.1.1 (and see Handbook of Applied Cryptography 4.81)
+
+        /*
+         * RFC 2631 2.2.1.2 (and see: Handbook of Applied Cryptography 4.81)
+         */
         do
         {
-            BigInteger h = createInRange(TWO, pMinusTwo, random);
+            BigInteger h = BigIntegers.createRandomInRange(TWO, pMinusTwo, random);
 
             g = h.modPow(TWO, p);
         }
         while (g.equals(ONE));
-*/
+
 
         return g;
     }
diff --git a/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
index aa8a4cc..be977d7 100644
--- a/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
+++ b/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
@@ -178,7 +178,7 @@
         int seedlen = N;
         byte[] seed = new byte[seedlen / 8];
 
-// 3. n = ⎡L ⁄ outlen⎤ – 1.
+// 3. n = ceiling(L ⁄ outlen) – 1.
         int n = (L - 1) / outlen;
 
 // 4. b = L – 1 – (n ∗ outlen).
@@ -288,7 +288,7 @@
 //        BigInteger e = p.subtract(ONE).divide(q);
 //        byte[] ggen = Hex.decode("6767656E");
 //
-//        // 7. U = domain_parameter_seed || “ggen” || index || count.
+//        // 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);
diff --git a/src/main/java/org/bouncycastle/crypto/macs/CMac.java b/src/main/java/org/bouncycastle/crypto/macs/CMac.java
deleted file mode 100644
index c5bc504..0000000
--- a/src/main/java/org/bouncycastle/crypto/macs/CMac.java
+++ /dev/null
@@ -1,237 +0,0 @@
-package org.bouncycastle.crypto.macs;
-
-import org.bouncycastle.crypto.BlockCipher;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.Mac;
-import org.bouncycastle.crypto.modes.CBCBlockCipher;
-import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
-
-/**
- * CMAC - as specified at www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html
- * <p>
- * CMAC is analogous to OMAC1 - see also en.wikipedia.org/wiki/CMAC
- * </p><p>
- * CMAC is a NIST recomendation - see 
- * csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
- * </p><p>
- * CMAC/OMAC1 is a blockcipher-based message authentication code designed and
- * analyzed by Tetsu Iwata and Kaoru Kurosawa.
- * </p><p>
- * CMAC/OMAC1 is a simple variant of the CBC MAC (Cipher Block Chaining Message 
- * Authentication Code). OMAC stands for One-Key CBC MAC.
- * </p><p>
- * It supports 128- or 64-bits block ciphers, with any key size, and returns
- * a MAC with dimension less or equal to the block size of the underlying 
- * cipher.
- * </p>
- */
-public class CMac implements Mac
-{
-    private static final byte CONSTANT_128 = (byte)0x87;
-    private static final byte CONSTANT_64 = (byte)0x1b;
-
-    private byte[] ZEROES;
-
-    private byte[] mac;
-
-    private byte[] buf;
-    private int bufOff;
-    private BlockCipher cipher;
-
-    private int macSize;
-
-    private byte[] L, Lu, Lu2;
-
-    /**
-     * create a standard MAC based on a CBC block cipher (64 or 128 bit block).
-     * This will produce an authentication code the length of the block size
-     * of the cipher.
-     *
-     * @param cipher the cipher to be used as the basis of the MAC generation.
-     */
-    public CMac(BlockCipher cipher)
-    {
-        this(cipher, cipher.getBlockSize() * 8);
-    }
-
-    /**
-     * create a standard MAC based on a block cipher with the size of the
-     * MAC been given in bits.
-     * <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 and <= 128.
-     */
-    public CMac(BlockCipher cipher, int macSizeInBits)
-    {
-        if ((macSizeInBits % 8) != 0)
-        {
-            throw new IllegalArgumentException("MAC size must be multiple of 8");
-        }
-
-        if (macSizeInBits > (cipher.getBlockSize() * 8))
-        {
-            throw new IllegalArgumentException(
-                "MAC size must be less or equal to "
-                    + (cipher.getBlockSize() * 8));
-        }
-
-        if (cipher.getBlockSize() != 8 && cipher.getBlockSize() != 16)
-        {
-            throw new IllegalArgumentException(
-                "Block size must be either 64 or 128 bits");
-        }
-
-        this.cipher = new CBCBlockCipher(cipher);
-        this.macSize = macSizeInBits / 8;
-
-        mac = new byte[cipher.getBlockSize()];
-
-        buf = new byte[cipher.getBlockSize()];
-
-        ZEROES = new byte[cipher.getBlockSize()];
-
-        bufOff = 0;
-    }
-
-    public String getAlgorithmName()
-    {
-        return cipher.getAlgorithmName();
-    }
-
-    private byte[] doubleLu(byte[] in)
-    {
-        int FirstBit = (in[0] & 0xFF) >> 7;
-        byte[] ret = new byte[in.length];
-        for (int i = 0; i < in.length - 1; i++)
-        {
-            ret[i] = (byte)((in[i] << 1) + ((in[i + 1] & 0xFF) >> 7));
-        }
-        ret[in.length - 1] = (byte)(in[in.length - 1] << 1);
-        if (FirstBit == 1)
-        {
-            ret[in.length - 1] ^= in.length == 16 ? CONSTANT_128 : CONSTANT_64;
-        }
-        return ret;
-    }
-
-    public void init(CipherParameters params)
-    {
-        reset();
-
-        cipher.init(true, params);
-
-        //initializes the L, Lu, Lu2 numbers
-        L = new byte[ZEROES.length];
-        cipher.processBlock(ZEROES, 0, L, 0);
-        Lu = doubleLu(L);
-        Lu2 = doubleLu(Lu);
-
-        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();
-
-        byte[] lu;
-        if (bufOff == blockSize)
-        {
-            lu = Lu;
-        }
-        else
-        {
-            new ISO7816d4Padding().addPadding(buf, bufOff);
-            lu = Lu2;
-        }
-
-        for (int i = 0; i < mac.length; i++)
-        {
-            buf[i] ^= lu[i];
-        }
-
-        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/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java b/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java
deleted file mode 100644
index 327026e..0000000
--- a/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java
+++ /dev/null
@@ -1,304 +0,0 @@
-package org.bouncycastle.crypto.modes;
-
-import org.bouncycastle.crypto.BlockCipher;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.Mac;
-import org.bouncycastle.crypto.macs.CMac;
-import org.bouncycastle.crypto.params.AEADParameters;
-import org.bouncycastle.crypto.params.ParametersWithIV;
-import org.bouncycastle.util.Arrays;
-
-/**
- * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and 
- * Efficiency - by M. Bellare, P. Rogaway, D. Wagner.
- * 
- * http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
- * 
- * EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block 
- * cipher to encrypt and authenticate data. It's on-line (the length of a 
- * message isn't needed to begin processing it), has good performances, it's
- * simple and provably secure (provided the underlying block cipher is secure).
- * 
- * Of course, this implementations is NOT thread-safe.
- */
-public class EAXBlockCipher
-    implements AEADBlockCipher
-{
-    private static final byte nTAG = 0x0;
-
-    private static final byte hTAG = 0x1;
-
-    private static final byte cTAG = 0x2;
-
-    private SICBlockCipher cipher;
-
-    private boolean forEncryption;
-
-    private int blockSize;
-
-    private Mac mac;
-
-    private byte[] nonceMac;
-    private byte[] associatedTextMac;
-    private byte[] macBlock;
-    
-    private int macSize;
-    private byte[] bufBlock;
-    private int bufOff;
-
-    /**
-     * Constructor that accepts an instance of a block cipher engine.
-     *
-     * @param cipher the engine to use
-     */
-    public EAXBlockCipher(BlockCipher cipher)
-    {
-        blockSize = cipher.getBlockSize();
-        mac = new CMac(cipher);
-        macBlock = new byte[blockSize];
-        bufBlock = new byte[blockSize * 2];
-        associatedTextMac = new byte[mac.getMacSize()];
-        nonceMac = new byte[mac.getMacSize()];
-        this.cipher = new SICBlockCipher(cipher);
-    }
-
-    public String getAlgorithmName()
-    {
-        return cipher.getUnderlyingCipher().getAlgorithmName() + "/EAX";
-    }
-
-    public BlockCipher getUnderlyingCipher()
-    {
-        return cipher.getUnderlyingCipher();
-    }
-
-    public int getBlockSize()
-    {
-        return cipher.getBlockSize();
-    }
-
-    public void init(boolean forEncryption, CipherParameters params)
-        throws IllegalArgumentException
-    {
-        this.forEncryption = forEncryption;
-
-        byte[] nonce, associatedText;
-        CipherParameters keyParam;
-
-        if (params instanceof AEADParameters)
-        {
-            AEADParameters param = (AEADParameters)params;
-
-            nonce = param.getNonce();
-            associatedText = param.getAssociatedText();
-            macSize = param.getMacSize() / 8;
-            keyParam = param.getKey();
-        }
-        else if (params instanceof ParametersWithIV)
-        {
-            ParametersWithIV param = (ParametersWithIV)params;
-
-            nonce = param.getIV();
-            associatedText = new byte[0];
-            macSize = mac.getMacSize() / 2;
-            keyParam = param.getParameters();
-        }
-        else
-        {
-            throw new IllegalArgumentException("invalid parameters passed to EAX");
-        }
-
-        byte[] tag = new byte[blockSize];
-
-        mac.init(keyParam);
-        tag[blockSize - 1] = hTAG;
-        mac.update(tag, 0, blockSize);
-        mac.update(associatedText, 0, associatedText.length);
-        mac.doFinal(associatedTextMac, 0);
-
-        tag[blockSize - 1] = nTAG;
-        mac.update(tag, 0, blockSize);
-        mac.update(nonce, 0, nonce.length);
-        mac.doFinal(nonceMac, 0);
-
-        tag[blockSize - 1] = cTAG;
-        mac.update(tag, 0, blockSize);
-
-        cipher.init(true, new ParametersWithIV(keyParam, nonceMac));
-    }
-
-    private void calculateMac()
-    {
-        byte[] outC = new byte[blockSize];
-        mac.doFinal(outC, 0);
-
-        for (int i = 0; i < macBlock.length; i++)
-        {
-            macBlock[i] = (byte)(nonceMac[i] ^ associatedTextMac[i] ^ outC[i]);
-        }
-    }
-
-    public void reset()
-    {
-        reset(true);
-    }
-
-    private void reset(
-        boolean clearMac)
-    {
-        cipher.reset();
-        mac.reset();
-
-        bufOff = 0;
-        Arrays.fill(bufBlock, (byte)0);
-
-        if (clearMac)
-        {
-            Arrays.fill(macBlock, (byte)0);
-        }
-
-        byte[] tag = new byte[blockSize];
-        tag[blockSize - 1] = cTAG;
-        mac.update(tag, 0, blockSize);
-    }
-
-    public int processByte(byte in, byte[] out, int outOff)
-        throws DataLengthException
-    {
-        return process(in, out, outOff);
-    }
-
-    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
-        throws DataLengthException
-    {
-        int resultLen = 0;
-
-        for (int i = 0; i != len; i++)
-        {
-            resultLen += process(in[inOff + i], out, outOff + resultLen);
-        }
-
-        return resultLen;
-    }
-
-    public int doFinal(byte[] out, int outOff)
-        throws IllegalStateException, InvalidCipherTextException
-    {
-        int extra = bufOff;
-        byte[] tmp = new byte[bufBlock.length];
-
-        bufOff = 0;
-
-        if (forEncryption)
-        {
-            cipher.processBlock(bufBlock, 0, tmp, 0);
-            cipher.processBlock(bufBlock, blockSize, tmp, blockSize);
-
-            System.arraycopy(tmp, 0, out, outOff, extra);
-
-            mac.update(tmp, 0, extra);
-
-            calculateMac();
-
-            System.arraycopy(macBlock, 0, out, outOff + extra, macSize);
-
-            reset(false);
-
-            return extra + macSize;
-        }
-        else
-        {
-            if (extra > macSize)
-            {
-                mac.update(bufBlock, 0, extra - macSize);
-
-                cipher.processBlock(bufBlock, 0, tmp, 0);
-                cipher.processBlock(bufBlock, blockSize, tmp, blockSize);
-
-                System.arraycopy(tmp, 0, out, outOff, extra - macSize);
-            }
-
-            calculateMac();
-
-            if (!verifyMac(bufBlock, extra - macSize))
-            {
-                throw new InvalidCipherTextException("mac check in EAX failed");
-            }
-
-            reset(false);
-
-            return extra - macSize;
-        }
-    }
-
-    public byte[] getMac()
-    {
-        byte[] mac = new byte[macSize];
-
-        System.arraycopy(macBlock, 0, mac, 0, macSize);
-
-        return mac;
-    }
-
-    public int getUpdateOutputSize(int len)
-    {
-        return ((len + bufOff) / blockSize) * blockSize;
-    }
-
-    public int getOutputSize(int len)
-    {
-        if (forEncryption)
-        {
-             return len + bufOff + macSize;
-        }
-        else
-        {
-             return len + bufOff - macSize;
-        }
-    }
-
-    private int process(byte b, byte[] out, int outOff)
-    {
-        bufBlock[bufOff++] = b;
-
-        if (bufOff == bufBlock.length)
-        {
-            int size;
-
-            if (forEncryption)
-            {
-                size = cipher.processBlock(bufBlock, 0, out, outOff);
-
-                mac.update(out, outOff, blockSize);
-            }
-            else
-            {
-                mac.update(bufBlock, 0, blockSize);
-
-                size = cipher.processBlock(bufBlock, 0, out, outOff);
-            }
-
-            bufOff = blockSize;
-            System.arraycopy(bufBlock, blockSize, bufBlock, 0, blockSize);
-
-            return size;
-        }
-
-        return 0;
-    }
-
-    private boolean verifyMac(byte[] mac, int off)
-    {
-        for (int i = 0; i < macSize; i++)
-        {
-            if (macBlock[i] != mac[off + i])
-            {
-                return false;
-            }
-        }
-
-        return true;
-    }
-}
diff --git a/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java b/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
index e866b34..e1949dc 100644
--- a/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
+++ b/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
@@ -1,9 +1,24 @@
 package org.bouncycastle.crypto.modes.gcm;
 
 import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.util.Arrays;
 
 abstract class GCMUtil
 {
+    static byte[] oneAsBytes()
+    {
+        byte[] tmp = new byte[16];
+        tmp[0] = (byte)0x80;
+        return tmp;
+    }
+
+    static int[] oneAsInts()
+    {
+        int[] tmp = new int[4];
+        tmp[0] = 0x80000000;
+        return tmp;
+    }
+
     static int[] asInts(byte[] bs)
     {
         int[] us = new int[4];
@@ -14,6 +29,35 @@
         return us;
     }
 
+    static void multiply(byte[] block, byte[] val)
+    {
+        byte[] tmp = Arrays.clone(block);
+        byte[] c = new byte[16];
+
+        for (int i = 0; i < 16; ++i)
+        {
+            byte bits = val[i];
+            for (int j = 7; j >= 0; --j)
+            {
+                if ((bits & (1 << j)) != 0)
+                {
+                    xor(c, tmp);
+                }
+
+                boolean lsb = (tmp[15] & 1) != 0;
+                shiftRight(tmp);
+                if (lsb)
+                {
+                    // R = new byte[]{ 0xe1, ... };
+//                    GCMUtil.xor(v, R);
+                    tmp[0] ^= (byte)0xe1;
+                }
+            }
+        }
+
+        System.arraycopy(c, 0, block, 0, 16);
+    }
+
     // P is the value with only bit i=1 set
     static void multiplyP(int[] x)
     {
diff --git a/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java b/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
index 0341227..99217b02 100644
--- a/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
+++ b/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
@@ -1,5 +1,8 @@
 package org.bouncycastle.crypto.signers;
 
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.DSA;
 import org.bouncycastle.crypto.params.ECKeyParameters;
@@ -10,9 +13,6 @@
 import org.bouncycastle.math.ec.ECConstants;
 import org.bouncycastle.math.ec.ECPoint;
 
-import java.math.BigInteger;
-import java.security.SecureRandom;
-
 /**
  * EC-DSA as described in X9.62
  */
@@ -76,7 +76,7 @@
                 {
                     k = new BigInteger(nBitLength, random);
                 }
-                while (k.equals(ZERO));
+                while (k.equals(ZERO) || k.compareTo(n) >= 0);
 
                 ECPoint p = key.getParameters().getG().multiply(k);
 
diff --git a/src/main/java/org/bouncycastle/crypto/util/Pack.java b/src/main/java/org/bouncycastle/crypto/util/Pack.java
index 12b5999..cdea3af 100644
--- a/src/main/java/org/bouncycastle/crypto/util/Pack.java
+++ b/src/main/java/org/bouncycastle/crypto/util/Pack.java
@@ -31,4 +31,34 @@
         intToBigEndian((int)(n >>> 32), bs, off);
         intToBigEndian((int)(n & 0xffffffffL), bs, off + 4);
     }
+
+    public static int littleEndianToInt(byte[] bs, int off)
+    {
+        int n = bs[  off];
+        n |= (bs[++off] & 0xff) << 8;
+        n |= (bs[++off] & 0xff) << 16;
+        n |= (bs[++off] & 0xff) << 24;
+        return n;
+    }
+
+    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 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 longToLittleEndian(long n, byte[] bs, int off)
+    {
+        intToLittleEndian((int)(n & 0xffffffffL), bs, off);
+        intToLittleEndian((int)(n >>> 32), bs, off + 4);
+    }
 }
diff --git a/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
index 94c8208..a352884 100644
--- a/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
+++ b/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
@@ -1,5 +1,9 @@
 package org.bouncycastle.crypto.util;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
 import org.bouncycastle.asn1.ASN1InputStream;
 import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1Sequence;
@@ -40,10 +44,6 @@
 // END android-removed
 import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-
 /**
  * Factory for creating private key objects from PKCS8 PrivateKeyInfo objects.
  */
@@ -56,29 +56,22 @@
      * @return a suitable private key parameter
      * @throws IOException on an error decoding the key
      */
-    public static AsymmetricKeyParameter createKey(
-        byte[] privateKeyInfoData)
-        throws IOException
+    public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) throws IOException
     {
-        return createKey(
-            PrivateKeyInfo.getInstance(
-                ASN1Object.fromByteArray(privateKeyInfoData)));
+        return createKey(PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(privateKeyInfoData)));
     }
 
     /**
-     * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding read from a stream.
+     * 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
+    public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException
     {
-        return createKey(
-            PrivateKeyInfo.getInstance(
-                new ASN1InputStream(inStr).readObject()));
+        return createKey(PrivateKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
     }
 
     /**
@@ -88,30 +81,27 @@
      * @return a suitable private key parameter
      * @throws IOException on an error decoding the key
      */
-    public static AsymmetricKeyParameter createKey(
-        PrivateKeyInfo    keyInfo)
-        throws IOException
+    public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) throws IOException
     {
-        AlgorithmIdentifier     algId = keyInfo.getAlgorithmId();
-        
-        if (algId.getObjectId().equals(PKCSObjectIdentifiers.rsaEncryption))
-        {
-            RSAPrivateKeyStructure  keyStructure = new RSAPrivateKeyStructure((ASN1Sequence)keyInfo.getPrivateKey());
+        AlgorithmIdentifier algId = keyInfo.getAlgorithmId();
 
-            return new RSAPrivateCrtKeyParameters(
-                                        keyStructure.getModulus(),
-                                        keyStructure.getPublicExponent(),
-                                        keyStructure.getPrivateExponent(),
-                                        keyStructure.getPrime1(),
-                                        keyStructure.getPrime2(),
-                                        keyStructure.getExponent1(),
-                                        keyStructure.getExponent2(),
-                                        keyStructure.getCoefficient());
+        if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption))
+        {
+            RSAPrivateKeyStructure keyStructure = new RSAPrivateKeyStructure(
+                (ASN1Sequence)keyInfo.getPrivateKey());
+
+            return new RSAPrivateCrtKeyParameters(keyStructure.getModulus(),
+                keyStructure.getPublicExponent(), keyStructure.getPrivateExponent(),
+                keyStructure.getPrime1(), keyStructure.getPrime2(), keyStructure.getExponent1(),
+                keyStructure.getExponent2(), keyStructure.getCoefficient());
         }
+        // TODO?
+//      else if (algId.getObjectId().equals(X9ObjectIdentifiers.dhpublicnumber))
         else if (algId.getObjectId().equals(PKCSObjectIdentifiers.dhKeyAgreement))
         {
-            DHParameter     params = new DHParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-            DERInteger      derX = (DERInteger)keyInfo.getPrivateKey();
+            DHParameter params = new DHParameter(
+                (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+            DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
 
             BigInteger lVal = params.getL();
             int l = lVal == null ? 0 : lVal.intValue();
@@ -122,44 +112,47 @@
         // BEGIN android-removed
         // else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
         // {
-        //     ElGamalParameter    params = new ElGamalParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-        //     DERInteger          derX = (DERInteger)keyInfo.getPrivateKey();
+        //     ElGamalParameter params = new ElGamalParameter(
+        //         (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+        //     DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
         //
-        //     return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(params.getP(), params.getG()));
+        //     return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(
+        //         params.getP(), params.getG()));
         // }
         // END android-removed
         else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa))
         {
             DERInteger derX = (DERInteger)keyInfo.getPrivateKey();
             DEREncodable de = keyInfo.getAlgorithmId().getParameters();
-        
+
             DSAParameters parameters = null;
             if (de != null)
             {
                 DSAParameter params = DSAParameter.getInstance(de.getDERObject());
                 parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
             }
-        
+
             return new DSAPrivateKeyParameters(derX.getValue(), parameters);
         }
         else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
         {
-            X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
-            ECDomainParameters  dParams = null;
-        
+            X962Parameters params = new X962Parameters(
+                (DERObject)keyInfo.getAlgorithmId().getParameters());
+            ECDomainParameters dParams = null;
+
             if (params.isNamedCurve())
             {
                 DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
-                X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
-        
+                X9ECParameters ecP = X962NamedCurves.getByOID(oid);
+
                 if (ecP == null)
                 {
                     ecP = SECNamedCurves.getByOID(oid);
-        
+
                     if (ecP == null)
                     {
                         ecP = NISTNamedCurves.getByOID(oid);
-        
+
                         // BEGIN android-removed
                         // if (ecP == null)
                         // {
@@ -168,28 +161,20 @@
                         // END android-removed
                     }
                 }
-        
-                dParams = new ECDomainParameters(
-                                            ecP.getCurve(),
-                                            ecP.getG(),
-                                            ecP.getN(),
-                                            ecP.getH(),
-                                            ecP.getSeed());
+
+                dParams = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(),
+                    ecP.getH(), ecP.getSeed());
             }
             else
             {
-                X9ECParameters ecP = new X9ECParameters(
-                            (ASN1Sequence)params.getParameters());
-                dParams = new ECDomainParameters(
-                                            ecP.getCurve(),
-                                            ecP.getG(),
-                                            ecP.getN(),
-                                            ecP.getH(),
-                                            ecP.getSeed());
+                X9ECParameters ecP = new X9ECParameters((ASN1Sequence)params.getParameters());
+                dParams = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(),
+                    ecP.getH(), ecP.getSeed());
             }
-        
-            ECPrivateKeyStructure   ec = new ECPrivateKeyStructure((ASN1Sequence)keyInfo.getPrivateKey());
-        
+
+            ECPrivateKeyStructure ec = new ECPrivateKeyStructure(
+                (ASN1Sequence)keyInfo.getPrivateKey());
+
             return new ECPrivateKeyParameters(ec.getKey(), dParams);
         }
         else
diff --git a/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
index f28c964..5e93a36 100644
--- a/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
+++ b/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
@@ -1,5 +1,9 @@
 package org.bouncycastle.crypto.util;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
 import org.bouncycastle.asn1.ASN1InputStream;
 import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1OctetString;
@@ -26,6 +30,9 @@
 import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.asn1.x9.DHDomainParameters;
+import org.bouncycastle.asn1.x9.DHPublicKey;
+import org.bouncycastle.asn1.x9.DHValidationParms;
 import org.bouncycastle.asn1.x9.X962NamedCurves;
 import org.bouncycastle.asn1.x9.X962Parameters;
 import org.bouncycastle.asn1.x9.X9ECParameters;
@@ -34,6 +41,7 @@
 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
 import org.bouncycastle.crypto.params.DHParameters;
 import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.crypto.params.DHValidationParameters;
 import org.bouncycastle.crypto.params.DSAParameters;
 import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
 import org.bouncycastle.crypto.params.ECDomainParameters;
@@ -44,13 +52,9 @@
 // END android-removed
 import org.bouncycastle.crypto.params.RSAKeyParameters;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-
 /**
- * Factory to create asymmetric public key parameters for asymmetric ciphers
- * from range of ASN.1 encoded SubjectPublicKeyInfo objects.
+ * Factory to create asymmetric public key parameters for asymmetric ciphers from range of
+ * ASN.1 encoded SubjectPublicKeyInfo objects.
  */
 public class PublicKeyFactory
 {
@@ -61,13 +65,9 @@
      * @return the appropriate key parameter
      * @throws IOException on an error decoding the key
      */
-    public static AsymmetricKeyParameter createKey(
-        byte[] keyInfoData)
-        throws IOException
+    public static AsymmetricKeyParameter createKey(byte[] keyInfoData) throws IOException
     {
-        return createKey(
-            SubjectPublicKeyInfo.getInstance(
-                ASN1Object.fromByteArray(keyInfoData)));
+        return createKey(SubjectPublicKeyInfo.getInstance(ASN1Object.fromByteArray(keyInfoData)));
     }
 
     /**
@@ -77,13 +77,9 @@
      * @return the appropriate key parameter
      * @throws IOException on an error decoding the key
      */
-    public static AsymmetricKeyParameter createKey(
-        InputStream inStr)
-        throws IOException
+    public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException
     {
-        return createKey(
-            SubjectPublicKeyInfo.getInstance(
-                new ASN1InputStream(inStr).readObject()));
+        return createKey(SubjectPublicKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
     }
 
     /**
@@ -93,25 +89,56 @@
      * @return the appropriate key parameter
      * @throws IOException on an error decoding the key
      */
-    public static AsymmetricKeyParameter createKey(
-        SubjectPublicKeyInfo    keyInfo)
-        throws IOException
+    public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo) throws IOException
     {
-        AlgorithmIdentifier     algId = keyInfo.getAlgorithmId();
-        
+        AlgorithmIdentifier algId = keyInfo.getAlgorithmId();
+
         if (algId.getObjectId().equals(PKCSObjectIdentifiers.rsaEncryption)
             || algId.getObjectId().equals(X509ObjectIdentifiers.id_ea_rsa))
         {
-            RSAPublicKeyStructure   pubKey = new RSAPublicKeyStructure((ASN1Sequence)keyInfo.getPublicKey());
+            RSAPublicKeyStructure pubKey = new RSAPublicKeyStructure(
+                (ASN1Sequence)keyInfo.getPublicKey());
 
             return new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent());
         }
-        else if (algId.getObjectId().equals(PKCSObjectIdentifiers.dhKeyAgreement)
-                 || algId.getObjectId().equals(X9ObjectIdentifiers.dhpublicnumber))
+        else if (algId.getObjectId().equals(X9ObjectIdentifiers.dhpublicnumber))
         {
-            DHParameter params = new DHParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-            DERInteger  derY = (DERInteger)keyInfo.getPublicKey();
-            
+            DHPublicKey dhPublicKey = DHPublicKey.getInstance(keyInfo.getPublicKey());
+
+            BigInteger y = dhPublicKey.getY().getValue();
+
+            DHDomainParameters dhParams = DHDomainParameters.getInstance(keyInfo.getAlgorithmId().getParameters());
+
+            BigInteger p = dhParams.getP().getValue();
+            BigInteger g = dhParams.getG().getValue();
+            BigInteger q = dhParams.getQ().getValue();
+
+            BigInteger j = null;
+            if (dhParams.getJ() != null)
+            {
+                j = dhParams.getJ().getValue();
+            }
+
+            DHValidationParameters validation = null;
+            DHValidationParms dhValidationParms = dhParams.getValidationParms();
+            if (dhValidationParms != null)
+            {
+                byte[] seed = dhValidationParms.getSeed().getBytes();
+                BigInteger pgenCounter = dhValidationParms.getPgenCounter().getValue();
+
+                // TODO Check pgenCounter size?
+
+                validation = new DHValidationParameters(seed, pgenCounter.intValue());
+            }
+
+            return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation));
+        }
+        else if (algId.getObjectId().equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+            DHParameter params = new DHParameter(
+                (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+            DERInteger derY = (DERInteger)keyInfo.getPublicKey();
+
             BigInteger lVal = params.getL();
             int l = lVal == null ? 0 : lVal.intValue();
             DHParameters dhParams = new DHParameters(params.getP(), params.getG(), null, l);
@@ -121,14 +148,16 @@
         // BEGIN android-removed
         // else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
         // {
-        //     ElGamalParameter    params = new ElGamalParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
-        //     DERInteger          derY = (DERInteger)keyInfo.getPublicKey();
+        //     ElGamalParameter params = new ElGamalParameter(
+        //         (ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+        //     DERInteger derY = (DERInteger)keyInfo.getPublicKey();
         //
-        //     return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(params.getP(), params.getG()));
+        //     return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
+        //         params.getP(), params.getG()));
         // }
         // END android-removed
         else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa)
-                 || algId.getObjectId().equals(OIWObjectIdentifiers.dsaWithSHA1))
+            || algId.getObjectId().equals(OIWObjectIdentifiers.dsaWithSHA1))
         {
             DERInteger derY = (DERInteger)keyInfo.getPublicKey();
             DEREncodable de = keyInfo.getAlgorithmId().getParameters();
@@ -144,22 +173,23 @@
         }
         else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
         {
-            X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
-            ECDomainParameters  dParams = null;
-        
+            X962Parameters params = new X962Parameters(
+                (DERObject)keyInfo.getAlgorithmId().getParameters());
+            ECDomainParameters dParams = null;
+
             if (params.isNamedCurve())
             {
                 DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
-                X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
-        
+                X9ECParameters ecP = X962NamedCurves.getByOID(oid);
+
                 if (ecP == null)
                 {
                     ecP = SECNamedCurves.getByOID(oid);
-        
+
                     if (ecP == null)
                     {
                         ecP = NISTNamedCurves.getByOID(oid);
-        
+
                         // BEGIN android-removed
                         // if (ecP == null)
                         // {
@@ -168,32 +198,23 @@
                         // END android-removed
                     }
                 }
-        
-                dParams = new ECDomainParameters(
-                                            ecP.getCurve(),
-                                            ecP.getG(),
-                                            ecP.getN(),
-                                            ecP.getH(),
-                                            ecP.getSeed());
+
+                dParams = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(),
+                    ecP.getH(), ecP.getSeed());
             }
             else
             {
-                X9ECParameters ecP = new X9ECParameters(
-                            (ASN1Sequence)params.getParameters());
-                dParams = new ECDomainParameters(
-                                            ecP.getCurve(),
-                                            ecP.getG(),
-                                            ecP.getN(),
-                                            ecP.getH(),
-                                            ecP.getSeed());
+                X9ECParameters ecP = new X9ECParameters((ASN1Sequence)params.getParameters());
+                dParams = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(),
+                    ecP.getH(), ecP.getSeed());
             }
-        
-            DERBitString    bits = keyInfo.getPublicKeyData();
-            byte[]          data = bits.getBytes();
+
+            DERBitString bits = keyInfo.getPublicKeyData();
+            byte[] data = bits.getBytes();
             ASN1OctetString key = new DEROctetString(data);
-        
-            X9ECPoint       derQ = new X9ECPoint(dParams.getCurve(), key);
-        
+
+            X9ECPoint derQ = new X9ECPoint(dParams.getCurve(), key);
+
             return new ECPublicKeyParameters(derQ.getPoint(), dParams);
         }
         else
diff --git a/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java b/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
new file mode 100644
index 0000000..5c0fe7d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
@@ -0,0 +1,125 @@
+package org.bouncycastle.jce;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+// END android-removed
+import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * a table of locally supported named curves.
+ */
+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 = X962NamedCurves.getByName(name);
+        if (ecP == null)
+        {
+            try
+            {
+                ecP = X962NamedCurves.getByOID(new DERObjectIdentifier(name));
+            }
+            catch (IllegalArgumentException e)
+            {
+                // ignore - not an oid
+            }
+        }
+        
+        if (ecP == null)
+        {
+            ecP = SECNamedCurves.getByName(name);
+            if (ecP == null)
+            {
+                try
+                {
+                    ecP = SECNamedCurves.getByOID(new DERObjectIdentifier(name));
+                }
+                catch (IllegalArgumentException e)
+                {
+                    // ignore - not an oid
+                }
+            }
+        }
+
+        // BEGIN android-removed
+        // if (ecP == null)
+        // {
+        //     ecP = TeleTrusTNamedCurves.getByName(name);
+        //     if (ecP == null)
+        //     {
+        //         try
+        //         {
+        //             ecP = TeleTrusTNamedCurves.getByOID(new DERObjectIdentifier(name));
+        //         }
+        //         catch (IllegalArgumentException e)
+        //         {
+        //             // ignore - not an oid
+        //         }
+        //     }
+        // }
+        // END android-removed
+
+        if (ecP == null)
+        {
+            ecP = NISTNamedCurves.getByName(name);
+        }
+        
+        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()
+    {
+        Vector v = new Vector();
+        
+        addEnumeration(v, X962NamedCurves.getNames());
+        addEnumeration(v, SECNamedCurves.getNames());
+        addEnumeration(v, NISTNamedCurves.getNames());
+        // BEGIN android-removed
+        // addEnumeration(v, TeleTrusTNamedCurves.getNames());
+        // END android-removed
+
+        return v.elements();
+    }
+
+    private static void addEnumeration(
+        Vector v, 
+        Enumeration e)
+    {
+        while (e.hasMoreElements())
+        {
+            v.addElement(e.nextElement());
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java b/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
index cdca7a9..ad1cfb2 100644
--- a/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
+++ b/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
@@ -1,5 +1,25 @@
 package 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 org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1InputStream;
 import org.bouncycastle.asn1.ASN1Object;
@@ -22,27 +42,9 @@
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.asn1.x509.X509Name;
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.util.Strings;
 
-import javax.security.auth.x500.X500Principal;
-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;
-
 /**
  * A class for verifying and creating PKCS10 Certification requests. 
  * <pre>
@@ -88,8 +90,10 @@
         algorithms.put("RSAWITHMD5", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
         algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
         algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
-        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        // BEGIN android-removed
+        // algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        // algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        // END android-removed
         algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
         algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
         algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
@@ -97,39 +101,59 @@
         algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
         algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
         algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
-        algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        // BEGIN android-removed
+        // algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        // END android-removed
         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 DERObjectIdentifier("1.2.840.113549.1.1.5"));
-        algorithms.put("RIPEMD160WITHRSAENCRYPTION", new DERObjectIdentifier("1.3.36.3.3.1.2"));
-        algorithms.put("RIPEMD160WITHRSA", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+        // BEGIN android-removed
+        // 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
         algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
         algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
-        algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+        // BEGIN android-removed
+        // algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+        // END android-removed
         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);
+        // BEGIN android-removed
+        // algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+        // END android-removed
         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);
-        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);
+        // BEGIN android-removed
+        // 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
 
         //
         // reverse mappings
         //
         oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
-        oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+        // BEGIN android-removed
+        // oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+        // END android-removed
         oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
         oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
         oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
-        oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
-        oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
+        // BEGIN android-removed
+        // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+        // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
+        // END android-removed
         
         oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
         // BEGIN android-removed
@@ -138,13 +162,17 @@
         // END android-removed
         oids.put(new DERObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
-        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+        // BEGIN android-removed
+        // oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+        // END android-removed
         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");
+        // BEGIN android-removed
+        // oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
+        // END android-removed
         oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
         
         //
@@ -158,19 +186,25 @@
         // The parameters field SHALL be NULL for RSA based signature algorithms.
         //
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
-        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+        // BEGIN android-removed
+        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+        // END android-removed
         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);
+        // BEGIN android-removed
+        // noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+        // END android-removed
         noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
 
         //
         // RFC 4491
         //
-        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
-        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // BEGIN android-removed
+        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // END android-removed
         //
         // explicit params
         //
@@ -179,10 +213,12 @@
         // END android-changed
         params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
 
-        // BEGIN android-changed
-        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
-        // END android-changed
-        params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+        // BEGIN android-removed
+        // // BEGIN android-changed
+        // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+        // // END android-changed
+        // params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+        // END android-removed
 
         // BEGIN android-changed
         AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
@@ -252,7 +288,7 @@
         throws NoSuchAlgorithmException, NoSuchProviderException,
                 InvalidKeyException, SignatureException
     {
-        this(signatureAlgorithm, subject, key, attributes, signingKey, "BC");
+        this(signatureAlgorithm, subject, key, attributes, signingKey, BouncyCastleProvider.PROVIDER_NAME);
     }
 
     private static X509Name convertName(
@@ -280,7 +316,7 @@
         throws NoSuchAlgorithmException, NoSuchProviderException,
                 InvalidKeyException, SignatureException
     {
-        this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, "BC");
+        this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, BouncyCastleProvider.PROVIDER_NAME);
     }
     
     /**
@@ -317,7 +353,14 @@
 
         if (sigOID == null)
         {
-            throw new IllegalArgumentException("Unknown signature type requested");
+            try
+            {
+                sigOID = new DERObjectIdentifier(algorithmName);
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException("Unknown signature type requested");
+            }
         }
 
         if (subject == null)
@@ -340,7 +383,7 @@
         }
         else
         {
-            this.sigAlgId = new AlgorithmIdentifier(sigOID, null);
+            this.sigAlgId = new AlgorithmIdentifier(sigOID, DERNull.INSTANCE);
         }
 
         try
@@ -384,7 +427,7 @@
     public PublicKey getPublicKey()
         throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException
     {
-        return getPublicKey("BC");
+        return getPublicKey(BouncyCastleProvider.PROVIDER_NAME);
     }
 
     public PublicKey getPublicKey(
@@ -444,7 +487,7 @@
         throws NoSuchAlgorithmException, NoSuchProviderException,
                 InvalidKeyException, SignatureException
     {
-        return verify("BC");
+        return verify(BouncyCastleProvider.PROVIDER_NAME);
     }
 
     /**
@@ -595,10 +638,12 @@
         {
             return "SHA1";
         }
-        else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
-        {
-            return "SHA224";
-        }
+        // BEGIN android-removed
+        // else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+        // {
+        //     return "SHA224";
+        // }
+        // END android-removed
         else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
         {
             return "SHA256";
@@ -611,22 +656,24 @@
         {
             return "SHA512";
         }
-        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";
-        }
+        // BEGIN android-removed
+        // 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
         else
         {
             return digestAlgOID.getId();            
diff --git a/src/main/java/org/bouncycastle/jce/X509Principal.java b/src/main/java/org/bouncycastle/jce/X509Principal.java
index 1d867e7..9cc5538 100644
--- a/src/main/java/org/bouncycastle/jce/X509Principal.java
+++ b/src/main/java/org/bouncycastle/jce/X509Principal.java
@@ -1,15 +1,15 @@
 package org.bouncycastle.jce;
 
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.x509.X509Name;
-
 import java.io.IOException;
 import java.security.Principal;
 import java.util.Hashtable;
 import java.util.Vector;
 
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.x509.X509Name;
+
 /**
  * a general extension of X509Name with a couple of extra methods and
  * constructors.
diff --git a/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java b/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
index e34d7ed..5179298 100644
--- a/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
+++ b/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
@@ -22,7 +22,6 @@
 import org.bouncycastle.asn1.DERBitString;
 import org.bouncycastle.asn1.DERIA5String;
 import org.bouncycastle.asn1.DERObject;
-import org.bouncycastle.asn1.DEROutputStream;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
diff --git a/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index b014312..f712938 100644
--- a/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -43,7 +43,7 @@
 public final class BouncyCastleProvider extends Provider
     implements ConfigurableProvider
 {
-    private static String info = "BouncyCastle Security Provider v1.45";
+    private static String info = "BouncyCastle Security Provider v1.46";
 
     // BEGIN android-changed
     //     this constant should be final
@@ -57,11 +57,13 @@
     private static final String[] SYMMETRIC_CIPHERS =
     {
         // BEGIN android-removed
-        // "AES", "Camellia", "CAST5", "Grainv1", "Grain128", "IDEA", "Noekeon", "SEED"
+        // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DESede", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
+        // "Noekeon", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
         // END android-removed
         // BEGIN android-added
-        "AES",
+        "AES", "ARC4", "Blowfish", "DESede",
         // END android-added
+
     };
 
     /*
@@ -80,7 +82,7 @@
      */
     public BouncyCastleProvider()
     {
-        super(PROVIDER_NAME, 1.45, info);
+        super(PROVIDER_NAME, 1.46, info);
 
         AccessController.doPrivileged(new PrivilegedAction()
         {
@@ -294,50 +296,16 @@
         // cipher engines
         //
         put("Cipher.DES", "org.bouncycastle.jce.provider.JCEBlockCipher$DES");
-        put("Cipher.DESEDE", "org.bouncycastle.jce.provider.JCEBlockCipher$DESede");
         // BEGIN android-removed
-        // put("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JCEBlockCipher$DESedeCBC");
         // put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.JCEBlockCipher$DESCBC");
-        // END android-removed
-        put("Cipher.DESEDEWRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$DESEDEWrap");
-        // BEGIN android-changed
-        put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWRAP");
-        // END android-changed
-        // BEGIN android-removed
-        // put("Cipher.SKIPJACK", "org.bouncycastle.jce.provider.JCEBlockCipher$Skipjack");
-        // END android-removed
-        put("Cipher.BLOWFISH", "org.bouncycastle.jce.provider.JCEBlockCipher$Blowfish");
-        // BEGIN android-removed
-        // put("Cipher.1.3.6.1.4.1.3029.1.2", "org.bouncycastle.jce.provider.JCEBlockCipher$BlowfishCBC");
-        // put("Cipher.TWOFISH", "org.bouncycastle.jce.provider.JCEBlockCipher$Twofish");
+        //
         // put("Cipher.RC2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2");
         // put("Cipher.RC2WRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
         // put("Cipher.1.2.840.113549.1.9.16.3.7", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
-        // END android-removed
-        put("Cipher.ARC4", "org.bouncycastle.jce.provider.JCEStreamCipher$RC4");
-        put("Alg.Alias.Cipher.1.2.840.113549.3.4", "ARC4");
-        put("Alg.Alias.Cipher.ARCFOUR", "ARC4");
-        put("Alg.Alias.Cipher.RC4", "ARC4");
-        // BEGIN android-removed
-        // put("Cipher.SALSA20", "org.bouncycastle.jce.provider.JCEStreamCipher$Salsa20");
-        // put("Cipher.HC128", "org.bouncycastle.jce.provider.JCEStreamCipher$HC128");
-        // put("Cipher.HC256", "org.bouncycastle.jce.provider.JCEStreamCipher$HC256");
-        // put("Cipher.VMPC", "org.bouncycastle.jce.provider.JCEStreamCipher$VMPC");
-        // put("Cipher.VMPC-KSA3", "org.bouncycastle.jce.provider.JCEStreamCipher$VMPCKSA3");
-        // put("Cipher.RC5", "org.bouncycastle.jce.provider.JCEBlockCipher$RC5");
+        //
         // put("Cipher.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2CBC");
-        // put("Alg.Alias.Cipher.RC5-32", "RC5");
-        // put("Cipher.RC5-64", "org.bouncycastle.jce.provider.JCEBlockCipher$RC564");
-        // put("Cipher.RC6", "org.bouncycastle.jce.provider.JCEBlockCipher$RC6");
-        // put("Cipher.RIJNDAEL", "org.bouncycastle.jce.provider.JCEBlockCipher$Rijndael");
-        // put("Cipher.DESEDERFC3211WRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$RFC3211DESedeWrap");
-        // put("Cipher.SERPENT", "org.bouncycastle.jce.provider.JCEBlockCipher$Serpent");
         // END android-removed
-
-
-        // BEGIN android-removed
-        // put("Cipher.CAST6", "org.bouncycastle.jce.provider.JCEBlockCipher$CAST6");
-        // END android-removed
+        
         put("Alg.Alias.Cipher.PBEWithSHAAnd3KeyTripleDES",  "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
         
         // BEGIN android-removed
@@ -345,9 +313,6 @@
         // put("Alg.Alias.Cipher.GOST", "GOST28147");
         // put("Alg.Alias.Cipher.GOST-28147", "GOST28147");
         // put("Cipher." + CryptoProObjectIdentifiers.gostR28147_cbc, "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147cbc");
-        //
-        // put("Cipher.TEA", "org.bouncycastle.jce.provider.JCEBlockCipher$TEA");
-        // put("Cipher.XTEA", "org.bouncycastle.jce.provider.JCEBlockCipher$XTEA");
         // END android-removed
 
         put("Cipher.RSA", "org.bouncycastle.jce.provider.JCERSACipher$NoPadding");
@@ -363,9 +328,7 @@
         // put("Cipher.RSA/OAEP", "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
         // put("Cipher." + PKCSObjectIdentifiers.id_RSAES_OAEP, "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
         // put("Cipher.RSA/ISO9796-1", "org.bouncycastle.jce.provider.JCERSACipher$ISO9796d1Padding");
-        // END android-removed
-
-        // BEGIN android-removed
+        //
         // put("Cipher.ECIES", "org.bouncycastle.jce.provider.JCEIESCipher$ECIES");
         // put("Cipher.BrokenECIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenECIES");
         // put("Cipher.IES", "org.bouncycastle.jce.provider.JCEIESCipher$IES");
@@ -380,9 +343,7 @@
         // put("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
         // put("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
         // put("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
-        // END android-removed
-        
-        // BEGIN android-removed
+        //
         // put("Alg.Alias.Cipher.ELGAMAL/ECB/PKCS1PADDING", "ELGAMAL/PKCS1");
         // put("Alg.Alias.Cipher.ELGAMAL/NONE/PKCS1PADDING", "ELGAMAL/PKCS1");
         // put("Alg.Alias.Cipher.ELGAMAL/NONE/NOPADDING", "ELGAMAL");
@@ -412,12 +373,14 @@
         put("Cipher.PBEWITHSHAAND128BITRC4", "org.bouncycastle.jce.provider.JCEStreamCipher$PBEWithSHAAnd128BitRC4");
         put("Cipher.PBEWITHSHAAND40BITRC4", "org.bouncycastle.jce.provider.JCEStreamCipher$PBEWithSHAAnd40BitRC4");
 
+        // BEGIN android-changed
         put("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
         put("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
         put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC2-CBC", "PBEWITHSHAAND128BITRC2-CBC");
         put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC");
         put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC4", "PBEWITHSHAAND128BITRC4");
         put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC4", "PBEWITHSHAAND40BITRC4");
+        // END android-changed
 
         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
         put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
@@ -449,7 +412,14 @@
         put("Cipher.PBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndTwofish");
         // BEGIN android-removed
         // put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish");
+        //
+        // put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
+        // put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
         // END android-removed
+        put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
+        put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDDES");
+        put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
+        put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
 
         put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.1", "PBEWITHSHAAND128BITRC4");
         put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.2", "PBEWITHSHAAND40BITRC4");
@@ -463,44 +433,10 @@
         //
         put("KeyGenerator.DES", "org.bouncycastle.jce.provider.JCEKeyGenerator$DES");
         put("Alg.Alias.KeyGenerator." + OIWObjectIdentifiers.desCBC, "DES");
-        put("KeyGenerator.DESEDE", "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede");
-        // BEGIN android-removed
-        // put("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede3");
-        // put("KeyGenerator.DESEDEWRAP", "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede");
-        // put("KeyGenerator.SKIPJACK", "org.bouncycastle.jce.provider.JCEKeyGenerator$Skipjack");
-        // END android-removed
-        put("KeyGenerator.BLOWFISH", "org.bouncycastle.jce.provider.JCEKeyGenerator$Blowfish");
-        put("Alg.Alias.KeyGenerator.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
-        // BEGIN android-removed
-        // put("KeyGenerator.TWOFISH", "org.bouncycastle.jce.provider.JCEKeyGenerator$Twofish");
-        // put("KeyGenerator.RC2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
-        // put("KeyGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
-        // END android-removed
-        put("KeyGenerator.RC4", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC4");
-        put("Alg.Alias.KeyGenerator.ARC4", "RC4");
-        // BEGIN android-added
-        put("Alg.Alias.KeyGenerator.ARCFOUR", "RC4");
-        // END android-added
-        // BEGIN android-removed
-        // put("Alg.Alias.KeyGenerator.1.2.840.113549.3.4", "RC4");
-        // put("KeyGenerator.RC5", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC5");
-        // put("Alg.Alias.KeyGenerator.RC5-32", "RC5");
-        // put("KeyGenerator.RC5-64", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC564");
-        // put("KeyGenerator.RC6", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC6");
-        // put("KeyGenerator.RIJNDAEL", "org.bouncycastle.jce.provider.JCEKeyGenerator$Rijndael");
-        //
-        // put("KeyGenerator.SERPENT", "org.bouncycastle.jce.provider.JCEKeyGenerator$Serpent");
-        // put("KeyGenerator.SALSA20", "org.bouncycastle.jce.provider.JCEKeyGenerator$Salsa20");
-        // put("KeyGenerator.HC128", "org.bouncycastle.jce.provider.JCEKeyGenerator$HC128");
-        // put("KeyGenerator.HC256", "org.bouncycastle.jce.provider.JCEKeyGenerator$HC256");
-        // put("KeyGenerator.VMPC", "org.bouncycastle.jce.provider.JCEKeyGenerator$VMPC");
-        // put("KeyGenerator.VMPC-KSA3", "org.bouncycastle.jce.provider.JCEKeyGenerator$VMPCKSA3");
-        // END android-removed
 
         // BEGIN android-removed
-        // put("KeyGenerator.CAST6", "org.bouncycastle.jce.provider.JCEKeyGenerator$CAST6");
-        // put("KeyGenerator.TEA", "org.bouncycastle.jce.provider.JCEKeyGenerator$TEA");
-        // put("KeyGenerator.XTEA", "org.bouncycastle.jce.provider.JCEKeyGenerator$XTEA");
+        // put("KeyGenerator.RC2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
+        // put("KeyGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
         //
         // put("KeyGenerator.GOST28147", "org.bouncycastle.jce.provider.JCEKeyGenerator$GOST28147");
         // put("Alg.Alias.KeyGenerator.GOST", "GOST28147");
@@ -564,25 +500,26 @@
         // BEGIN android-removed
         // put("AlgorithmParameters.RC2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
         // put("AlgorithmParameters.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
-        // put("AlgorithmParameters.RC5", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-        // put("AlgorithmParameters.RC6", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
         // END android-removed
-        put("AlgorithmParameters.BLOWFISH", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-        put("Alg.Alias.AlgorithmParameters.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
-        // BEGIN android-removed
-        // put("AlgorithmParameters.TWOFISH", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-        // put("AlgorithmParameters.SKIPJACK", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-        // put("AlgorithmParameters.RIJNDAEL", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
-        // END android-removed
-
         
         //
         // secret key factories.
         //
         put("SecretKeyFactory.DES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$DES");
-        put("SecretKeyFactory.DESEDE", "org.bouncycastle.jce.provider.JCESecretKeyFactory$DESede");
         // BEGIN android-removed
         // put("SecretKeyFactory.PBEWITHMD2ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndDES");
+        // END android-removed
+
+        // BEGIN android-removed
+        // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
+        // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
+        // END android-removed
+        put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
+        put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDDES");
+        put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
+        put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
+
+        // BEGIN android-removed
         // put("SecretKeyFactory.PBEWITHMD2ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndRC2");
         // END android-removed
         put("SecretKeyFactory.PBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5AndDES");
@@ -709,11 +646,11 @@
 
                 if (loader != null)
                 {
-                    clazz = loader.loadClass(packageName + names[i] + "Mappings");
+                    clazz = loader.loadClass(packageName + names[i] + "$Mappings");
                 }
                 else
                 {
-                    clazz = Class.forName(packageName + names[i] + "Mappings");
+                    clazz = Class.forName(packageName + names[i] + "$Mappings");
                 }
             }
             catch (ClassNotFoundException e)
@@ -730,7 +667,7 @@
                 catch (Exception e)
                 {   // this should never ever happen!!
                     throw new InternalError("cannot create instance of "
-                        + packageName + names[i] + "Mappings : " + e);
+                        + packageName + names[i] + "$Mappings : " + e);
                 }
             }
         }
@@ -762,49 +699,23 @@
         // put("Mac.DESMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$DESCFB8");
         // put("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
         //
-        // put("Mac.DESEDEMAC", "org.bouncycastle.jce.provider.JCEMac$DESede");
-        // put("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
-        // put("Mac.DESEDEMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$DESedeCFB8");
-        // put("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
-        //
         // put("Mac.DESWITHISO9797", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
         // put("Alg.Alias.Mac.DESISO9797MAC", "DESWITHISO9797");
         //
-        // put("Mac.DESEDEMAC64", "org.bouncycastle.jce.provider.JCEMac$DESede64");
-        // put("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
-        //
-        // put("Mac.DESEDEMAC64WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.JCEMac$DESede64with7816d4");
-        // put("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-        // put("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-        // put("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
-        //
         // put("Mac.ISO9797ALG3MAC", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
         // put("Alg.Alias.Mac.ISO9797ALG3", "ISO9797ALG3MAC");
         // put("Mac.ISO9797ALG3WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3with7816d4");
         // put("Alg.Alias.Mac.ISO9797ALG3MACWITHISO7816-4PADDING", "ISO9797ALG3WITHISO7816-4PADDING");
         //
-        // put("Mac.SKIPJACKMAC", "org.bouncycastle.jce.provider.JCEMac$Skipjack");
-        // put("Alg.Alias.Mac.SKIPJACK", "SKIPJACKMAC");
-        // put("Mac.SKIPJACKMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$SkipjackCFB8");
-        // put("Alg.Alias.Mac.SKIPJACK/CFB8", "SKIPJACKMAC/CFB8");
-        //
         // put("Mac.RC2MAC", "org.bouncycastle.jce.provider.JCEMac$RC2");
         // put("Alg.Alias.Mac.RC2", "RC2MAC");
         // put("Mac.RC2MAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$RC2CFB8");
         // put("Alg.Alias.Mac.RC2/CFB8", "RC2MAC/CFB8");
         //
-        // put("Mac.RC5MAC", "org.bouncycastle.jce.provider.JCEMac$RC5");
-        // put("Alg.Alias.Mac.RC5", "RC5MAC");
-        // put("Mac.RC5MAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$RC5CFB8");
-        // put("Alg.Alias.Mac.RC5/CFB8", "RC5MAC/CFB8");
         //
         // put("Mac.GOST28147MAC", "org.bouncycastle.jce.provider.JCEMac$GOST28147");
         // put("Alg.Alias.Mac.GOST28147", "GOST28147MAC");
         //
-        // put("Mac.VMPCMAC", "org.bouncycastle.jce.provider.JCEMac$VMPC");
-        // put("Alg.Alias.Mac.VMPC", "VMPCMAC");
-        // put("Alg.Alias.Mac.VMPC-MAC", "VMPCMAC");
-        //
         // put("Mac.OLDHMACSHA384", "org.bouncycastle.jce.provider.JCEMac$OldSHA384");
         //
         // put("Mac.OLDHMACSHA512", "org.bouncycastle.jce.provider.JCEMac$OldSHA512");
diff --git a/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java b/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
index 338680a..f9dbe89 100644
--- a/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
+++ b/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
@@ -36,10 +36,6 @@
 
 import javax.security.auth.x500.X500Principal;
 
-// BEGIN android-added
-import org.apache.harmony.xnet.provider.jsse.IndexedPKIXParameters;
-
-// END android-added
 import org.bouncycastle.asn1.ASN1InputStream;
 import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1OctetString;
@@ -82,6 +78,8 @@
 
 public class CertPathValidatorUtilities
 {
+    protected static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
     protected static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
     protected static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
     protected static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
@@ -119,38 +117,13 @@
         "privilegeWithdrawn",
         "aACompromise" };
     
-    // BEGIN android-removed
-    // /**
-    //  * 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.
-    //  *
-    //  * @exception 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);
-    // }
-    // END android-removed
-    
-    // BEGIN android-changed
     /**
      * Search the given Set of TrustAnchor's for one that is the
-     * issuer of the given X509 certificate.
+     * issuer of the given X509 certificate. Uses the default provider
+     * for signature verification.
      *
      * @param cert the X509 certificate
-     * @param params used to find the trust anchors and signature provider
+     * @param trustAnchors a Set of TrustAnchor's
      *
      * @return the <code>TrustAnchor</code> object if found or
      * <code>null</code> if not.
@@ -161,21 +134,35 @@
      */
     protected static TrustAnchor findTrustAnchor(
         X509Certificate cert,
-        PKIXParameters  params)
+        Set             trustAnchors)
             throws AnnotatedException
-    // END android-changed
     {
-        // BEGIN android-changed
-        // If we have a trust anchor index, use it.
-        if (params instanceof IndexedPKIXParameters) {
-            try {
-                IndexedPKIXParameters indexed = (IndexedPKIXParameters) params;
-                return indexed.findTrustAnchor(cert);
-            } catch (CertPathValidatorException e) {
-                throw new AnnotatedException(e.getMessage(), e);
-            }
-        }
-        // END android-changed
+        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.
+     *
+     * @exception 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;
@@ -192,9 +179,7 @@
             throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
         }
 
-        // BEGIN android-changed
-        Iterator iter = params.getTrustAnchors().iterator();
-        // END android-changed
+        Iterator iter = trustAnchors.iterator();
         while (iter.hasNext() && trust == null)
         {
             trust = (TrustAnchor) iter.next();
@@ -238,9 +223,7 @@
             {
                 try
                 {
-                    // BEGIN android-changed
-                    verifyX509Certificate(cert, trustPublicKey, params.getSigProvider());
-                    // END android-changed
+                    verifyX509Certificate(cert, trustPublicKey, sigProvider);
                 }
                 catch (Exception ex)
                 {
@@ -392,69 +375,6 @@
     
     // crl checking
 
-    /**
-     * Return a Collection of all CRLs found in the X509Store's that are
-     * matching the crlSelect criteriums.
-     *
-     * @param crlSelect a {@link X509CRLStoreSelector} object that will be used
-     *            to select the CRLs
-     * @param crlStores a List containing only
-     *            {@link org.bouncycastle.x509.X509Store  X509Store} objects.
-     *            These are used to search for CRLs
-     *
-     * @return a Collection of all found {@link X509CRL X509CRL} objects. May be
-     *         empty but never <code>null</code>.
-     */
-    protected static final Collection findCRLs(X509CRLStoreSelector 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();
-
-            if (obj instanceof X509Store)
-            {
-                X509Store store = (X509Store)obj;
-
-                try
-                {
-                    crls.addAll(store.getMatches(crlSelect));
-                    foundValidStore = true;
-                }
-                catch (StoreException e)
-                {
-                    lastException = new AnnotatedException(
-                        "Exception searching in X.509 CRL store.", e);
-                }
-            }
-            else
-            {
-                CertStore store = (CertStore)obj;
-
-                try
-                {
-                    crls.addAll(store.getCRLs(crlSelect));
-                    foundValidStore = true;
-                }
-                catch (CertStoreException e)
-                {
-                    lastException = new AnnotatedException(
-                        "Exception searching in X.509 CRL store.", e);
-                }
-            }
-        }
-        if (!foundValidStore && lastException != null)
-        {
-            throw lastException;
-        }
-        return crls;
-    }
 
     //
     // policy checking
@@ -772,13 +692,13 @@
                 //     X509LDAPCertStoreParameters params = new X509LDAPCertStoreParameters.Builder(
                 //         url, base).build();
                 //     pkixParams.addAdditionalStore(X509Store.getInstance(
-                //         "CERTIFICATE/LDAP", params, "BC"));
+                //         "CERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
                 //     pkixParams.addAdditionalStore(X509Store.getInstance(
-                //         "CRL/LDAP", params, "BC"));
+                //         "CRL/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
                 //     pkixParams.addAdditionalStore(X509Store.getInstance(
-                //         "ATTRIBUTECERTIFICATE/LDAP", params, "BC"));
+                //         "ATTRIBUTECERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
                 //     pkixParams.addAdditionalStore(X509Store.getInstance(
-                //         "CERTIFICATEPAIR/LDAP", params, "BC"));
+                //         "CERTIFICATEPAIR/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
                 // }
                 // END android-removed
             }
@@ -1146,15 +1066,6 @@
 
         X509CRLStoreSelector deltaSelect = new X509CRLStoreSelector();
 
-        if (paramsPKIX.getDate() != null)
-        {
-            deltaSelect.setDateAndTime(paramsPKIX.getDate());
-        }
-        else
-        {
-            deltaSelect.setDateAndTime(currentDate);
-        }
-
         // 5.2.4 (a)
         try
         {
@@ -1206,18 +1117,8 @@
         // 5.2.4 (c)
         deltaSelect.setMaxBaseCRLNumber(completeCRLNumber);
 
-        Set temp = new HashSet();
         // find delta CRLs
-        try
-        {
-            temp.addAll(CertPathValidatorUtilities.findCRLs(deltaSelect, paramsPKIX.getAdditionalStores()));
-            temp.addAll(CertPathValidatorUtilities.findCRLs(deltaSelect, paramsPKIX.getStores()));
-            temp.addAll(CertPathValidatorUtilities.findCRLs(deltaSelect, paramsPKIX.getCertStores()));
-        }
-        catch (AnnotatedException e)
-        {
-            throw new AnnotatedException("Could not search for delta CRLs.", e);
-        }
+        Set temp = CRL_UTIL.findCRLs(deltaSelect, paramsPKIX, currentDate);
 
         Set result = new HashSet();
 
@@ -1288,28 +1189,12 @@
             crlselect.setAttrCertificateChecking((X509AttributeCertificate)cert);
         }
 
-        if (paramsPKIX.getDate() != null)
-        {
-            crlselect.setDateAndTime(paramsPKIX.getDate());
-        }
-        else
-        {
-            crlselect.setDateAndTime(currentDate);
-        }
+
 
         crlselect.setCompleteCRLEnabled(true);
 
-        Set crls = new HashSet();
-        try
-        {
-            crls.addAll(CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getStores()));
-            crls.addAll(CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getAdditionalStores()));
-            crls.addAll(CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getCertStores()));
-        }
-        catch (AnnotatedException e)
-        {
-            throw new AnnotatedException("Could not search for CRLs.", e);
-        }
+        Set crls = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
+
         if (crls.isEmpty())
         {
             if (cert instanceof X509AttributeCertificate)
@@ -1446,7 +1331,7 @@
                 dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
             try
             {
-                KeyFactory keyFactory = KeyFactory.getInstance("DSA", "BC");
+                KeyFactory keyFactory = KeyFactory.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
                 return keyFactory.generatePublic(dsaPubKeySpec);
             }
             catch (Exception exception)
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java b/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
index 5ba4cc2..1b48aec 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
@@ -1,43 +1,48 @@
 package org.bouncycastle.jce.provider;
 
+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.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+// BEGIN android-removed
+// import javax.crypto.spec.RC2ParameterSpec;
+// import javax.crypto.spec.RC5ParameterSpec;
+// END android-removed
+
 import org.bouncycastle.crypto.BlockCipher;
 import org.bouncycastle.crypto.BufferedBlockCipher;
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.DataLengthException;
 import org.bouncycastle.crypto.InvalidCipherTextException;
 import org.bouncycastle.crypto.engines.AESFastEngine;
-import org.bouncycastle.crypto.engines.BlowfishEngine;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.engines.CAST5Engine;
-// import org.bouncycastle.crypto.engines.CAST6Engine;
-// END android-removed
 import org.bouncycastle.crypto.engines.DESEngine;
 import org.bouncycastle.crypto.engines.DESedeEngine;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.engines.GOST28147Engine;
 // END android-removed
 import org.bouncycastle.crypto.engines.RC2Engine;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.engines.RC532Engine;
-// import org.bouncycastle.crypto.engines.RC564Engine;
-// END android-removed
-// import org.bouncycastle.crypto.engines.RC6Engine;
-// import org.bouncycastle.crypto.engines.RijndaelEngine;
-// import org.bouncycastle.crypto.engines.SEEDEngine;
-// import org.bouncycastle.crypto.engines.SerpentEngine;
-// import org.bouncycastle.crypto.engines.SkipjackEngine;
-// import org.bouncycastle.crypto.engines.TEAEngine;
-// END android-removed
 import org.bouncycastle.crypto.engines.TwofishEngine;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.engines.XTEAEngine;
-// END android-removed
 import org.bouncycastle.crypto.modes.AEADBlockCipher;
 import org.bouncycastle.crypto.modes.CBCBlockCipher;
 import org.bouncycastle.crypto.modes.CCMBlockCipher;
 import org.bouncycastle.crypto.modes.CFBBlockCipher;
 import org.bouncycastle.crypto.modes.CTSBlockCipher;
-import org.bouncycastle.crypto.modes.EAXBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.EAXBlockCipher;
+// END android-removed
 import org.bouncycastle.crypto.modes.GCMBlockCipher;
 import org.bouncycastle.crypto.modes.GOFBBlockCipher;
 import org.bouncycastle.crypto.modes.OFBBlockCipher;
@@ -64,27 +69,6 @@
 // END android-removed
 import org.bouncycastle.util.Strings;
 
-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.spec.IvParameterSpec;
-import javax.crypto.spec.PBEParameterSpec;
-// BEGIN android-removed
-// import javax.crypto.spec.RC2ParameterSpec;
-// import javax.crypto.spec.RC5ParameterSpec;
-// END android-removed
-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;
-
 public class JCEBlockCipher extends WrapCipherSpi
     implements PBE
 {
@@ -175,7 +159,7 @@
             {
                 try
                 {
-                    engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, "BC");
+                    engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
                     engineParams.init(pbeSpec);
                 }
                 catch (Exception e)
@@ -194,7 +178,7 @@
 
                 try
                 {
-                    engineParams = AlgorithmParameters.getInstance(name, "BC");
+                    engineParams = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME);
                     engineParams.init(ivParam.getIV());
                 }
                 catch (Exception e)
@@ -304,11 +288,13 @@
             ivLength = baseEngine.getBlockSize();
             cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
         }
-        else if (modeName.startsWith("EAX"))
-        {
-            ivLength = baseEngine.getBlockSize();
-            cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
-        }
+        // BEGIN android-removed
+        // else if (modeName.startsWith("EAX"))
+        // {
+        //     ivLength = baseEngine.getBlockSize();
+        //     cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
+        // }
+        // END android-removed
         else if (modeName.startsWith("GCM"))
         {
             ivLength = baseEngine.getBlockSize();
@@ -801,32 +787,6 @@
     //         super(new CBCBlockCipher(new DESEngine()), 64);
     //     }
     // }
-    // END android-removed
-
-    /**
-     * DESede
-     */
-    static public class DESede
-        extends JCEBlockCipher
-    {
-        public DESede()
-        {
-            super(new DESedeEngine());
-        }
-    }
-
-    // BEGIN android-removed
-    // /**
-    //  * DESedeCBC
-    //  */
-    // static public class DESedeCBC
-    //     extends JCEBlockCipher
-    // {
-    //     public DESedeCBC()
-    //     {
-    //         super(new CBCBlockCipher(new DESedeEngine()), 64);
-    //     }
-    // }
     //
     // /**
     //  *  GOST28147
@@ -839,7 +799,7 @@
     //         super(new GOST28147Engine());
     //     }
     // }
-    //    
+    //
     // static public class GOST28147cbc
     //     extends JCEBlockCipher
     // {
@@ -850,56 +810,6 @@
     // }
     //
     // /**
-    //  * SKIPJACK
-    //  */
-    // static public class Skipjack
-    //     extends JCEBlockCipher
-    // {
-    //     public Skipjack()
-    //     {
-    //         super(new SkipjackEngine());
-    //     }
-    // }
-    // END android-removed
-    
-    /**
-     * Blowfish
-     */
-    static public class Blowfish
-        extends JCEBlockCipher
-    {
-        public Blowfish()
-        {
-            super(new BlowfishEngine());
-        }
-    }
-    
-    // BEGIN android-removed
-    // /**
-    //  * Blowfish CBC
-    //  */
-    // static public class BlowfishCBC
-    //     extends JCEBlockCipher
-    // {
-    //     public BlowfishCBC()
-    //     {
-    //         super(new CBCBlockCipher(new BlowfishEngine()), 64);
-    //     }
-    // }
-    //
-    // /**
-    //  * Twofish
-    //  */
-    // static public class Twofish
-    //     extends JCEBlockCipher
-    // {
-    //     public Twofish()
-    //     {
-    //         super(new TwofishEngine());
-    //     }
-    // }
-    //
-    // /**
     //  * RC2
     //  */
     // static public class RC2
@@ -922,188 +832,6 @@
     //         super(new CBCBlockCipher(new RC2Engine()), 64);
     //     }
     // }
-    //
-    // /**
-    //  * RC5
-    //  */
-    // static public class RC5
-    //     extends JCEBlockCipher
-    // {
-    //     public RC5()
-    //     {
-    //         super(new RC532Engine());
-    //     }
-    // }
-    //
-    // /**
-    //  * RC564
-    //  */
-    // static public class RC564
-    //     extends JCEBlockCipher
-    // {
-    //     public RC564()
-    //     {
-    //         super(new RC564Engine());
-    //     }
-    // }
-    //
-    // /**
-    //  * RC6
-    //  */
-    // static public class RC6
-    //     extends JCEBlockCipher
-    // {
-    //     public RC6()
-    //     {
-    //         super(new RC6Engine());
-    //     }
-    // }
-    //
-    // /**
-    //  * AES
-    //  */
-    // static public class AES
-    //     extends JCEBlockCipher
-    // {
-    //     public AES()
-    //     {
-    //         super(new AESFastEngine());
-    //     }
-    // }
-    //
-    // /**
-    //  * AESCBC
-    //  */
-    // static public class AESCBC
-    //     extends JCEBlockCipher
-    // {
-    //     public AESCBC()
-    //     {
-    //         super(new CBCBlockCipher(new AESFastEngine()), 128);
-    //     }
-    // }
-    //
-    // /**
-    //  * AESCFB
-    //  */
-    // static public class AESCFB
-    //     extends JCEBlockCipher
-    // {
-    //     public AESCFB()
-    //     {
-    //         super(new CFBBlockCipher(new AESFastEngine(), 128), 128);
-    //     }
-    // }
-    //
-    // /**
-    //  * AESOFB
-    //  */
-    // static public class AESOFB
-    //     extends JCEBlockCipher
-    // {
-    //     public AESOFB()
-    //     {
-    //         super(new OFBBlockCipher(new AESFastEngine(), 128), 128);
-    //     }
-    // }
-    //
-    // /**
-    //  * Rijndael
-    //  */
-    // static public class Rijndael
-    //     extends JCEBlockCipher
-    // {
-    //     public Rijndael()
-    //     {
-    //         super(new RijndaelEngine());
-    //     }
-    // }
-    //
-    // /**
-    //  * Serpent
-    //  */
-    // static public class Serpent
-    //     extends JCEBlockCipher
-    // {
-    //     public Serpent()
-    //     {
-    //         super(new SerpentEngine());
-    //     }
-    // }
-    //
-    //
-    //
-    // /**
-    //  * CAST5
-    //  */
-    // static public class CAST5
-    //     extends JCEBlockCipher
-    // {
-    //     public CAST5()
-    //     {
-    //         super(new CAST5Engine());
-    //     }
-    // }
-    //
-    // /**
-    //  * CAST5 CBC
-    //  */
-    // static public class CAST5CBC
-    //     extends JCEBlockCipher
-    // {
-    //     public CAST5CBC()
-    //     {
-    //         super(new CBCBlockCipher(new CAST5Engine()), 64);
-    //     }
-    // }
-    //
-    // /**
-    //  * CAST6
-    //  */
-    // static public class CAST6
-    //     extends JCEBlockCipher
-    // {
-    //     public CAST6()
-    //     {
-    //         super(new CAST6Engine());
-    //     }
-    // }
-    // 
-    // /**
-    //  * TEA
-    //  */
-    // static public class TEA
-    //     extends JCEBlockCipher
-    // {
-    //     public TEA()
-    //     {
-    //         super(new TEAEngine());
-    //     }
-    // }
-    //
-    // /**
-    //  * XTEA
-    //  */
-    // static public class XTEA
-    //     extends JCEBlockCipher
-    // {
-    //     public XTEA()
-    //     {
-    //         super(new XTEAEngine());
-    //     }
-    // }
-    // 
-    // /**
-    //  * SEED
-    //  */
-    // static public class SEED
-    //     extends JCEBlockCipher
-    // {
-    //     public SEED()
-    //     {
-    //         super(new SEEDEngine());
-    //     }
-    // }
     // END android-removed
 
     /**
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java b/src/main/java/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java
index 75fbdf7..ef8f76a 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java
@@ -1,7 +1,12 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.crypto.params.DESParameters;
-import org.bouncycastle.util.Strings;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
 
 import javax.crypto.KeyAgreementSpi;
 import javax.crypto.SecretKey;
@@ -10,13 +15,9 @@
 import javax.crypto.interfaces.DHPublicKey;
 import javax.crypto.spec.DHParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
-import java.math.BigInteger;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.Hashtable;
+
+import org.bouncycastle.crypto.params.DESParameters;
+import org.bouncycastle.util.Strings;
 
 /**
  * Diffie-Hellman key agreement. There's actually a better way of doing this
@@ -31,8 +32,6 @@
     private BigInteger      g;
     private BigInteger      result;
 
-    private SecureRandom    random;
-
     private static final Hashtable algorithms = new Hashtable();
 
     static
@@ -41,11 +40,13 @@
         Integer i64 = Integer.valueOf(64);
         Integer i192 = Integer.valueOf(192);
         Integer i128 = Integer.valueOf(128);
+        Integer i256 = Integer.valueOf(256);
         // END android-changed
 
         algorithms.put("DES", i64);
         algorithms.put("DESEDE", i192);
         algorithms.put("BLOWFISH", i128);
+        algorithms.put("AES", i256);
     }
 
     private byte[] bigIntToBytes(
@@ -172,8 +173,6 @@
         }
         DHPrivateKey    privKey = (DHPrivateKey)key;
 
-        this.random = random;
-
         if (params != null)
         {
             if (!(params instanceof DHParameterSpec))
@@ -206,7 +205,6 @@
 
         DHPrivateKey    privKey = (DHPrivateKey)key;
 
-        this.random = random;
         this.p = privKey.getParams().getP();
         this.g = privKey.getParams().getG();
         this.x = this.result = privKey.getX();
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java b/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
index 3da31fb..fc38481 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
@@ -1,5 +1,15 @@
 package 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 org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERInteger;
@@ -8,18 +18,11 @@
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x9.DHDomainParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
 import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
 
-import javax.crypto.interfaces.DHPrivateKey;
-import javax.crypto.spec.DHParameterSpec;
-import javax.crypto.spec.DHPrivateKeySpec;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.math.BigInteger;
-import java.util.Enumeration;
-
 public class JCEDHPrivateKey
     implements DHPrivateKey, PKCS12BagAttributeCarrier
 {
@@ -27,7 +30,8 @@
     
     BigInteger      x;
 
-    DHParameterSpec dhSpec;
+    private DHParameterSpec dhSpec;
+    private PrivateKeyInfo  info;
 
     private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
 
@@ -52,17 +56,35 @@
     JCEDHPrivateKey(
         PrivateKeyInfo  info)
     {
-        DHParameter     params = new DHParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
+        ASN1Sequence    seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters());
         DERInteger      derX = (DERInteger)info.getPrivateKey();
+        DERObjectIdentifier id = info.getAlgorithmId().getObjectId();
 
+        this.info = info;
         this.x = derX.getValue();
-        if (params.getL() != null)
+
+        if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement))
         {
-            this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+            DHParameter params = new DHParameter(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
         {
-            this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+            throw new IllegalArgumentException("unknown algorithm type: " + id);
         }
     }
 
@@ -96,6 +118,11 @@
      */
     public byte[] getEncoded()
     {
+        if (info != null)
+        {
+            return info.getDEREncoded();
+        }
+        
         PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).getDERObject()), new DERInteger(getX()));
 
         return info.getDEREncoded();
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java b/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java
index e343af3..942e3bf 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java
@@ -1,21 +1,25 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.pkcs.DHParameter;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import org.bouncycastle.crypto.params.DHPublicKeyParameters;
-
-import javax.crypto.interfaces.DHPublicKey;
-import javax.crypto.spec.DHParameterSpec;
-import javax.crypto.spec.DHPublicKeySpec;
 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 org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.DHDomainParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+
 public class JCEDHPublicKey
     implements DHPublicKey
 {
@@ -23,7 +27,8 @@
     
     private BigInteger              y;
     private DHParameterSpec         dhSpec;
-
+    private SubjectPublicKeyInfo    info;
+    
     JCEDHPublicKey(
         DHPublicKeySpec    spec)
     {
@@ -56,9 +61,9 @@
     JCEDHPublicKey(
         SubjectPublicKeyInfo    info)
     {
-        DHParameter             params = new DHParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
-        DERInteger              derY = null;
+        this.info = info;
 
+        DERInteger              derY;
         try
         {
             derY = (DERInteger)info.getPublicKey();
@@ -69,13 +74,33 @@
         }
 
         this.y = derY.getValue();
-        if (params.getL() != null)
+
+        ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters());
+        DERObjectIdentifier id = info.getAlgorithmId().getObjectId();
+
+        // we need the PKCS check to handle older keys marked with the X9 oid.
+        if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement) || isPKCSParam(seq))
         {
-            this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+            DHParameter             params = new DHParameter(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
         {
-            this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+            throw new IllegalArgumentException("unknown algorithm type: " + id);
         }
     }
 
@@ -91,7 +116,12 @@
 
     public byte[] getEncoded()
     {
-        SubjectPublicKeyInfo    info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.dhpublicnumber, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).getDERObject()), new DERInteger(y));
+        if (info != null)
+        {
+            return info.getDEREncoded();
+        }
+
+        SubjectPublicKeyInfo    info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).getDERObject()), new DERInteger(y));
 
         return info.getDEREncoded();
     }
@@ -106,6 +136,29 @@
         return y;
     }
 
+    private boolean isPKCSParam(ASN1Sequence seq)
+    {
+        if (seq.size() == 2)
+        {
+            return true;
+        }
+        
+        if (seq.size() > 3)
+        {
+            return false;
+        }
+
+        DERInteger l = DERInteger.getInstance(seq.getObjectAt(2));
+        DERInteger p = DERInteger.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
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java b/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
index 4a12124..3b3f318 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
@@ -292,7 +292,10 @@
         if (ecSpec instanceof ECNamedCurveSpec)
         {
             DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
-            
+            if (curveOid == null)  // guess it's the OID
+            {
+                curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+            }
             params = new X962Parameters(curveOid);
         }
         else if (ecSpec == null)
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java b/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
index 92b478a..00277ac 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
@@ -372,7 +372,10 @@
             if (ecSpec instanceof ECNamedCurveSpec)
             {
                 DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
-                
+                if (curveOid == null)
+                {
+                    curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+                }
                 params = new X962Parameters(curveOid);
             }
             else if (ecSpec == null)
@@ -410,6 +413,7 @@
         {
             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++)
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java b/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java
index 7515013..6373557 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java
@@ -1,18 +1,18 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.crypto.CipherKeyGenerator;
-import org.bouncycastle.crypto.KeyGenerationParameters;
-import org.bouncycastle.crypto.generators.DESKeyGenerator;
-import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
-
-import javax.crypto.KeyGeneratorSpi;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
 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 org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.generators.DESKeyGenerator;
+
 public class JCEKeyGenerator
     extends KeyGeneratorSpi
 {
@@ -98,110 +98,8 @@
         }
     }
 
-    /**
-     * 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.
-     */
-    public static class DESede
-        extends JCEKeyGenerator
-    {
-        private boolean     keySizeSet = false;
-
-        public DESede()
-        {
-            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(new SecureRandom(), 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 (SecretKey)(new SecretKeySpec(k, algName));
-            }
-            else
-            {
-                return (SecretKey)(new SecretKeySpec(engine.generateKey(), algName));
-            }
-        }
-    }
-    
     // BEGIN android-removed
     // /**
-    //  * generate a desEDE key in the a-b-c format.
-    //  */
-    // public static class DESede3
-    //     extends JCEKeyGenerator
-    // {
-    //     public DESede3()
-    //     {
-    //         super("DESede3", 192, new DESedeKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * SKIPJACK
-    //  */
-    // public static class Skipjack
-    //     extends JCEKeyGenerator
-    // {
-    //     public Skipjack()
-    //     {
-    //         super("SKIPJACK", 80, new CipherKeyGenerator());
-    //     }
-    // }
-    // END android-removed
-    
-    /**
-     * Blowfish
-     */
-    public static class Blowfish
-        extends JCEKeyGenerator
-    {
-        public Blowfish()
-        {
-            super("Blowfish", 128, new CipherKeyGenerator());
-        }
-    }
-    
-    // BEGIN android-removed
-    // /**
-    //  * Twofish
-    //  */
-    // public static class Twofish
-    //     extends JCEKeyGenerator
-    // {
-    //     public Twofish()
-    //     {
-    //         super("Twofish", 256, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
     //  * RC2
     //  */
     // public static class RC2
@@ -212,56 +110,6 @@
     //         super("RC2", 128, new CipherKeyGenerator());
     //     }
     // }
-    // END android-removed
-    
-    /**
-     * RC4
-     */
-    public static class RC4
-        extends JCEKeyGenerator
-    {
-        public RC4()
-        {
-            super("RC4", 128, new CipherKeyGenerator());
-        }
-    }
-    
-    // BEGIN android-removed
-    // /**
-    //  * RC5
-    //  */
-    // public static class RC5
-    //     extends JCEKeyGenerator
-    // {
-    //     public RC5()
-    //     {
-    //         super("RC5", 128, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * RC5
-    //  */
-    // public static class RC564
-    //     extends JCEKeyGenerator
-    // {
-    //     public RC564()
-    //     {
-    //         super("RC5-64", 256, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * RC6
-    //  */
-    // public static class RC6
-    //     extends JCEKeyGenerator
-    // {
-    //     public RC6()
-    //     {
-    //         super("RC6", 256, new CipherKeyGenerator());
-    //     }
-    // }
     //
     // /**
     //  * GOST28147
@@ -274,128 +122,6 @@
     //         super("GOST28147", 256, new CipherKeyGenerator());
     //     }
     // }
-    
-    // /**
-    //  * Rijndael
-    //  */
-    // public static class Rijndael
-    //     extends JCEKeyGenerator
-    // {
-    //     public Rijndael()
-    //     {
-    //         super("Rijndael", 192, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * Serpent
-    //  */
-    // public static class Serpent
-    //     extends JCEKeyGenerator
-    // {
-    //     public Serpent()
-    //     {
-    //         super("Serpent", 192, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    //
-    //
-    // /**
-    //  * CAST6
-    //  */
-    // public static class CAST6
-    //     extends JCEKeyGenerator
-    // {
-    //     public CAST6()
-    //     {
-    //         super("CAST6", 256, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * TEA
-    //  */
-    // public static class TEA
-    //     extends JCEKeyGenerator
-    // {
-    //     public TEA()
-    //     {
-    //         super("TEA", 128, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * XTEA
-    //  */
-    // public static class XTEA
-    //     extends JCEKeyGenerator
-    // {
-    //     public XTEA()
-    //     {
-    //         super("XTEA", 128, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * Salsa20
-    //  */
-    // public static class Salsa20
-    //     extends JCEKeyGenerator
-    // {
-    //     public Salsa20()
-    //     {
-    //         super("Salsa20", 128, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * HC128
-    //  */
-    // public static class HC128
-    //     extends JCEKeyGenerator
-    // {
-    //     public HC128()
-    //     {
-    //         super("HC128", 128, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * HC256
-    //  */
-    // public static class HC256
-    //     extends JCEKeyGenerator
-    // {
-    //     public HC256()
-    //     {
-    //         super("HC256", 256, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * VMPC
-    //  */
-    // public static class VMPC
-    //     extends JCEKeyGenerator
-    // {
-    //     public VMPC()
-    //     {
-    //         super("VMPC", 128, new CipherKeyGenerator());
-    //     }
-    // }
-    //
-    // /**
-    //  * VMPC-KSA3
-    //  */
-    // public static class VMPCKSA3
-    //     extends JCEKeyGenerator
-    // {
-    //     public VMPCKSA3()
-    //     {
-    //         super("VMPC-KSA3", 128, new CipherKeyGenerator());
-    //     }
-    // }
     // END android-removed
 
     // HMAC Related secret keys..
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEMac.java b/src/main/java/org/bouncycastle/jce/provider/JCEMac.java
index cbb2547..cf876f5 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEMac.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEMac.java
@@ -1,5 +1,14 @@
 package org.bouncycastle.jce.provider;
 
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.MacSpi;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.Mac;
 // BEGIN android-removed
@@ -22,11 +31,8 @@
 // import org.bouncycastle.crypto.digests.TigerDigest;
 // END android-removed
 import org.bouncycastle.crypto.engines.DESEngine;
-import org.bouncycastle.crypto.engines.DESedeEngine;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.engines.RC2Engine;
-// import org.bouncycastle.crypto.engines.RC532Engine;
-// import org.bouncycastle.crypto.engines.SkipjackEngine;
 // END android-removed
 import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
 // BEGIN android-removed
@@ -37,20 +43,11 @@
 // BEGIN android-removed
 // import org.bouncycastle.crypto.macs.ISO9797Alg3Mac;
 // import org.bouncycastle.crypto.macs.OldHMac;
-// import org.bouncycastle.crypto.macs.VMPCMac;
 // END android-removed
 import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
 import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithIV;
 
-import javax.crypto.MacSpi;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.PBEParameterSpec;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.spec.AlgorithmParameterSpec;
-
 public class JCEMac
     extends MacSpi implements PBE
 {
@@ -174,30 +171,6 @@
     // }
     //
     // /**
-    //  * DESede
-    //  */
-    // public static class DESede
-    //     extends JCEMac
-    // {
-    //     public DESede()
-    //     {
-    //         super(new CBCBlockCipherMac(new DESedeEngine()));
-    //     }
-    // }
-    //
-    // /**
-    //  * SKIPJACK
-    //  */
-    // public static class Skipjack
-    //     extends JCEMac
-    // {
-    //     public Skipjack()
-    //     {
-    //         super(new CBCBlockCipherMac(new SkipjackEngine()));
-    //     }
-    // }
-    //
-    // /**
     //  * RC2
     //  */
     // public static class RC2
@@ -210,18 +183,6 @@
     // }
     //
     // /**
-    //  * RC5
-    //  */
-    // public static class RC5
-    //     extends JCEMac
-    // {
-    //     public RC5()
-    //     {
-    //         super(new CBCBlockCipherMac(new RC532Engine()));
-    //     }
-    // }
-    //
-    // /**
     //  * GOST28147
     //  */
     // public static class GOST28147
@@ -233,17 +194,7 @@
     //     }
     // }
     //
-    // /**
-    //  * VMPC
-    //  */
-    // public static class VMPC
-    //     extends JCEMac
-    // {
-    //     public VMPC()
-    //     {
-    //         super(new VMPCMac());
-    //     }
-    // }
+    //
     //
     // /**
     //  * DES
@@ -258,30 +209,6 @@
     // }
     //
     // /**
-    //  * DESede
-    //  */
-    // public static class DESedeCFB8
-    //     extends JCEMac
-    // {
-    //     public DESedeCFB8()
-    //     {
-    //         super(new CFBBlockCipherMac(new DESedeEngine()));
-    //     }
-    // }
-    //
-    // /**
-    //  * SKIPJACK
-    //  */
-    // public static class SkipjackCFB8
-    //     extends JCEMac
-    // {
-    //     public SkipjackCFB8()
-    //     {
-    //         super(new CFBBlockCipherMac(new SkipjackEngine()));
-    //     }
-    // }
-    //
-    // /**
     //  * RC2CFB8
     //  */
     // public static class RC2CFB8
@@ -294,43 +221,6 @@
     // }
     //
     // /**
-    //  * RC5CFB8
-    //  */
-    // public static class RC5CFB8
-    //     extends JCEMac
-    // {
-    //     public RC5CFB8()
-    //     {
-    //         super(new CFBBlockCipherMac(new RC532Engine()));
-    //     }
-    // }
-    //
-    //
-    // /**
-    //  * DESede64
-    //  */
-    // public static class DESede64
-    //     extends JCEMac
-    // {
-    //     public DESede64()
-    //     {
-    //         super(new CBCBlockCipherMac(new DESedeEngine(), 64));
-    //     }
-    // }
-    //
-    // /**
-    //  * DESede64with7816-4Padding
-    //  */
-    // public static class DESede64with7816d4
-    //     extends JCEMac
-    // {
-    //     public DESede64with7816d4()
-    //     {
-    //         super(new CBCBlockCipherMac(new DESedeEngine(), 64, new ISO7816d4Padding()));
-    //     }
-    // }
-    //
-    // /**
     //  * DES9797Alg3with7816-4Padding
     //  */
     // public static class DES9797Alg3with7816d4
@@ -378,7 +268,7 @@
     //     }
     // }
     // END android-removed
-    
+
     /**
      * MD5 HMac
      */
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCERSACipher.java b/src/main/java/org/bouncycastle/jce/provider/JCERSACipher.java
index 877dc6b..50a0e41 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCERSACipher.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCERSACipher.java
@@ -1,23 +1,5 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.crypto.AsymmetricBlockCipher;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.encodings.ISO9796d1Encoding;
-import org.bouncycastle.crypto.encodings.OAEPEncoding;
-import org.bouncycastle.crypto.encodings.PKCS1Encoding;
-import org.bouncycastle.crypto.engines.RSABlindedEngine;
-import org.bouncycastle.crypto.params.ParametersWithRandom;
-import org.bouncycastle.util.Strings;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.spec.OAEPParameterSpec;
-import javax.crypto.spec.PSource;
 import java.io.ByteArrayOutputStream;
 import java.security.AlgorithmParameters;
 import java.security.InvalidAlgorithmParameterException;
@@ -32,6 +14,25 @@
 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.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.encodings.ISO9796d1Encoding;
+import org.bouncycastle.crypto.encodings.OAEPEncoding;
+import org.bouncycastle.crypto.encodings.PKCS1Encoding;
+import org.bouncycastle.crypto.engines.RSABlindedEngine;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.util.Strings;
+
 public class JCERSACipher extends WrapCipherSpi
 {
     private AsymmetricBlockCipher   cipher;
@@ -143,7 +144,7 @@
             {
                 try
                 {
-                    engineParams = AlgorithmParameters.getInstance("OAEP", "BC");
+                    engineParams = AlgorithmParameters.getInstance("OAEP", BouncyCastleProvider.PROVIDER_NAME);
                     engineParams.init(paramSpec);
                 }
                 catch (Exception e)
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java b/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
index 2d384d3..51f8e38 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
@@ -8,7 +8,6 @@
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactorySpi;
 import javax.crypto.spec.DESKeySpec;
-import javax.crypto.spec.DESedeKeySpec;
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.SecretKeySpec;
 
@@ -209,20 +208,19 @@
                 {
                     param = Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
                 }
-                
+
+                KeyParameter kParam;
                 if (param instanceof ParametersWithIV)
                 {
-                    KeyParameter    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
-
-                    DESParameters.setOddParity(kParam.getKey());
+                    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
                 }
                 else
                 {
-                    KeyParameter    kParam = (KeyParameter)param;
-
-                    DESParameters.setOddParity(kParam.getKey());
+                    kParam = (KeyParameter)param;
                 }
-                
+
+                DESParameters.setOddParity(kParam.getKey());
+
                 return new JCEPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
             }
             
@@ -252,75 +250,6 @@
         }
     }
 
-    static public class DESede
-        extends JCESecretKeyFactory
-    {
-        public DESede()
-        {
-            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);
-        }
-    }
-    
     // BEGIN android-removed
     // /**
     //  * PBEWithMD2AndDES
@@ -375,7 +304,7 @@
     * PBEWithSHA1AndDES
     */
    static public class PBEWithSHA1AndDES
-       extends PBEKeyFactory
+       extends DESPBEKeyFactory
    {
        public PBEWithSHA1AndDES()
        {
@@ -399,7 +328,7 @@
     * PBEWithSHAAnd3-KeyTripleDES-CBC
     */
    static public class PBEWithSHAAndDES3Key
-       extends PBEKeyFactory
+       extends DESPBEKeyFactory
    {
        public PBEWithSHAAndDES3Key()
        {
@@ -411,7 +340,7 @@
     * PBEWithSHAAnd2-KeyTripleDES-CBC
     */
    static public class PBEWithSHAAndDES2Key
-       extends PBEKeyFactory
+       extends DESPBEKeyFactory
    {
        public PBEWithSHAAndDES2Key()
        {
diff --git a/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java b/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
index 6226581..b88ccae 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
@@ -1,29 +1,11 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.crypto.BlockCipher;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.StreamBlockCipher;
-import org.bouncycastle.crypto.StreamCipher;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.engines.BlowfishEngine;
-// import org.bouncycastle.crypto.engines.DESEngine;
-// import org.bouncycastle.crypto.engines.DESedeEngine;
-// import org.bouncycastle.crypto.engines.HC128Engine;
-// import org.bouncycastle.crypto.engines.HC256Engine;
-// END android-removed
-import org.bouncycastle.crypto.engines.RC4Engine;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.engines.Salsa20Engine;
-// import org.bouncycastle.crypto.engines.SkipjackEngine;
-// import org.bouncycastle.crypto.engines.TwofishEngine;
-// import org.bouncycastle.crypto.engines.VMPCEngine;
-// import org.bouncycastle.crypto.engines.VMPCKSA3Engine;
-// END android-removed
-import org.bouncycastle.crypto.modes.CFBBlockCipher;
-import org.bouncycastle.crypto.modes.OFBBlockCipher;
-import org.bouncycastle.crypto.params.KeyParameter;
-import org.bouncycastle.crypto.params.ParametersWithIV;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
 
 import javax.crypto.Cipher;
 import javax.crypto.NoSuchPaddingException;
@@ -35,12 +17,26 @@
 // import javax.crypto.spec.RC2ParameterSpec;
 // import javax.crypto.spec.RC5ParameterSpec;
 // END android-removed
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.StreamBlockCipher;
+import org.bouncycastle.crypto.StreamCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.BlowfishEngine;
+// import org.bouncycastle.crypto.engines.DESEngine;
+// import org.bouncycastle.crypto.engines.DESedeEngine;
+// END android-removed
+import org.bouncycastle.crypto.engines.RC4Engine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.SkipjackEngine;
+// import org.bouncycastle.crypto.engines.TwofishEngine;
+// END android-removed
+import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.OFBBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
 
 public class JCEStreamCipher
     extends WrapCipherSpi implements PBE
@@ -113,7 +109,7 @@
             {
                 try
                 {
-                    AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, "BC");
+                    AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
                     engineParams.init(pbeSpec);
                     
                     return engineParams;
@@ -505,18 +501,6 @@
     // END android-removed
 
     /**
-     * RC4
-     */
-    static public class RC4
-        extends JCEStreamCipher
-    {
-        public RC4()
-        {
-            super(new RC4Engine(), 0);
-        }
-    }
-
-    /**
      * PBEWithSHAAnd128BitRC4
      */
     static public class PBEWithSHAAnd128BitRC4
@@ -539,66 +523,4 @@
             super(new RC4Engine(), 0);
         }
     }
-    
-    // BEGIN android-removed
-    // /**
-    //  * Salsa20
-    //  */
-    // static public class Salsa20
-    //     extends JCEStreamCipher
-    // {
-    //     public Salsa20()
-    //     {
-    //         super(new Salsa20Engine(), 8);
-    //     }
-    // }
-    //
-    // /**
-    //  * HC-128
-    //  */
-    // static public class HC128
-    //     extends JCEStreamCipher
-    // {
-    //     public HC128()
-    //     {
-    //         super(new HC128Engine(), 16);
-    //     }
-    // }
-    //
-    // /**
-    //  * HC-256
-    //  */
-    // static public class HC256
-    //     extends JCEStreamCipher
-    // {
-    //     public HC256()
-    //     {
-    //         super(new HC256Engine(), 32);
-    //     }
-    // }
-    //
-    // /**
-    //  * VMPC
-    //  */
-    // static public class VMPC
-    //     extends JCEStreamCipher
-    // {
-    //     public VMPC()
-    //     {
-    //         super(new VMPCEngine(), 16);
-    //     }
-    // }
-    //
-    // /**
-    //  * VMPC-KSA3
-    //  */
-    // static public class VMPCKSA3
-    //     extends JCEStreamCipher
-    // {
-    //     public VMPCKSA3()
-    //     {
-    //         super(new VMPCKSA3Engine(), 16);
-    //     }
-    // }
-    // END android-removed
 }
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java b/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java
index f367434..b61acfa 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java
@@ -1,5 +1,20 @@
 package org.bouncycastle.jce.provider;
 
+import java.security.AlgorithmParameterGeneratorSpi;
+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 javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+// BEGIN android-removed
+// import javax.crypto.spec.RC2ParameterSpec;
+// END android-removed
+
 import org.bouncycastle.crypto.generators.DHParametersGenerator;
 import org.bouncycastle.crypto.generators.DSAParametersGenerator;
 // BEGIN android-removed
@@ -15,20 +30,6 @@
 // import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
 // END android-removed
 
-import javax.crypto.spec.DHGenParameterSpec;
-import javax.crypto.spec.DHParameterSpec;
-import javax.crypto.spec.IvParameterSpec;
-// BEGIN android-removed
-// import javax.crypto.spec.RC2ParameterSpec;
-// END android-removed
-import java.security.AlgorithmParameterGeneratorSpi;
-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;
-
 public abstract class JDKAlgorithmParameterGenerator
     extends AlgorithmParameterGeneratorSpi
 {
@@ -83,7 +84,7 @@
 
             try
             {
-                params = AlgorithmParameters.getInstance("DH", "BC");
+                params = AlgorithmParameters.getInstance("DH", BouncyCastleProvider.PROVIDER_NAME);
                 params.init(new DHParameterSpec(p.getP(), p.getG(), l));
             }
             catch (Exception e)
@@ -138,7 +139,7 @@
 
             try
             {
-                params = AlgorithmParameters.getInstance("DSA", "BC");
+                params = AlgorithmParameters.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
                 params.init(new DSAParameterSpec(p.getP(), p.getQ(), p.getG()));
             }
             catch (Exception e)
@@ -150,198 +151,198 @@
         }
     }
 
-   // BEGIN android-removed
-   // public static class GOST3410
-   //     extends JDKAlgorithmParameterGenerator
-   // {
-   //     protected void engineInit(
-   //             AlgorithmParameterSpec  genParamSpec,
-   //             SecureRandom            random)
-   //     throws InvalidAlgorithmParameterException
-   //     {
-   //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for GOST3410 parameter generation.");
-   //     }
-   //       
-   //     protected AlgorithmParameters engineGenerateParameters()
-   //     {
-   //         GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator();
-   //           
-   //         if (random != null)
-   //         {
-   //             pGen.init(strength, 2, random);
-   //         }
-   //         else
-   //         {
-   //             pGen.init(strength, 2, new SecureRandom());
-   //         }
-   //           
-   //         GOST3410Parameters p = pGen.generateParameters();
-   //           
-   //         AlgorithmParameters params;
-   //           
-   //         try
-   //         {
-   //             params = AlgorithmParameters.getInstance("GOST3410", "BC");
-   //             params.init(new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(p.getP(), p.getQ(), p.getA())));
-   //         }
-   //         catch (Exception e)
-   //         {
-   //             throw new RuntimeException(e.getMessage());
-   //         }
-   //           
-   //         return params;
-   //     }
-   // }
-   //   
-   // public static class ElGamal
-   //     extends JDKAlgorithmParameterGenerator
-   // {
-   //     private int l = 0;
-   //       
-   //     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()
-   //     {
-   //         ElGamalParametersGenerator pGen = new ElGamalParametersGenerator();
-   //
-   //         if (random != null)
-   //         {
-   //             pGen.init(strength, 20, random);
-   //         }
-   //         else
-   //         {
-   //             pGen.init(strength, 20, new SecureRandom());
-   //         }
-   //
-   //         ElGamalParameters p = pGen.generateParameters();
-   //
-   //         AlgorithmParameters params;
-   //
-   //         try
-   //         {
-   //             params = AlgorithmParameters.getInstance("ElGamal", "BC");
-   //             params.init(new DHParameterSpec(p.getP(), p.getG(), l));
-   //         }
-   //         catch (Exception e)
-   //         {
-   //             throw new RuntimeException(e.getMessage());
-   //         }
-   //
-   //         return params;
-   //     }
-   // }
-   //
-   //  public static class DES
-   //      extends JDKAlgorithmParameterGenerator
-   //  {
-   //      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 = new SecureRandom();
-   //          }
-   //
-   //          random.nextBytes(iv);
-   //
-   //          AlgorithmParameters params;
-   //
-   //          try
-   //          {
-   //              params = AlgorithmParameters.getInstance("DES", "BC");
-   //              params.init(new IvParameterSpec(iv));
-   //          }
-   //          catch (Exception e)
-   //          {
-   //              throw new RuntimeException(e.getMessage());
-   //          }
-   //
-   //          return params;
-   //      }
-   //  }
-   //
-   //  public static class RC2
-   //      extends JDKAlgorithmParameterGenerator
-   //  {
-   //      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 = new SecureRandom();
-   //              }
-   //
-   //              random.nextBytes(iv);
-   //
-   //              try
-   //              {
-   //                  params = AlgorithmParameters.getInstance("RC2", "BC");
-   //                  params.init(new IvParameterSpec(iv));
-   //              }
-   //              catch (Exception e)
-   //              {
-   //                  throw new RuntimeException(e.getMessage());
-   //              }
-   //          }
-   //          else
-   //          {
-   //              try
-   //              {
-   //                  params = AlgorithmParameters.getInstance("RC2", "BC");
-   //                  params.init(spec);
-   //              }
-   //              catch (Exception e)
-   //              {
-   //                  throw new RuntimeException(e.getMessage());
-   //              }
-   //          }
-   //
-   //          return params;
-   //      }
-   //  }
-   // END android-removed
+    // BEGIN android-removed
+    // public static class GOST3410
+    //     extends JDKAlgorithmParameterGenerator
+    // {
+    //     protected void engineInit(
+    //             AlgorithmParameterSpec  genParamSpec,
+    //             SecureRandom            random)
+    //     throws InvalidAlgorithmParameterException
+    //     {
+    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for GOST3410 parameter generation.");
+    //     }
+    //    
+    //     protected AlgorithmParameters engineGenerateParameters()
+    //     {
+    //         GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator();
+    //        
+    //         if (random != null)
+    //         {
+    //             pGen.init(strength, 2, random);
+    //         }
+    //         else
+    //         {
+    //             pGen.init(strength, 2, new SecureRandom());
+    //         }
+    //        
+    //         GOST3410Parameters p = pGen.generateParameters();
+    //        
+    //         AlgorithmParameters params;
+    //
+    //         try
+    //         {
+    //             params = AlgorithmParameters.getInstance("GOST3410", BouncyCastleProvider.PROVIDER_NAME);
+    //             params.init(new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(p.getP(), p.getQ(), p.getA())));
+    //         }
+    //         catch (Exception e)
+    //         {
+    //             throw new RuntimeException(e.getMessage());
+    //         }
+    //
+    //         return params;
+    //     }
+    // }
+    //
+    // public static class ElGamal
+    //     extends JDKAlgorithmParameterGenerator
+    // {
+    //     private int l = 0;
+    //
+    //     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()
+    //     {
+    //         ElGamalParametersGenerator pGen = new ElGamalParametersGenerator();
+    //
+    //         if (random != null)
+    //         {
+    //             pGen.init(strength, 20, random);
+    //         }
+    //         else
+    //         {
+    //             pGen.init(strength, 20, new SecureRandom());
+    //         }
+    //
+    //         ElGamalParameters p = pGen.generateParameters();
+    //
+    //         AlgorithmParameters params;
+    //
+    //         try
+    //         {
+    //             params = AlgorithmParameters.getInstance("ElGamal", BouncyCastleProvider.PROVIDER_NAME);
+    //             params.init(new DHParameterSpec(p.getP(), p.getG(), l));
+    //         }
+    //         catch (Exception e)
+    //         {
+    //             throw new RuntimeException(e.getMessage());
+    //         }
+    //
+    //         return params;
+    //     }
+    // }
+    //
+    // public static class DES
+    //     extends JDKAlgorithmParameterGenerator
+    // {
+    //     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 = new SecureRandom();
+    //         }
+    //
+    //         random.nextBytes(iv);
+    //
+    //         AlgorithmParameters params;
+    //
+    //         try
+    //         {
+    //             params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
+    //             params.init(new IvParameterSpec(iv));
+    //         }
+    //         catch (Exception e)
+    //         {
+    //             throw new RuntimeException(e.getMessage());
+    //         }
+    //
+    //         return params;
+    //     }
+    // }
+    //
+    // public static class RC2
+    //     extends JDKAlgorithmParameterGenerator
+    // {
+    //     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 = new SecureRandom();
+    //             }
+    //
+    //             random.nextBytes(iv);
+    //
+    //             try
+    //             {
+    //                 params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
+    //                 params.init(new IvParameterSpec(iv));
+    //             }
+    //             catch (Exception e)
+    //             {
+    //                 throw new RuntimeException(e.getMessage());
+    //             }
+    //         }
+    //         else
+    //         {
+    //             try
+    //             {
+    //                 params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
+    //                 params.init(spec);
+    //             }
+    //             catch (Exception e)
+    //             {
+    //                 throw new RuntimeException(e.getMessage());
+    //             }
+    //         }
+    //
+    //         return params;
+    //     }
+    // }
+    // END android-removed
 }
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKDSASigner.java b/src/main/java/org/bouncycastle/jce/provider/JDKDSASigner.java
index 9402743..1c22952 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKDSASigner.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKDSASigner.java
@@ -21,6 +21,7 @@
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.DSA;
 import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.NullDigest;
 import org.bouncycastle.crypto.digests.SHA1Digest;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.digests.SHA224Digest;
@@ -33,7 +34,6 @@
 // BEGIN android-removed
 // import org.bouncycastle.jce.interfaces.GOST3410Key;
 // END android-removed
-import org.bouncycastle.jce.provider.util.NullDigest;
 
 public class JDKDSASigner
     extends SignatureSpi
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKDigestSignature.java b/src/main/java/org/bouncycastle/jce/provider/JDKDigestSignature.java
index 380dcd1..badeac1 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKDigestSignature.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKDigestSignature.java
@@ -28,6 +28,7 @@
 // import org.bouncycastle.crypto.digests.MD4Digest;
 // END android-removed
 import org.bouncycastle.crypto.digests.MD5Digest;
+import org.bouncycastle.crypto.digests.NullDigest;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.digests.RIPEMD128Digest;
 // import org.bouncycastle.crypto.digests.RIPEMD160Digest;
@@ -42,7 +43,6 @@
 import org.bouncycastle.crypto.digests.SHA512Digest;
 import org.bouncycastle.crypto.encodings.PKCS1Encoding;
 import org.bouncycastle.crypto.engines.RSABlindedEngine;
-import org.bouncycastle.jce.provider.util.NullDigest;
 
 public class JDKDigestSignature
     extends SignatureSpi
@@ -185,13 +185,13 @@
                 }
             }
         }
-        else if (expected.length == sig.length - 2)  // NULL left out
+        else if (sig.length == expected.length - 2)  // NULL left out
         {
             int sigOffset = sig.length - hash.length - 2;
             int expectedOffset = expected.length - hash.length - 2;
 
-            sig[1] -= 2;      // adjust lengths
-            sig[3] -= 2;
+            expected[1] -= 2;      // adjust lengths
+            expected[3] -= 2;
 
             for (int i = 0; i < hash.length; i++)
             {
@@ -201,7 +201,7 @@
                 }
             }
 
-            for (int i = 0; i < expectedOffset; i++)
+            for (int i = 0; i < sigOffset; i++)
             {
                 if (sig[i] != expected[i])  // check header less NULL
                 {
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java b/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java
index b9aca26..3ed5821 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java
@@ -321,6 +321,10 @@
         {
               return new JCEDHPrivateKey(info);
         }
+        else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+              return new JCEDHPrivateKey(info);
+        }
         // BEGIN android-removed
         // else if (algOid.equals(OIWObjectIdentifiers.elGamalAlgorithm))
         // {
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java b/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java
index e6f74c6..1c68095 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java
@@ -361,7 +361,7 @@
 
         try
         {
-            CertificateFactory cFact = CertificateFactory.getInstance(type, "BC");
+            CertificateFactory cFact = CertificateFactory.getInstance(type, BouncyCastleProvider.PROVIDER_NAME);
             ByteArrayInputStream bIn = new ByteArrayInputStream(cEnc);
 
             return cFact.generateCertificate(bIn);
@@ -436,11 +436,11 @@
             switch (keyType)
             {
             case KEY_PRIVATE:
-                return KeyFactory.getInstance(algorithm, "BC").generatePrivate(spec);
+                return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePrivate(spec);
             case KEY_PUBLIC:
-                return KeyFactory.getInstance(algorithm, "BC").generatePublic(spec);
+                return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePublic(spec);
             case KEY_SECRET:
-                return SecretKeyFactory.getInstance(algorithm, "BC").generateSecret(spec);
+                return SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generateSecret(spec);
             default:
                 throw new IOException("Key type " + keyType + " not recognised!");
             }
@@ -463,10 +463,10 @@
         try
         {
             PBEKeySpec          pbeSpec = new PBEKeySpec(password);
-            SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(algorithm, "BC");
+            SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
             PBEParameterSpec    defParams = new PBEParameterSpec(salt, iterationCount);
 
-            Cipher cipher = Cipher.getInstance(algorithm, "BC");
+            Cipher cipher = Cipher.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
 
             cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams);
 
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java b/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
index 205c2bb..9707b05 100644
--- a/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
@@ -7,6 +7,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.security.Key;
+import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.KeyStoreSpi;
 import java.security.NoSuchAlgorithmException;
@@ -16,8 +17,11 @@
 import java.security.PublicKey;
 import java.security.SecureRandom;
 import java.security.UnrecoverableKeyException;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.ProtectionParameter;
 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.Date;
@@ -46,6 +50,7 @@
 import org.bouncycastle.asn1.DERObject;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DEROutputStream;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERSet;
 import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
@@ -1102,9 +1107,50 @@
         }
     }
 
+    public void engineStore(LoadStoreParameter param) throws IOException,
+            NoSuchAlgorithmException, CertificateException
+    {
+        if (param == null)
+        {
+            throw new IllegalArgumentException("'param' arg cannot be null");
+        }
+
+        if (!(param instanceof JDKPKCS12StoreParameter))
+        {
+            throw new IllegalArgumentException(
+                "No support for 'param' of type " + param.getClass().getName());
+        }
+
+        JDKPKCS12StoreParameter bcParam = (JDKPKCS12StoreParameter)param;
+
+        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.isUseDEREncoding());
+    }
+
     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.");
@@ -1432,9 +1478,17 @@
         AuthenticatedSafe   auth = new AuthenticatedSafe(info);
 
         ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
-        BEROutputStream         berOut = new BEROutputStream(bOut);
+        DEROutputStream asn1Out;
+        if (useDEREncoding)
+        {
+            asn1Out = new DEROutputStream(bOut);
+        }
+        else
+        {
+            asn1Out = new BEROutputStream(bOut);
+        }
 
-        berOut.writeObject(auth);
+        asn1Out.writeObject(auth);
 
         byte[]              pkg = bOut.toByteArray();
 
@@ -1473,9 +1527,16 @@
         //
         Pfx                 pfx = new Pfx(mainInfo, mData);
 
-        berOut = new BEROutputStream(stream);
+        if (useDEREncoding)
+        {
+            asn1Out = new DEROutputStream(stream);
+        }
+        else
+        {
+            asn1Out = new BEROutputStream(stream);
+        }
 
-        berOut.writeObject(pfx);
+        asn1Out.writeObject(pfx);
     }
 
     private static byte[] calculatePbeMac(
diff --git a/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java b/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java
new file mode 100644
index 0000000..865481f
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.OutputStream;
+import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.ProtectionParameter;
+
+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/src/main/java/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java b/src/main/java/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java
index 4e77119..984283f 100644
--- a/src/main/java/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java
+++ b/src/main/java/org/bouncycastle/jce/provider/PKCS12BagAttributeCarrierImpl.java
@@ -1,9 +1,6 @@
 package org.bouncycastle.jce.provider;
 
 import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
-// BEGIN android-added
-import org.bouncycastle.asn1.OrderedTable;
-// END android-added
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.ASN1OutputStream;
@@ -20,73 +17,65 @@
 class PKCS12BagAttributeCarrierImpl
     implements PKCS12BagAttributeCarrier
 {
-    // BEGIN android-changed
-    private OrderedTable pkcs12 = new OrderedTable();
-    // END android-changed
+    private Hashtable pkcs12Attributes;
+    private Vector pkcs12Ordering;
 
-    // BEGIN android-removed
-    // PKCS12BagAttributeCarrierImpl(Hashtable attributes, Vector ordering)
-    // {
-    //     this.pkcs12Attributes = attributes;
-    //     this.pkcs12Ordering = ordering;
-    // }
-    // END android-removed
+    PKCS12BagAttributeCarrierImpl(Hashtable attributes, Vector ordering)
+    {
+        this.pkcs12Attributes = attributes;
+        this.pkcs12Ordering = ordering;
+    }
 
     public PKCS12BagAttributeCarrierImpl()
     {
-        // BEGIN android-removed
-        // this(new Hashtable(), new Vector());
-        // END android-removed
+        this(new Hashtable(), new Vector());
     }
 
     public void setBagAttribute(
         DERObjectIdentifier oid,
         DEREncodable        attribute)
     {
-        // BEGIN android-changed
-        // preserve original ordering
-        pkcs12.put(oid, attribute);
-        // END android-changed
+        if (pkcs12Attributes.containsKey(oid))
+        {                           // preserve original ordering
+            pkcs12Attributes.put(oid, attribute);
+        }
+        else
+        {
+            pkcs12Attributes.put(oid, attribute);
+            pkcs12Ordering.addElement(oid);
+        }
     }
 
     public DEREncodable getBagAttribute(
         DERObjectIdentifier oid)
     {
-        // BEGIN android-changed
-        return (DEREncodable)pkcs12.get(oid);
-        // END android-changed
+        return (DEREncodable)pkcs12Attributes.get(oid);
     }
 
     public Enumeration getBagAttributeKeys()
     {
-        // BEGIN android-changed
-        return pkcs12.getKeys();
-        // END android-changed
+        return pkcs12Ordering.elements();
     }
 
     int size()
     {
-        // BEGIN android-changed
-        return pkcs12.size();
-        // END android-changed
+        return pkcs12Ordering.size();
     }
 
-    // BEGIN android-removed
-    // Hashtable getAttributes()
-    // {
-    //     return pkcs12Attributes;
-    // }
-    //
-    // Vector getOrdering()
-    // {
-    //     return pkcs12Ordering;
-    // }
-    // END android-removed
+    Hashtable getAttributes()
+    {
+        return pkcs12Attributes;
+    }
+
+    Vector getOrdering()
+    {
+        return pkcs12Ordering;
+    }
 
     public void writeObject(ObjectOutputStream out)
         throws IOException
     {
-        if (pkcs12.size() == 0)
+        if (pkcs12Ordering.size() == 0)
         {
             out.writeObject(new Hashtable());
             out.writeObject(new Vector());
@@ -103,7 +92,7 @@
                 DERObjectIdentifier    oid = (DERObjectIdentifier)e.nextElement();
 
                 aOut.writeObject(oid);
-                aOut.writeObject(pkcs12.get(oid));
+                aOut.writeObject(pkcs12Attributes.get(oid));
             }
 
             out.writeObject(bOut.toByteArray());
@@ -117,11 +106,8 @@
 
         if (obj instanceof Hashtable)
         {
-            // BEGIN android-changed
-            // we only write out Hashtable/Vector in empty case
-            in.readObject(); // consume empty Vector
-            this.pkcs12 = new OrderedTable();
-            // END android-changed
+            this.pkcs12Attributes = (Hashtable)obj;
+            this.pkcs12Ordering = (Vector)in.readObject();
         }
         else
         {
diff --git a/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java b/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java
new file mode 100644
index 0000000..c94016d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java
@@ -0,0 +1,155 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.PKIXParameters;
+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 org.bouncycastle.util.StoreException;
+import org.bouncycastle.x509.ExtendedPKIXParameters;
+import org.bouncycastle.x509.X509CRLStoreSelector;
+import org.bouncycastle.x509.X509Store;
+
+public class PKIXCRLUtil
+{
+    public Set findCRLs(X509CRLStoreSelector crlselect, ExtendedPKIXParameters paramsPKIX, Date currentDate)
+        throws AnnotatedException
+    {
+        Set initialSet = new HashSet();
+
+        // get complete CRL(s)
+        try
+        {
+            initialSet.addAll(findCRLs(crlselect, paramsPKIX.getAdditionalStores()));
+            initialSet.addAll(findCRLs(crlselect, paramsPKIX.getStores()));
+            initialSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores()));
+        }
+        catch (AnnotatedException e)
+        {
+            throw new AnnotatedException("Exception obtaining complete CRLs.", e);
+        }
+
+        Set finalSet = new HashSet();
+        Date validityDate = currentDate;
+
+        if (paramsPKIX.getDate() != null)
+        {
+            validityDate = paramsPKIX.getDate();
+        }
+
+        // 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;
+    }
+
+    public Set findCRLs(X509CRLStoreSelector crlselect, PKIXParameters paramsPKIX)
+        throws AnnotatedException
+    {
+        Set completeSet = new HashSet();
+
+        // get complete CRL(s)
+        try
+        {
+            completeSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores()));
+        }
+        catch (AnnotatedException e)
+        {
+            throw new AnnotatedException("Exception obtaining complete CRLs.", e);
+        }
+
+        return completeSet;
+    }
+
+/**
+     * Return a Collection of all CRLs found in the X509Store's that are
+     * matching the crlSelect criteriums.
+     *
+     * @param crlSelect a {@link X509CRLStoreSelector} object that will be used
+     *            to select the CRLs
+     * @param crlStores a List containing only
+     *            {@link org.bouncycastle.x509.X509Store  X509Store} 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(X509CRLStoreSelector 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();
+
+            if (obj instanceof X509Store)
+            {
+                X509Store store = (X509Store)obj;
+
+                try
+                {
+                    crls.addAll(store.getMatches(crlSelect));
+                    foundValidStore = true;
+                }
+                catch (StoreException e)
+                {
+                    lastException = new AnnotatedException(
+                        "Exception searching in X.509 CRL store.", e);
+                }
+            }
+            else
+            {
+                CertStore store = (CertStore)obj;
+
+                try
+                {
+                    crls.addAll(store.getCRLs(crlSelect));
+                    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/src/main/java/org/bouncycastle/jce/provider/PKIXCertPath.java b/src/main/java/org/bouncycastle/jce/provider/PKIXCertPath.java
index 8c8969a..af4b8ab 100644
--- a/src/main/java/org/bouncycastle/jce/provider/PKIXCertPath.java
+++ b/src/main/java/org/bouncycastle/jce/provider/PKIXCertPath.java
@@ -179,7 +179,7 @@
                 }
                 Enumeration e = ((ASN1Sequence)derObject).getObjects();
                 certificates = new ArrayList();
-                CertificateFactory certFactory = CertificateFactory.getInstance("X.509", "BC");
+                CertificateFactory certFactory = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
                 while (e.hasMoreElements())
                 {
                     ASN1Encodable element = (ASN1Encodable)e.nextElement();
@@ -192,7 +192,7 @@
             {
                 inStream = new BufferedInputStream(inStream);
                 certificates = new ArrayList();
-                CertificateFactory certFactory= CertificateFactory.getInstance("X.509", "BC");
+                CertificateFactory certFactory= CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
                 Certificate cert;
                 while ((cert = certFactory.generateCertificate(inStream)) != null)
                 {
diff --git a/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java b/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java
index 05bba8e..384eb86 100644
--- a/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java
+++ b/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java
@@ -1,10 +1,5 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.jce.exception.ExtCertPathBuilderException;
-import org.bouncycastle.util.Selector;
-import org.bouncycastle.x509.ExtendedPKIXBuilderParameters;
-import org.bouncycastle.x509.X509CertStoreSelector;
-
 import java.security.InvalidAlgorithmParameterException;
 import java.security.cert.CertPath;
 import java.security.cert.CertPathBuilderException;
@@ -24,6 +19,11 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.bouncycastle.jce.exception.ExtCertPathBuilderException;
+import org.bouncycastle.util.Selector;
+import org.bouncycastle.x509.ExtendedPKIXBuilderParameters;
+import org.bouncycastle.x509.X509CertStoreSelector;
+
 /**
  * Implements the PKIX CertPathBuilding algorithm for BouncyCastle.
  * 
@@ -160,8 +160,8 @@
 
         try
         {
-            cFact = CertificateFactory.getInstance("X.509", "BC");
-            validator = CertPathValidator.getInstance("PKIX", "BC");
+            cFact = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+            validator = CertPathValidator.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
         }
         catch (Exception e)
         {
@@ -172,9 +172,8 @@
         try
         {
             // check whether the issuer of <tbvCert> is a TrustAnchor
-            // BEGIN android-changed
-            if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams) != null)
-                // END android-changed
+            if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams.getTrustAnchors(),
+                pkixParams.getSigProvider()) != null)
             {
                 // exception message from possibly later tried certification
                 // chains
diff --git a/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java b/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
index f6148cd..fb698f9 100644
--- a/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
+++ b/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
@@ -24,10 +24,6 @@
 
 import javax.security.auth.x500.X500Principal;
 
-// BEGIN android-added
-import org.apache.harmony.xnet.provider.jsse.IndexedPKIXParameters;
-
-// END android-added
 import org.bouncycastle.asn1.DEREncodable;
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -115,18 +111,6 @@
                     + " instance.");
         }
 
-        // BEGIN android-added
-        IndexedPKIXParameters indexedParams;
-        if (params instanceof IndexedPKIXParameters)
-        {
-            indexedParams = (IndexedPKIXParameters)params;
-        }
-        else
-        {
-            indexedParams = null;
-        }
-
-        // END android-added
         ExtendedPKIXParameters paramsPKIX;
         if (params instanceof ExtendedPKIXParameters)
         {
@@ -189,10 +173,8 @@
         TrustAnchor trust;
         try
         {
-            // BEGIN android-changed
             trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
-                    indexedParams != null ? indexedParams : paramsPKIX);
-            // END android-changed
+                    paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider());
         }
         catch (AnnotatedException e)
         {
diff --git a/src/main/java/org/bouncycastle/jce/provider/ProviderUtil.java b/src/main/java/org/bouncycastle/jce/provider/ProviderUtil.java
index 880437d..6060ad4 100644
--- a/src/main/java/org/bouncycastle/jce/provider/ProviderUtil.java
+++ b/src/main/java/org/bouncycastle/jce/provider/ProviderUtil.java
@@ -1,23 +1,23 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.jce.ProviderConfigurationPermission;
-import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
-import org.bouncycastle.jce.interfaces.ConfigurableProvider;
-import org.bouncycastle.jce.spec.ECParameterSpec;
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.security.Permission;
 
+import org.bouncycastle.jce.ProviderConfigurationPermission;
+import org.bouncycastle.jce.interfaces.ConfigurableProvider;
+import org.bouncycastle.jce.provider.asymmetric.ec.EC5Util;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+
 public class ProviderUtil
 {
     private static final long  MAX_MEMORY = Runtime.getRuntime().maxMemory();
 
     private static Permission BC_EC_LOCAL_PERMISSION = new ProviderConfigurationPermission(
-                                                   "BC", ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA);
+                                                   BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA);
     private static Permission BC_EC_PERMISSION = new ProviderConfigurationPermission(
-                                                   "BC", ConfigurableProvider.EC_IMPLICITLY_CA);
+                                                   BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.EC_IMPLICITLY_CA);
 
     private static ThreadLocal threadSpec = new ThreadLocal();
     private static volatile ECParameterSpec ecImplicitCaParams;
diff --git a/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java b/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
index 269f295..ef3baaa 100644
--- a/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
+++ b/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
@@ -59,6 +59,7 @@
 
 public class RFC3280CertPathUtilities
 {
+    private static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
 
     /**
      * If the complete CRL includes an issuing distribution point (IDP) CRL
@@ -491,7 +492,7 @@
             }
             try
             {
-                CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", "BC");
+                CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
                 selector = new X509CertStoreSelector();
                 selector.setCertificate(signingCert);
                 ExtendedPKIXParameters temp = (ExtendedPKIXParameters)paramsPKIX.clone();
@@ -678,20 +679,10 @@
         X509CRL crl)
         throws AnnotatedException
     {
-        Set completeSet = new HashSet();
         Set deltaSet = new HashSet();
         X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
         crlselect.setCertificateChecking(cert);
 
-        if (paramsPKIX.getDate() != null)
-        {
-            crlselect.setDateAndTime(paramsPKIX.getDate());
-        }
-        else
-        {
-            crlselect.setDateAndTime(currentDate);
-        }
-
         try
         {
             crlselect.addIssuerName(crl.getIssuerX500Principal().getEncoded());
@@ -702,18 +693,8 @@
         }
 
         crlselect.setCompleteCRLEnabled(true);
+        Set completeSet = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
 
-        // get complete CRL(s)
-        try
-        {
-            completeSet.addAll(CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getAdditionalStores()));
-            completeSet.addAll(CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getStores()));
-            completeSet.addAll(CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getCertStores()));
-        }
-        catch (AnnotatedException e)
-        {
-            throw new AnnotatedException("Exception obtaining complete CRLs.", e);
-        }
         if (paramsPKIX.isUseDeltasEnabled())
         {
             // get delta CRL(s)
@@ -732,6 +713,8 @@
                 deltaSet};
     }
 
+
+
     /**
      * If use-deltas is set, verify the issuer and scope of the delta CRL.
      *
@@ -1583,7 +1566,7 @@
                     ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
                     if (constraint.getTagNo() == 0)
                     {
-                        tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+                        tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
                         if (tmpInt < explicitPolicy)
                         {
                             return tmpInt;
@@ -1637,7 +1620,7 @@
                     ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
                     if (constraint.getTagNo() == 1)
                     {
-                        tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+                        tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
                         if (tmpInt < policyMapping)
                         {
                             return tmpInt;
@@ -2343,7 +2326,7 @@
         }
         catch (AnnotatedException e)
         {
-            throw new ExtCertPathValidatorException("Policy constraints could no be decoded.", e, certPath, index);
+            throw new ExtCertPathValidatorException("Policy constraints could not be decoded.", e, certPath, index);
         }
         if (pc != null)
         {
@@ -2357,12 +2340,12 @@
                     case 0:
                         try
                         {
-                            tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+                            tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
                         }
                         catch (Exception e)
                         {
                             throw new ExtCertPathValidatorException(
-                                "Policy constraints requireExplicitPolicy field could no be decoded.", e, certPath,
+                                "Policy constraints requireExplicitPolicy field could not be decoded.", e, certPath,
                                 index);
                         }
                         if (tmpInt == 0)
diff --git a/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java b/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java
index 7b78f82..1a5808b 100644
--- a/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java
+++ b/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java
@@ -1,23 +1,18 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.Wrapper;
-import org.bouncycastle.crypto.engines.DESedeEngine;
-import org.bouncycastle.crypto.engines.DESedeWrapEngine;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.engines.RC2WrapEngine;
-// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
-// END android-removed
-import org.bouncycastle.crypto.params.KeyParameter;
-import org.bouncycastle.crypto.params.ParametersWithIV;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+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.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;
@@ -32,19 +27,22 @@
 // import javax.crypto.spec.RC5ParameterSpec;
 // END android-removed
 import javax.crypto.spec.SecretKeySpec;
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-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.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Wrapper;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.RC2WrapEngine;
+// END android-removed
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
 
 public abstract class WrapCipherSpi extends CipherSpi
     implements PBE
@@ -406,7 +404,7 @@
         {
             try
             {
-                KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, "BC");
+                KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
 
                 if (wrappedKeyType == Cipher.PUBLIC_KEY)
                 {
@@ -440,17 +438,6 @@
     // classes that inherit directly from us
     //
 
-
-
-    public static class DESEDEWrap
-        extends WrapCipherSpi
-    {
-        public DESEDEWrap()
-        {
-            super(new DESedeWrapEngine());
-        }
-    }
-
     // BEGIN android-removed
     // public static class RC2Wrap
     //     extends WrapCipherSpi
@@ -460,14 +447,5 @@
     //         super(new RC2WrapEngine());
     //     }
     // }
-    //
-    // public static class RFC3211DESedeWrap
-    //     extends WrapCipherSpi
-    // {
-    //     public RFC3211DESedeWrap()
-    //     {
-    //         super(new RFC3211WrapEngine(new DESedeEngine()), 8);
-    //     }
-    // }
     // END android-removed
 }
diff --git a/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java b/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
index b86833a..1a073e0 100644
--- a/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
+++ b/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
@@ -1,22 +1,5 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DEREnumerated;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DEROutputStream;
-import org.bouncycastle.asn1.util.ASN1Dump;
-import org.bouncycastle.asn1.x509.CRLReason;
-import org.bouncycastle.asn1.x509.GeneralName;
-import org.bouncycastle.asn1.x509.GeneralNames;
-import org.bouncycastle.asn1.x509.TBSCertList;
-import org.bouncycastle.asn1.x509.X509Extension;
-import org.bouncycastle.asn1.x509.X509Extensions;
-import org.bouncycastle.x509.extension.X509ExtensionUtil;
-
-import javax.security.auth.x500.X500Principal;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.math.BigInteger;
 import java.security.cert.CRLException;
@@ -26,6 +9,22 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEREnumerated;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x509.CRLReason;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.TBSCertList;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.x509.extension.X509ExtensionUtil;
+
 /**
  * The following extensions are listed in RFC 2459 as relevant to CRL Entries
  * 
diff --git a/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java b/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
index b196f3d..956c58b 100644
--- a/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
+++ b/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
@@ -1,25 +1,5 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1OutputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DEROutputStream;
-import org.bouncycastle.asn1.util.ASN1Dump;
-import org.bouncycastle.asn1.x509.CRLDistPoint;
-import org.bouncycastle.asn1.x509.CRLNumber;
-import org.bouncycastle.asn1.x509.CertificateList;
-import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
-import org.bouncycastle.asn1.x509.TBSCertList;
-import org.bouncycastle.asn1.x509.X509Extension;
-import org.bouncycastle.asn1.x509.X509Extensions;
-import org.bouncycastle.jce.X509Principal;
-import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.x509.extension.X509ExtensionUtil;
-
-import javax.security.auth.x500.X500Principal;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.math.BigInteger;
@@ -35,12 +15,32 @@
 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 java.util.Collections;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OutputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x509.CRLDistPoint;
+import org.bouncycastle.asn1.x509.CRLNumber;
+import org.bouncycastle.asn1.x509.CertificateList;
+import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
+import org.bouncycastle.asn1.x509.TBSCertList;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.x509.extension.X509ExtensionUtil;
 
 /**
  * The following extensions are listed in RFC 2459 as relevant to CRLs
@@ -185,7 +185,7 @@
         throws CRLException,  NoSuchAlgorithmException,
             InvalidKeyException, NoSuchProviderException, SignatureException
     {
-        verify(key, "BC");
+        verify(key, BouncyCastleProvider.PROVIDER_NAME);
     }
 
     public void verify(PublicKey key, String sigProvider)
diff --git a/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java b/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
index e81211e..d52386a 100644
--- a/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
+++ b/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
@@ -1,31 +1,5 @@
 package org.bouncycastle.jce.provider;
 
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1OutputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERIA5String;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DEROutputStream;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-import org.bouncycastle.asn1.misc.NetscapeCertType;
-import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
-import org.bouncycastle.asn1.misc.VerisignCzagExtension;
-import org.bouncycastle.asn1.util.ASN1Dump;
-import org.bouncycastle.asn1.x509.BasicConstraints;
-import org.bouncycastle.asn1.x509.KeyUsage;
-import org.bouncycastle.asn1.x509.X509CertificateStructure;
-import org.bouncycastle.asn1.x509.X509Extension;
-import org.bouncycastle.asn1.x509.X509Extensions;
-import org.bouncycastle.jce.X509Principal;
-import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
-import org.bouncycastle.util.Arrays;
-import org.bouncycastle.util.encoders.Hex;
-
-import javax.security.auth.x500.X500Principal;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.math.BigInteger;
@@ -53,6 +27,34 @@
 import java.util.List;
 import java.util.Set;
 
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OutputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.asn1.misc.NetscapeCertType;
+import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
+import org.bouncycastle.asn1.misc.VerisignCzagExtension;
+import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.KeyUsage;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+
 public class X509CertificateObject
     extends X509Certificate
     implements PKCS12BagAttributeCarrier
@@ -222,7 +224,7 @@
      */
     public String getSigAlgName()
     {
-        Provider    prov = Security.getProvider("BC");
+        Provider    prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
 
         if (prov != null)
         {
@@ -546,19 +548,19 @@
         {
             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)
@@ -582,7 +584,13 @@
     {
         try
         {
-            return Arrays.hashCode(this.getEncoded());
+            int hashCode = 0;
+            byte[] certData = this.getEncoded();
+            for (int i = 1; i < certData.length; i++)
+            {
+                 hashCode += certData[i] * i;
+            }
+            return hashCode;
         }
         catch (CertificateEncodingException e)
         {
@@ -714,7 +722,7 @@
 
         try
         {
-            signature = Signature.getInstance(sigName, "BC");
+            signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
         }
         catch (Exception e)
         {
@@ -742,7 +750,7 @@
         throws CertificateException, NoSuchAlgorithmException, 
             SignatureException, InvalidKeyException
     {
-        if (!c.getSignatureAlgorithm().equals(c.getTBSCertificate().getSignature()))
+        if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
         {
             throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
         }
@@ -761,4 +769,34 @@
             throw new InvalidKeyException("Public key presented not for certificate signature");
         }
     }
+
+    private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+    {
+        if (!id1.getObjectId().equals(id2.getObjectId()))
+        {
+            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());
+    }
 }
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/EC.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/EC.java
new file mode 100644
index 0000000..5d873f9
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/asymmetric/EC.java
@@ -0,0 +1,117 @@
+package org.bouncycastle.jce.provider.asymmetric;
+
+import java.util.HashMap;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END android-removed
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+
+public class EC
+{
+    public static class Mappings
+        extends HashMap
+    {
+        public Mappings()
+        {
+            put("KeyAgreement.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DH");
+            // BEGIN android-removed
+            // put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
+            // put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
+            // put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
+            // put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
+            // END android-removed
+
+            put("KeyFactory.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$EC");
+            // BEGIN android-removed
+            // put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
+            // put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
+            // put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
+            // put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
+            // END android-removed
+            put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.id_ecPublicKey, "EC");
+            // TODO Should this be an alias for ECDH?
+            put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+            // BEGIN android-removed
+            // put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
+            //
+            // put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
+            // put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
+            // put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
+            // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
+            // END android-removed
+
+            put("KeyPairGenerator.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$EC");
+            // BEGIN android-removed
+            // put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
+            // put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
+            // put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
+            // put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
+            // put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
+            // END android-removed
+            // TODO Should this be an alias for ECDH?
+            put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+            // BEGIN android-removed
+            // put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
+            //
+            // put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
+            // put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
+            // put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
+            // END android-removed
+
+            put("Signature.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA");
+            put("Signature.NONEwithECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSAnone");
+
+            put("Alg.Alias.Signature.SHA1withECDSA", "ECDSA");
+            put("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA");
+            put("Alg.Alias.Signature.SHA1WITHECDSA", "ECDSA");
+            put("Alg.Alias.Signature.ECDSAWITHSHA1", "ECDSA");
+            put("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA");
+            put("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA");
+            put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
+            // BEGIN android-removed
+            // put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
+            //
+            // addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
+            // END android-removed
+            addSignatureAlgorithm("SHA256", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
+            addSignatureAlgorithm("SHA384", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
+            addSignatureAlgorithm("SHA512", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
+            // BEGIN android-removed
+            // addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
+            //
+            // put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
+            // put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
+            // put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
+            // put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
+            // put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
+            //
+            // addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
+            // addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
+            // addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
+            // END android-removed
+        }
+
+        private void addSignatureAlgorithm(
+            String digest,
+            String algorithm,
+            String className,
+            DERObjectIdentifier oid)
+        {
+            String mainName = digest + "WITH" + algorithm;
+            String jdk11Variation1 = digest + "with" + algorithm;
+            String jdk11Variation2 = digest + "With" + algorithm;
+            String alias = digest + "/" + algorithm;
+
+            put("Signature." + mainName, className);
+            put("Alg.Alias.Signature." + jdk11Variation1, mainName);
+            put("Alg.Alias.Signature." + jdk11Variation2, mainName);
+            put("Alg.Alias.Signature." + alias, mainName);
+            put("Alg.Alias.Signature." + oid, mainName);
+            put("Alg.Alias.Signature.OID." + oid, mainName);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ECMappings.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ECMappings.java
deleted file mode 100644
index 4294d14..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ECMappings.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package org.bouncycastle.jce.provider.asymmetric;
-
-import java.util.HashMap;
-
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-// BEGIN android-removed
-// import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
-// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
-// END android-removed
-import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-
-public class ECMappings
-    extends HashMap
-{
-    public ECMappings()
-    {
-        put("KeyAgreement.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DH");
-        // BEGIN android-removed
-        // put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHC");
-        // put("KeyAgreement.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQV");
-        // put("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$DHwithSHA1KDF");
-        // put("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "org.bouncycastle.jce.provider.asymmetric.ec.KeyAgreement$MQVwithSHA1KDF");
-        // END android-removed
-
-        put("KeyFactory.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$EC");
-        // BEGIN android-removed
-        // put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDSA");
-        // put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDH");
-        // put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECDHC");
-        // put("KeyFactory.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECMQV");
-        // END android-removed
-        put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.id_ecPublicKey, "EC");
-        // TODO Should this be an alias for ECDH?
-        put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
-        // BEGIN android-removed
-        // put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
-
-        // put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory$ECGOST3410");
-        // put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
-        // put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
-        // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
-        // END android-removed
-
-        put("KeyPairGenerator.EC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$EC");
-        // BEGIN android-removed
-        // put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDSA");
-        // put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
-        // put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDHC");
-        // put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECDH");
-        // put("KeyPairGenerator.ECMQV", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECMQV");
-        // END android-removed
-        // TODO Should this be an alias for ECDH?
-        put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
-        // BEGIN android-removed
-        // put("Alg.Alias.KeyPairGenerator." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV");
-
-        // put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.asymmetric.ec.KeyPairGenerator$ECGOST3410");
-        // put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
-        // put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
-        // END android-removed
-
-        put("Signature.ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA");
-        put("Signature.NONEwithECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSAnone");
-
-        put("Alg.Alias.Signature.SHA1withECDSA", "ECDSA");
-        put("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA");
-        put("Alg.Alias.Signature.SHA1WITHECDSA", "ECDSA");
-        put("Alg.Alias.Signature.ECDSAWITHSHA1", "ECDSA");
-        put("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA");
-        put("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA");
-        put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
-        // BEGIN android-removed
-        // put("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
-
-        // addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
-        // END android-removed
-        addSignatureAlgorithm("SHA256", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
-        addSignatureAlgorithm("SHA384", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
-        addSignatureAlgorithm("SHA512", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
-        // BEGIN android-removed
-        // addSignatureAlgorithm("RIPEMD160", "ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
-
-        // put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR");
-        // put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR224");
-        // put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR256");
-        // put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR384");
-        // put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecNR512");
-
-        // addSignatureAlgorithm("SHA1", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
-        // addSignatureAlgorithm("SHA224", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
-        // addSignatureAlgorithm("SHA256", "CVC-ECDSA", "org.bouncycastle.jce.provider.asymmetric.ec.Signature$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
-        // END android-removed
-    }
-
-    private void addSignatureAlgorithm(
-        String digest,
-        String algorithm,
-        String className,
-        DERObjectIdentifier oid)
-    {
-        String mainName = digest + "WITH" + algorithm;
-        String jdk11Variation1 = digest + "with" + algorithm;
-        String jdk11Variation2 = digest + "With" + algorithm;
-        String alias = digest + "/" + algorithm;
-
-        put("Signature." + mainName, className);
-        put("Alg.Alias.Signature." + jdk11Variation1, mainName);
-        put("Alg.Alias.Signature." + jdk11Variation2, mainName);
-        put("Alg.Alias.Signature." + alias, mainName);
-        put("Alg.Alias.Signature." + oid, mainName);
-        put("Alg.Alias.Signature.OID." + oid, mainName);
-    }
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java
index d2fa69e..438928f 100644
--- a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java
+++ b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyAgreement.java
@@ -59,9 +59,11 @@
 
     static
     {
-        Integer i128 = new Integer(128);
-        Integer i192 = new Integer(192);
-        Integer i256 = new Integer(256);
+        // BEGIN android-changed
+        Integer i128 = Integer.valueOf(128);
+        Integer i192 = Integer.valueOf(192);
+        Integer i256 = Integer.valueOf(256);
+        // END android-changed
 
         algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
         algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java
index 88228d5..ab104ed 100644
--- a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java
+++ b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/KeyPairGenerator.java
@@ -60,13 +60,15 @@
         static {
             ecParameters = new Hashtable();
 
-            ecParameters.put(new Integer(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
-            ecParameters.put(new Integer(239), new ECGenParameterSpec("prime239v1"));
-            ecParameters.put(new Integer(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
+            // BEGIN android-changed
+            ecParameters.put(Integer.valueOf(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
+            ecParameters.put(Integer.valueOf(239), new ECGenParameterSpec("prime239v1"));
+            ecParameters.put(Integer.valueOf(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
 
-            ecParameters.put(new Integer(224), new ECGenParameterSpec("P-224"));
-            ecParameters.put(new Integer(384), new ECGenParameterSpec("P-384"));
-            ecParameters.put(new Integer(521), new ECGenParameterSpec("P-521"));
+            ecParameters.put(Integer.valueOf(224), new ECGenParameterSpec("P-224"));
+            ecParameters.put(Integer.valueOf(384), new ECGenParameterSpec("P-384"));
+            ecParameters.put(Integer.valueOf(521), new ECGenParameterSpec("P-521"));
+            // END android-changed
         }
 
         public EC()
@@ -94,7 +96,9 @@
             // BEGIN android-added
             }
             // END android-added
-            this.ecParams = ecParameters.get(new Integer(strength));
+            // BEGIN android-changed
+            this.ecParams = ecParameters.get(Integer.valueOf(strength));
+            // END android-changed
 
             if (ecParams != null)
             {
diff --git a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java
index 13a868c..0bb21f8 100644
--- a/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java
+++ b/src/main/java/org/bouncycastle/jce/provider/asymmetric/ec/Signature.java
@@ -10,7 +10,6 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1InputStream;
 import org.bouncycastle.asn1.ASN1Object;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERInteger;
@@ -18,6 +17,7 @@
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.DSA;
 import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.NullDigest;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.digests.RIPEMD160Digest;
 // END android-removed
@@ -37,7 +37,6 @@
 import org.bouncycastle.jce.provider.DSABase;
 import org.bouncycastle.jce.provider.DSAEncoder;
 import org.bouncycastle.jce.provider.JDKKeyFactory;
-import org.bouncycastle.jce.provider.util.NullDigest;
 
 public class Signature
     extends DSABase
diff --git a/src/main/java/org/bouncycastle/jce/provider/symmetric/AES.java b/src/main/java/org/bouncycastle/jce/provider/symmetric/AES.java
index f2e84e4..6076ee5 100644
--- a/src/main/java/org/bouncycastle/jce/provider/symmetric/AES.java
+++ b/src/main/java/org/bouncycastle/jce/provider/symmetric/AES.java
@@ -1,27 +1,32 @@
 package org.bouncycastle.jce.provider.symmetric;
 
-import org.bouncycastle.crypto.BufferedBlockCipher;
-import org.bouncycastle.crypto.CipherKeyGenerator;
-import org.bouncycastle.crypto.engines.AESEngine;
-import org.bouncycastle.crypto.engines.AESFastEngine;
-import org.bouncycastle.crypto.engines.AESWrapEngine;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
-// END android-removed
-import org.bouncycastle.crypto.modes.CBCBlockCipher;
-import org.bouncycastle.crypto.modes.CFBBlockCipher;
-import org.bouncycastle.crypto.modes.OFBBlockCipher;
-import org.bouncycastle.jce.provider.JCEBlockCipher;
-import org.bouncycastle.jce.provider.JCEKeyGenerator;
-import org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator;
-import org.bouncycastle.jce.provider.JDKAlgorithmParameters;
-import org.bouncycastle.jce.provider.WrapCipherSpi;
-
-import javax.crypto.spec.IvParameterSpec;
 import java.security.AlgorithmParameters;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.SecureRandom;
 import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.engines.AESFastEngine;
+import org.bouncycastle.crypto.engines.AESWrapEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+// import org.bouncycastle.crypto.macs.CMac;
+// END android-removed
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.OFBBlockCipher;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.provider.JCEBlockCipher;
+import org.bouncycastle.jce.provider.JCEKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+import org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator;
+import org.bouncycastle.jce.provider.JDKAlgorithmParameters;
+import org.bouncycastle.jce.provider.WrapCipherSpi;
 
 public final class AES
 {
@@ -65,6 +70,15 @@
     //         super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128);
     //     }
     // }
+    //
+    // public static class AESCMAC
+    //     extends JCEMac
+    // {
+    //     public AESCMAC()
+    //     {
+    //         super(new CMac(new AESFastEngine()));
+    //     }
+    // }
     // END android-removed
 
     static public class Wrap
@@ -82,7 +96,7 @@
     // {
     //     public RFC3211Wrap()
     //     {
-    //         super(new RFC3211WrapEngine(new AESEngine()), 16);
+    //         super(new RFC3211WrapEngine(new AESFastEngine()), 16);
     //     }
     // }
     // END android-removed
@@ -155,7 +169,7 @@
     //
     //         try
     //         {
-    //             params = AlgorithmParameters.getInstance("AES", "BC");
+    //             params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
     //             params.init(new IvParameterSpec(iv));
     //         }
     //         catch (Exception e)
@@ -176,4 +190,89 @@
             return "AES IV";
         }
     }
+
+    public static class Mappings
+        extends HashMap
+    {
+        /**
+         * 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()
+        {
+            put("AlgorithmParameters.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParams");
+            put("Alg.Alias.AlgorithmParameters." + wrongAES128, "AES");
+            put("Alg.Alias.AlgorithmParameters." + wrongAES192, "AES");
+            put("Alg.Alias.AlgorithmParameters." + wrongAES256, "AES");
+            put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+            put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+            put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+
+            // BEGIN android-removed
+            // put("AlgorithmParameterGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParamGen");
+            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
+            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
+            // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
+            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+            // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+            // END android-removed
+
+            put("Cipher.AES", "org.bouncycastle.jce.provider.symmetric.AES$ECB");
+            put("Alg.Alias.Cipher." + wrongAES128, "AES");
+            put("Alg.Alias.Cipher." + wrongAES192, "AES");
+            put("Alg.Alias.Cipher." + wrongAES256, "AES");
+            // BEGIN android-removed
+            // put("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
+            // put("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
+            // put("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$ECB");
+            // put("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
+            // put("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
+            // put("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$CBC");
+            // put("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
+            // put("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
+            // put("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$OFB");
+            // put("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
+            // put("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
+            // put("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$CFB");
+            // END android-removed
+            put("Cipher.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$Wrap");
+            put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
+            put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
+            put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
+            // BEGIN android-removed
+            // put("Cipher.AESRFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.AES$RFC3211Wrap");
+            // END android-removed
+
+            put("KeyGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
+            // BEGIN android-removed
+            // put("KeyGenerator.2.16.840.1.101.3.4.2", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+            // put("KeyGenerator.2.16.840.1.101.3.4.22", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+            // put("KeyGenerator.2.16.840.1.101.3.4.42", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+            // put("KeyGenerator.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
+            // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
+            //
+            // put("Mac.AESCMAC", "org.bouncycastle.jce.provider.symmetric.AES$AESCMAC");
+            // END android-removed
+        }
+    }
 }
diff --git a/src/main/java/org/bouncycastle/jce/provider/symmetric/AESMappings.java b/src/main/java/org/bouncycastle/jce/provider/symmetric/AESMappings.java
deleted file mode 100644
index b3294c3..0000000
--- a/src/main/java/org/bouncycastle/jce/provider/symmetric/AESMappings.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.bouncycastle.jce.provider.symmetric;
-
-import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-
-import java.util.HashMap;
-
-public class AESMappings
-    extends HashMap
-{
-    /**
-     * 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 AESMappings()
-    {
-        put("AlgorithmParameters.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParams");
-        put("Alg.Alias.AlgorithmParameters." + wrongAES128, "AES");
-        put("Alg.Alias.AlgorithmParameters." + wrongAES192, "AES");
-        put("Alg.Alias.AlgorithmParameters." + wrongAES256, "AES");
-        put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
-        put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
-        put("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
-
-        // BEGIN android-removed
-        // put("AlgorithmParameterGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$AlgParamGen");
-        // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
-        // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
-        // put("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
-        // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
-        // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
-        // put("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
-        // END android-removed
-
-        put("Cipher.AES", "org.bouncycastle.jce.provider.symmetric.AES$ECB");
-        put("Alg.Alias.Cipher." + wrongAES128, "AES");
-        put("Alg.Alias.Cipher." + wrongAES192, "AES");
-        put("Alg.Alias.Cipher." + wrongAES256, "AES");
-        // BEGIN android-changed
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_ECB, "AES");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_ECB, "AES");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_ECB, "AES");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_OFB, "AES");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_OFB, "AES");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_OFB, "AES");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_CFB, "AES");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_CFB, "AES");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_CFB, "AES");
-        // END android-changed
-        put("Cipher.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$Wrap");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
-        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
-        // BEGIN android-removed
-        // put("Cipher.AESRFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.AES$RFC3211Wrap");
-        // END android-removed
-
-        put("KeyGenerator.AES", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
-        // BEGIN android-removed
-        // put("KeyGenerator.2.16.840.1.101.3.4.2", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-        // put("KeyGenerator.2.16.840.1.101.3.4.22", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-        // put("KeyGenerator.2.16.840.1.101.3.4.42", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-        // put("KeyGenerator.AESWRAP", "org.bouncycastle.jce.provider.symmetric.AES$KeyGen");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen128");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen192");
-        // put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, "org.bouncycastle.jce.provider.symmetric.AES$KeyGen256");
-        // END android-removed
-    }
-}
diff --git a/src/main/java/org/bouncycastle/jce/provider/symmetric/ARC4.java b/src/main/java/org/bouncycastle/jce/provider/symmetric/ARC4.java
new file mode 100644
index 0000000..1206f6c
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/symmetric/ARC4.java
@@ -0,0 +1,50 @@
+package org.bouncycastle.jce.provider.symmetric;
+
+import java.util.HashMap;
+
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.engines.RC4Engine;
+import org.bouncycastle.jce.provider.JCEKeyGenerator;
+import org.bouncycastle.jce.provider.JCEStreamCipher;
+
+public final class ARC4
+{
+    private ARC4()
+    {
+    }
+    
+    public static class Base
+        extends JCEStreamCipher
+    {
+        public Base()
+        {
+            super(new RC4Engine(), 0);
+        }
+    }
+
+    public static class KeyGen
+        extends JCEKeyGenerator
+    {
+        public KeyGen()
+        {
+            // BEGIN android-changed
+            super("ARC4", 128, new CipherKeyGenerator());
+            // END android-changed
+        }
+    }
+
+    public static class Mappings
+        extends HashMap
+    {
+        public Mappings()
+        {
+            put("Cipher.ARC4", "org.bouncycastle.jce.provider.symmetric.ARC4$Base");
+            put("Alg.Alias.Cipher.1.2.840.113549.3.4", "ARC4");
+            put("Alg.Alias.Cipher.ARCFOUR", "ARC4");
+            put("Alg.Alias.Cipher.RC4", "ARC4");
+            put("KeyGenerator.ARC4", "org.bouncycastle.jce.provider.symmetric.ARC4$KeyGen");
+            put("Alg.Alias.KeyGenerator.RC4", "ARC4");
+            put("Alg.Alias.KeyGenerator.1.2.840.113549.3.4", "ARC4");
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/symmetric/Blowfish.java b/src/main/java/org/bouncycastle/jce/provider/symmetric/Blowfish.java
new file mode 100644
index 0000000..b1a8b72
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/symmetric/Blowfish.java
@@ -0,0 +1,69 @@
+package org.bouncycastle.jce.provider.symmetric;
+
+import java.util.HashMap;
+
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.engines.BlowfishEngine;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.jce.provider.JCEBlockCipher;
+import org.bouncycastle.jce.provider.JCEKeyGenerator;
+import org.bouncycastle.jce.provider.JDKAlgorithmParameters;
+
+public final class Blowfish
+{
+    private Blowfish()
+    {
+    }
+    
+    public static class ECB
+        extends JCEBlockCipher
+    {
+        public ECB()
+        {
+            super(new BlowfishEngine());
+        }
+    }
+
+    public static class CBC
+        extends JCEBlockCipher
+    {
+        public CBC()
+        {
+            super(new CBCBlockCipher(new BlowfishEngine()), 64);
+        }
+    }
+
+    public static class KeyGen
+        extends JCEKeyGenerator
+    {
+        public KeyGen()
+        {
+            super("Blowfish", 128, new CipherKeyGenerator());
+        }
+    }
+
+    public static class AlgParams
+        extends JDKAlgorithmParameters.IVAlgorithmParameters
+    {
+        protected String engineToString()
+        {
+            return "Blowfish IV";
+        }
+    }
+
+    public static class Mappings
+        extends HashMap
+    {
+        public Mappings()
+        {
+            put("Cipher.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$ECB");
+            // BEGIN android-removed
+            // put("Cipher.1.3.6.1.4.1.3029.1.2", "org.bouncycastle.jce.provider.symmetric.Blowfish$CBC");
+            // END android-removed
+            put("KeyGenerator.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$KeyGen");
+            put("Alg.Alias.KeyGenerator.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
+            put("AlgorithmParameters.BLOWFISH", "org.bouncycastle.jce.provider.symmetric.Blowfish$AlgParams");
+            put("Alg.Alias.AlgorithmParameters.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/jce/provider/symmetric/DESede.java b/src/main/java/org/bouncycastle/jce/provider/symmetric/DESede.java
new file mode 100644
index 0000000..ec35f61
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jce/provider/symmetric/DESede.java
@@ -0,0 +1,313 @@
+package org.bouncycastle.jce.provider.symmetric;
+
+import java.security.SecureRandom;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.HashMap;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESedeKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.engines.DESedeEngine;
+import org.bouncycastle.crypto.engines.DESedeWrapEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+// END android-removed
+import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+// import org.bouncycastle.crypto.macs.CMac;
+// END android-removed
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.jce.provider.JCEBlockCipher;
+import org.bouncycastle.jce.provider.JCEKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+import org.bouncycastle.jce.provider.JCESecretKeyFactory;
+import org.bouncycastle.jce.provider.WrapCipherSpi;
+
+public final class DESede
+{
+    private DESede()
+    {
+    }
+
+    static public class ECB
+        extends JCEBlockCipher
+    {
+        public ECB()
+        {
+            super(new DESedeEngine());
+        }
+    }
+
+    static public class CBC
+        extends JCEBlockCipher
+    {
+        public CBC()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()), 64);
+        }
+    }
+
+    // BEGIN android-removed
+    // /**
+    //  * DESede   CFB8
+    //  */
+    // public static class DESedeCFB8
+    //     extends JCEMac
+    // {
+    //     public DESedeCFB8()
+    //     {
+    //         super(new CFBBlockCipherMac(new DESedeEngine()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * DESede64
+     */
+    public static class DESede64
+        extends JCEMac
+    {
+        public DESede64()
+        {
+            super(new CBCBlockCipherMac(new DESedeEngine(), 64));
+        }
+    }
+
+    /**
+     * DESede64with7816-4Padding
+     */
+    public static class DESede64with7816d4
+        extends JCEMac
+    {
+        public DESede64with7816d4()
+        {
+            super(new CBCBlockCipherMac(new DESedeEngine(), 64, new ISO7816d4Padding()));
+        }
+    }
+    
+    public static class CBCMAC
+        extends JCEMac
+    {
+        public CBCMAC()
+        {
+            super(new CBCBlockCipherMac(new DESedeEngine()));
+        }
+    }
+
+    // BEGIN android-removed
+    // static public class CMAC
+    //     extends JCEMac
+    // {
+    //     public CMAC()
+    //     {
+    //         super(new CMac(new DESedeEngine()));
+    //     }
+    // }
+    // END android-removed
+
+    public static class Wrap
+        extends WrapCipherSpi
+    {
+        public Wrap()
+        {
+            super(new DESedeWrapEngine());
+        }
+    }
+
+    // BEGIN android-removed
+    // public static class RFC3211
+    //     extends WrapCipherSpi
+    // {
+    //     public RFC3211()
+    //     {
+    //         super(new RFC3211WrapEngine(new DESedeEngine()), 8);
+    //     }
+    // }
+    // END android-removed
+
+  /**
+     * 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.
+     */
+    public static class KeyGenerator
+        extends JCEKeyGenerator
+    {
+        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(new SecureRandom(), 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.
+     */
+    public static class KeyGenerator3
+        extends JCEKeyGenerator
+    {
+        public KeyGenerator3()
+        {
+            super("DESede3", 192, new DESedeKeyGenerator());
+        }
+    }
+
+    static public class KeyFactory
+        extends JCESecretKeyFactory
+    {
+        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);
+        }
+    }
+
+    public static class Mappings
+        extends HashMap
+    {
+        public Mappings()
+        {
+            put("Cipher.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$ECB");
+            // BEGIN android-removed
+            // put("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
+            // put("Cipher." + OIWObjectIdentifiers.desCBC, "org.bouncycastle.jce.provider.symmetric.DESede$CBC");
+            // END android-removed
+            put("Cipher.DESEDEWRAP", "org.bouncycastle.jce.provider.symmetric.DESede$Wrap");
+            // BEGIN android-changed
+            put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWRAP");
+            // END android-changed
+            // BEGIN android-removed
+            // put("Cipher.DESEDERFC3211WRAP", "org.bouncycastle.jce.provider.symmetric.DESede$RFC3211");
+            // END android-removed
+
+            put("KeyGenerator.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator");
+            // BEGIN android-removed
+            // put("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator3");
+            // put("KeyGenerator.DESEDEWRAP", "org.bouncycastle.jce.provider.symmetric.DESede$KeyGenerator");
+            // END android-removed
+
+            put("SecretKeyFactory.DESEDE", "org.bouncycastle.jce.provider.symmetric.DESede$KeyFactory");
+
+            // BEGIN android-removed
+            // put("Mac.DESEDECMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CMAC");
+            // put("Mac.DESEDEMAC", "org.bouncycastle.jce.provider.symmetric.DESede$CBCMAC");
+            // put("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
+            //
+            // put("Mac.DESEDEMAC/CFB8", "org.bouncycastle.jce.provider.symmetric.DESede$DESedeCFB8");
+            // put("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
+            //
+            // put("Mac.DESEDEMAC64", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64");
+            // put("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
+            //
+            // put("Mac.DESEDEMAC64WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.symmetric.DESede$DESede64with7816d4");
+            // put("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+            // put("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+            // put("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+            // END android-removed
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java b/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
index a5b268e..78a7a8f 100644
--- a/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
+++ b/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
@@ -13,16 +13,15 @@
             throw new IllegalArgumentException("P and Q must be on same curve");
         }
 
-        // TODO Add special case back in when WTNAF is enabled
-//        // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
-//        if (c instanceof ECCurve.F2m)
-//        {
-//            ECCurve.F2m f2mCurve = (ECCurve.F2m) c;
-//            if (f2mCurve.isKoblitz())
-//            {
-//                return P.multiply(a).add(Q.multiply(b));
-//            }
-//        }
+        // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
+        if (c instanceof ECCurve.F2m)
+        {
+            ECCurve.F2m f2mCurve = (ECCurve.F2m)c;
+            if (f2mCurve.isKoblitz())
+            {
+                return P.multiply(a).add(Q.multiply(b));
+            }
+        }
 
         return implShamirsTrick(P, a, Q, b);
     }
diff --git a/src/main/java/org/bouncycastle/math/ec/ECCurve.java b/src/main/java/org/bouncycastle/math/ec/ECCurve.java
index 4db07d5..c984104 100644
--- a/src/main/java/org/bouncycastle/math/ec/ECCurve.java
+++ b/src/main/java/org/bouncycastle/math/ec/ECCurve.java
@@ -80,6 +80,10 @@
             {
                 // infinity
             case 0x00:
+                if (encoded.length > 1)
+                {
+                    throw new RuntimeException("Invalid point encoding");
+                }
                 p = getInfinity();
                 break;
                 // compressed
@@ -410,6 +414,10 @@
             {
                 // infinity
             case 0x00:
+                if (encoded.length > 1)
+                {
+                    throw new RuntimeException("Invalid point encoding");
+                }
                 p = getInfinity();
                 break;
                 // compressed
diff --git a/src/main/java/org/bouncycastle/math/ec/ECPoint.java b/src/main/java/org/bouncycastle/math/ec/ECPoint.java
index 2d38ee4..b14e4c1 100644
--- a/src/main/java/org/bouncycastle/math/ec/ECPoint.java
+++ b/src/main/java/org/bouncycastle/math/ec/ECPoint.java
@@ -133,6 +133,11 @@
      */
     public ECPoint multiply(BigInteger k)
     {
+        if (k.signum() < 0)
+        {
+            throw new IllegalArgumentException("The multiplicator cannot be negative");
+        }
+
         if (this.isInfinity())
         {
             return this;
@@ -309,17 +314,16 @@
             return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);
         }
 
-        // TODO Uncomment this to enable WNAF algorithm for Fp point multiplication
-//        /**
-//         * Sets the default <code>ECMultiplier</code>, unless already set. 
-//         */
-//        synchronized void assertECMultiplier()
-//        {
-//            if (this.multiplier == null)
-//            {
-//                this.multiplier = new WNafMultiplier();
-//            }
-//        }
+        /**
+         * Sets the default <code>ECMultiplier</code>, unless already set. 
+         */
+        synchronized void assertECMultiplier()
+        {
+            if (this.multiplier == null)
+            {
+                this.multiplier = new WNafMultiplier();
+            }
+        }
     }
 
     /**
@@ -367,15 +371,6 @@
             this.withCompression = withCompression;
         }
 
-        /**
-         * @deprecated use ECCurve.getInfinity()
-         * Constructor for point at infinity
-         */
-        public F2m(ECCurve curve)
-        {
-            super(curve, null, null);
-        }
-
         /* (non-Javadoc)
          * @see org.bouncycastle.math.ec.ECPoint#getEncoded()
          */
@@ -572,23 +567,22 @@
             return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression);
         }
 
-        // TODO Uncomment this to enable WNAF/WTNAF F2m point multiplication
-//        /**
-//         * Sets the appropriate <code>ECMultiplier</code>, unless already set. 
-//         */
-//        synchronized void assertECMultiplier()
-//        {
-//            if (this.multiplier == null)
-//            {
-//                if (((ECCurve.F2m)(this.curve)).isKoblitz())
-//                {
-//                    this.multiplier = new WTauNafMultiplier();
-//                }
-//                else
-//                {
-//                    this.multiplier = new WNafMultiplier();
-//                }
-//            }
-//        }
+        /**
+         * Sets the appropriate <code>ECMultiplier</code>, unless already set. 
+         */
+        synchronized void assertECMultiplier()
+        {
+            if (this.multiplier == null)
+            {
+                if (((ECCurve.F2m)this.curve).isKoblitz())
+                {
+                    this.multiplier = new WTauNafMultiplier();
+                }
+                else
+                {
+                    this.multiplier = new WNafMultiplier();
+                }
+            }
+        }
     }
 }
diff --git a/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java b/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java
new file mode 100644
index 0000000..10c8ed2
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java
@@ -0,0 +1,240 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the WNAF (Window Non-Adjacent Form) multiplication
+ * algorithm.
+ */
+class WNafMultiplier implements ECMultiplier
+{
+    /**
+     * 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 byte[] windowNaf(byte width, BigInteger k)
+    {
+        // The window NAF is at most 1 element longer than the binary
+        // representation of the integer k. byte can be used instead of short or
+        // int unless the window width is larger than 8. For larger width use
+        // short or int. However, a width of more than 8 is not efficient for
+        // m = log2(q) smaller than 2305 Bits. Note: Values for m larger than
+        // 1000 Bits are currently not used in practice.
+        byte[] wnaf = new byte[k.bitLength() + 1];
+
+        // 2^width as short and BigInteger
+        short pow2wB = (short)(1 << width);
+        BigInteger pow2wBI = BigInteger.valueOf(pow2wB);
+
+        int i = 0;
+
+        // The actual length of the WNAF
+        int length = 0;
+
+        // while k >= 1
+        while (k.signum() > 0)
+        {
+            // if k is odd
+            if (k.testBit(0))
+            {
+                // k mod 2^width
+                BigInteger remainder = k.mod(pow2wBI);
+
+                // if remainder > 2^(width - 1) - 1
+                if (remainder.testBit(width - 1))
+                {
+                    wnaf[i] = (byte)(remainder.intValue() - pow2wB);
+                }
+                else
+                {
+                    wnaf[i] = (byte)remainder.intValue();
+                }
+                // wnaf[i] is now in [-2^(width-1), 2^(width-1)-1]
+
+                k = k.subtract(BigInteger.valueOf(wnaf[i]));
+                length = i;
+            }
+            else
+            {
+                wnaf[i] = 0;
+            }
+
+            // k = k/2
+            k = k.shiftRight(1);
+            i++;
+        }
+
+        length++;
+
+        // Reduce the WNAF array to its actual length
+        byte[] wnafShort = new byte[length];
+        System.arraycopy(wnaf, 0, wnafShort, 0, length);
+        return wnafShort;
+    }
+
+    /**
+     * 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>.
+     */
+    public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+    {
+        WNafPreCompInfo wnafPreCompInfo;
+
+        if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo))
+        {
+            wnafPreCompInfo = (WNafPreCompInfo)preCompInfo;
+        }
+        else
+        {
+            // Ignore empty PreCompInfo or PreCompInfo of incorrect type
+            wnafPreCompInfo = new WNafPreCompInfo();
+        }
+
+        // floor(log2(k))
+        int m = k.bitLength();
+
+        // width of the Window NAF
+        byte width;
+
+        // Required length of precomputation array
+        int reqPreCompLen;
+
+        // Determine optimal width and corresponding length of precomputation
+        // array based on literature values
+        if (m < 13)
+        {
+            width = 2;
+            reqPreCompLen = 1;
+        }
+        else
+        {
+            if (m < 41)
+            {
+                width = 3;
+                reqPreCompLen = 2;
+            }
+            else
+            {
+                if (m < 121)
+                {
+                    width = 4;
+                    reqPreCompLen = 4;
+                }
+                else
+                {
+                    if (m < 337)
+                    {
+                        width = 5;
+                        reqPreCompLen = 8;
+                    }
+                    else
+                    {
+                        if (m < 897)
+                        {
+                            width = 6;
+                            reqPreCompLen = 16;
+                        }
+                        else
+                        {
+                            if (m < 2305)
+                            {
+                                width = 7;
+                                reqPreCompLen = 32;
+                            }
+                            else
+                            {
+                                width = 8;
+                                reqPreCompLen = 127;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // The length of the precomputation array
+        int preCompLen = 1;
+
+        ECPoint[] preComp = wnafPreCompInfo.getPreComp();
+        ECPoint twiceP = wnafPreCompInfo.getTwiceP();
+
+        // Check if the precomputed ECPoints already exist
+        if (preComp == null)
+        {
+            // Precomputation must be performed from scratch, create an empty
+            // precomputation array of desired length
+            preComp = new ECPoint[]{ p };
+        }
+        else
+        {
+            // Take the already precomputed ECPoints to start with
+            preCompLen = preComp.length;
+        }
+
+        if (twiceP == null)
+        {
+            // Compute twice(p)
+            twiceP = p.twice();
+        }
+
+        if (preCompLen < reqPreCompLen)
+        {
+            // Precomputation array must be made bigger, copy existing preComp
+            // array into the larger new preComp array
+            ECPoint[] oldPreComp = preComp;
+            preComp = new ECPoint[reqPreCompLen];
+            System.arraycopy(oldPreComp, 0, preComp, 0, preCompLen);
+
+            for (int i = preCompLen; i < reqPreCompLen; i++)
+            {
+                // Compute the new ECPoints for the precomputation array.
+                // The values 1, 3, 5, ..., 2^(width-1)-1 times p are
+                // computed
+                preComp[i] = twiceP.add(preComp[i - 1]);
+            }            
+        }
+
+        // Compute the Window NAF of the desired width
+        byte[] wnaf = windowNaf(width, k);
+        int l = wnaf.length;
+
+        // Apply the Window NAF to p using the precomputed ECPoint values.
+        ECPoint q = p.getCurve().getInfinity();
+        for (int i = l - 1; i >= 0; i--)
+        {
+            q = q.twice();
+
+            if (wnaf[i] != 0)
+            {
+                if (wnaf[i] > 0)
+                {
+                    q = q.add(preComp[(wnaf[i] - 1)/2]);
+                }
+                else
+                {
+                    // wnaf[i] < 0
+                    q = q.subtract(preComp[(-wnaf[i] - 1)/2]);
+                }
+            }
+        }
+
+        // Set PreCompInfo in ECPoint, such that it is available for next
+        // multiplication.
+        wnafPreCompInfo.setPreComp(preComp);
+        wnafPreCompInfo.setTwiceP(twiceP);
+        p.setPreCompInfo(wnafPreCompInfo);
+        return q;
+    }
+
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java b/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java
new file mode 100644
index 0000000..fc0d5fe
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java
@@ -0,0 +1,44 @@
+package org.bouncycastle.math.ec;
+
+/**
+ * Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
+ * algorithm.
+ */
+class WNafPreCompInfo implements PreCompInfo
+{
+    /**
+     * Array holding the precomputed <code>ECPoint</code>s used for the Window
+     * NAF multiplication in <code>
+     * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()
+     * WNafMultiplier.multiply()}</code>.
+     */
+    private ECPoint[] preComp = null;
+
+    /**
+     * Holds an <code>ECPoint</code> representing twice(this). Used for the
+     * Window NAF multiplication in <code>
+     * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()
+     * WNafMultiplier.multiply()}</code>.
+     */
+    private ECPoint twiceP = null;
+
+    protected ECPoint[] getPreComp()
+    {
+        return preComp;
+    }
+
+    protected void setPreComp(ECPoint[] preComp)
+    {
+        this.preComp = preComp;
+    }
+
+    protected ECPoint getTwiceP()
+    {
+        return twiceP;
+    }
+
+    protected void setTwiceP(ECPoint twiceThis)
+    {
+        this.twiceP = twiceThis;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java b/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java
new file mode 100644
index 0000000..2353979
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java
@@ -0,0 +1,119 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the WTNAF (Window
+ * <code>&tau;</code>-adic Non-Adjacent Form) algorithm.
+ */
+class WTauNafMultiplier implements ECMultiplier
+{
+    /**
+     * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+     * by <code>k</code> using the reduced <code>&tau;</code>-adic NAF (RTNAF)
+     * method.
+     * @param p The ECPoint.F2m to multiply.
+     * @param k The integer by which to multiply <code>k</code>.
+     * @return <code>p</code> multiplied by <code>k</code>.
+     */
+    public ECPoint multiply(ECPoint point, BigInteger k, PreCompInfo preCompInfo)
+    {
+        if (!(point instanceof ECPoint.F2m))
+        {
+            throw new IllegalArgumentException("Only ECPoint.F2m can be " +
+                    "used in WTauNafMultiplier");
+        }
+
+        ECPoint.F2m p = (ECPoint.F2m)point;
+
+        ECCurve.F2m curve = (ECCurve.F2m) p.getCurve();
+        int m = curve.getM();
+        byte a = curve.getA().toBigInteger().byteValue();
+        byte mu = curve.getMu();
+        BigInteger[] s = curve.getSi();
+
+        ZTauElement rho = Tnaf.partModReduction(k, m, a, s, mu, (byte)10);
+
+        return multiplyWTnaf(p, rho, preCompInfo, a, mu);
+    }
+
+    /**
+     * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+     * 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.F2m 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.F2m multiplyWTnaf(ECPoint.F2m p, ZTauElement lambda,
+            PreCompInfo preCompInfo, byte a, byte mu)
+    {
+        ZTauElement[] alpha;
+        if (a == 0)
+        {
+            alpha = Tnaf.alpha0;
+        }
+        else
+        {
+            // a == 1
+            alpha = 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, preCompInfo);
+    }
+
+    /**
+     * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+     * 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.F2m to multiply.
+     * @param u The the WTNAF of <code>&lambda;</code>..
+     * @return <code>&lambda; * p</code>
+     */
+    private static ECPoint.F2m multiplyFromWTnaf(ECPoint.F2m p, byte[] u,
+            PreCompInfo preCompInfo)
+    {
+        ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
+        byte a = curve.getA().toBigInteger().byteValue();
+
+        ECPoint.F2m[] pu;
+        if ((preCompInfo == null) || !(preCompInfo instanceof WTauNafPreCompInfo))
+        {
+            pu = Tnaf.getPreComp(p, a);
+            p.setPreCompInfo(new WTauNafPreCompInfo(pu));
+        }
+        else
+        {
+            pu = ((WTauNafPreCompInfo)preCompInfo).getPreComp();
+        }
+
+        // q = infinity
+        ECPoint.F2m q = (ECPoint.F2m) p.getCurve().getInfinity();
+        for (int i = u.length - 1; i >= 0; i--)
+        {
+            q = Tnaf.tau(q);
+            if (u[i] != 0)
+            {
+                if (u[i] > 0)
+                {
+                    q = q.addSimple(pu[u[i]]);
+                }
+                else
+                {
+                    // u[i] < 0
+                    q = q.subtractSimple(pu[-u[i]]);
+                }
+            }
+        }
+
+        return q;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/math/ec/WTauNafPreCompInfo.java b/src/main/java/org/bouncycastle/math/ec/WTauNafPreCompInfo.java
new file mode 100644
index 0000000..d7c583f
--- /dev/null
+++ b/src/main/java/org/bouncycastle/math/ec/WTauNafPreCompInfo.java
@@ -0,0 +1,39 @@
+package org.bouncycastle.math.ec;
+
+/**
+ * Class holding precomputation data for the WTNAF (Window
+ * <code>&tau;</code>-adic Non-Adjacent Form) algorithm.
+ */
+class WTauNafPreCompInfo implements PreCompInfo
+{
+    /**
+     * Array holding the precomputed <code>ECPoint.F2m</code>s used for the
+     * WTNAF multiplication in <code>
+     * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+     * WTauNafMultiplier.multiply()}</code>.
+     */
+    private ECPoint.F2m[] preComp = null;
+
+    /**
+     * Constructor for <code>WTauNafPreCompInfo</code>
+     * @param preComp Array holding the precomputed <code>ECPoint.F2m</code>s
+     * used for the WTNAF multiplication in <code>
+     * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+     * WTauNafMultiplier.multiply()}</code>.
+     */
+    WTauNafPreCompInfo(ECPoint.F2m[] preComp)
+    {
+        this.preComp = preComp;
+    }
+
+    /**
+     * @return the array holding the precomputed <code>ECPoint.F2m</code>s
+     * used for the WTNAF multiplication in <code>
+     * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+     * WTauNafMultiplier.multiply()}</code>.
+     */
+    protected ECPoint.F2m[] getPreComp()
+    {
+        return preComp;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java b/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java
new file mode 100644
index 0000000..5793007
--- /dev/null
+++ b/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java
@@ -0,0 +1,335 @@
+package org.bouncycastle.openssl;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.cms.ContentInfo;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.jce.PKCS10CertificationRequest;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.io.pem.PemGenerationException;
+import org.bouncycastle.util.io.pem.PemHeader;
+import org.bouncycastle.util.io.pem.PemObject;
+import org.bouncycastle.util.io.pem.PemObjectGenerator;
+import org.bouncycastle.x509.X509AttributeCertificate;
+import org.bouncycastle.x509.X509V2AttributeCertificate;
+
+/**
+ * PEM generator for the original set of PEM objects used in Open SSL.
+ */
+public class MiscPEMGenerator
+    implements PemObjectGenerator
+{
+    private Object obj;
+    private String algorithm;
+    private char[] password;
+    private SecureRandom random;
+    private Provider provider;
+
+    public MiscPEMGenerator(Object o)
+    {
+        this.obj = o;
+    }
+
+    public MiscPEMGenerator(
+        Object       obj,
+        String       algorithm,
+        char[]       password,
+        SecureRandom random,
+        Provider     provider)
+    {
+        this.obj = obj;
+        this.algorithm = algorithm;
+        this.password = password;
+        this.random = random;
+        this.provider = provider;
+    }
+
+    public MiscPEMGenerator(
+        Object       obj,
+        String       algorithm,
+        char[]       password,
+        SecureRandom random,
+        String       provider)
+        throws NoSuchProviderException
+    {
+        this.obj = obj;
+        this.algorithm = algorithm;
+        this.password = password;
+        this.random = random;
+
+        if (provider != null)
+        {
+            this.provider = Security.getProvider(provider);
+            if (this.provider == null)
+            {
+                throw new NoSuchProviderException("cannot find provider: " + provider);
+            }
+        }
+    }
+
+    private PemObject createPemObject(Object o)
+        throws IOException
+    {
+        String  type;
+        byte[]  encoding;
+
+        if (o instanceof PemObject)
+        {
+            return (PemObject)o;
+        }
+        if (o instanceof PemObjectGenerator)
+        {
+            return ((PemObjectGenerator)o).generate();
+        }
+        if (o instanceof X509Certificate)
+        {
+            type = "CERTIFICATE";
+            try
+            {
+                encoding = ((X509Certificate)o).getEncoded();
+            }
+            catch (CertificateEncodingException e)
+            {
+                throw new PemGenerationException("Cannot encode object: " + e.toString());
+            }
+        }
+        else if (o instanceof X509CRL)
+        {
+            type = "X509 CRL";
+            try
+            {
+                encoding = ((X509CRL)o).getEncoded();
+            }
+            catch (CRLException e)
+            {
+                throw new PemGenerationException("Cannot encode object: " + e.toString());
+            }
+        }
+        else if (o instanceof KeyPair)
+        {
+            return createPemObject(((KeyPair)o).getPrivate());
+        }
+        else if (o instanceof PrivateKey)
+        {
+            PrivateKeyInfo info = new PrivateKeyInfo(
+                (ASN1Sequence) ASN1Object.fromByteArray(((Key)o).getEncoded()));
+
+            if (o instanceof RSAPrivateKey)
+            {
+                type = "RSA PRIVATE KEY";
+
+                encoding = info.getPrivateKey().getEncoded();
+            }
+            else if (o instanceof DSAPrivateKey)
+            {
+                type = "DSA PRIVATE KEY";
+
+                DSAParameter p = DSAParameter.getInstance(info.getAlgorithmId().getParameters());
+                ASN1EncodableVector v = new ASN1EncodableVector();
+
+                v.add(new DERInteger(0));
+                v.add(new DERInteger(p.getP()));
+                v.add(new DERInteger(p.getQ()));
+                v.add(new DERInteger(p.getG()));
+
+                BigInteger x = ((DSAPrivateKey)o).getX();
+                BigInteger y = p.getG().modPow(x, p.getP());
+
+                v.add(new DERInteger(y));
+                v.add(new DERInteger(x));
+
+                encoding = new DERSequence(v).getEncoded();
+            }
+            else if (((PrivateKey)o).getAlgorithm().equals("ECDSA"))
+            {
+                type = "EC PRIVATE KEY";
+
+                encoding = info.getPrivateKey().getEncoded();
+            }
+            else
+            {
+                throw new IOException("Cannot identify private key");
+            }
+        }
+        else if (o instanceof PublicKey)
+        {
+            type = "PUBLIC KEY";
+
+            encoding = ((PublicKey)o).getEncoded();
+        }
+        else if (o instanceof X509AttributeCertificate)
+        {
+            type = "ATTRIBUTE CERTIFICATE";
+            encoding = ((X509V2AttributeCertificate)o).getEncoded();
+        }
+        else if (o instanceof PKCS10CertificationRequest)
+        {
+            type = "CERTIFICATE REQUEST";
+            encoding = ((PKCS10CertificationRequest)o).getEncoded();
+        }
+        else if (o instanceof ContentInfo)
+        {
+            type = "PKCS7";
+            encoding = ((ContentInfo)o).getEncoded();
+        }
+        else
+        {
+            throw new PemGenerationException("unknown object passed - can't encode.");
+        }
+
+        return new PemObject(type, encoding);
+    }
+
+    private String getHexEncoded(byte[] bytes)
+        throws IOException
+    {
+        bytes = Hex.encode(bytes);
+
+        char[] chars = new char[bytes.length];
+
+        for (int i = 0; i != bytes.length; i++)
+        {
+            chars[i] = (char)bytes[i];
+        }
+
+        return new String(chars);
+    }
+
+    private PemObject createPemObject(
+        Object       obj,
+        String       algorithm,
+        char[]       password,
+        SecureRandom random)
+        throws IOException
+    {
+        if (obj instanceof KeyPair)
+        {
+            return createPemObject(((KeyPair)obj).getPrivate(), algorithm, password, random);
+        }
+
+        String type = null;
+        byte[] keyData = null;
+
+        if (obj instanceof RSAPrivateCrtKey)
+        {
+            type = "RSA PRIVATE KEY";
+
+            RSAPrivateCrtKey k = (RSAPrivateCrtKey)obj;
+
+            RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure(
+                k.getModulus(),
+                k.getPublicExponent(),
+                k.getPrivateExponent(),
+                k.getPrimeP(),
+                k.getPrimeQ(),
+                k.getPrimeExponentP(),
+                k.getPrimeExponentQ(),
+                k.getCrtCoefficient());
+
+            // convert to bytearray
+            keyData = keyStruct.getEncoded();
+        }
+        else if (obj instanceof DSAPrivateKey)
+        {
+            type = "DSA PRIVATE KEY";
+
+            DSAPrivateKey       k = (DSAPrivateKey)obj;
+            DSAParams p = k.getParams();
+            ASN1EncodableVector v = new ASN1EncodableVector();
+
+            v.add(new DERInteger(0));
+            v.add(new DERInteger(p.getP()));
+            v.add(new DERInteger(p.getQ()));
+            v.add(new DERInteger(p.getG()));
+
+            BigInteger x = k.getX();
+            BigInteger y = p.getG().modPow(x, p.getP());
+
+            v.add(new DERInteger(y));
+            v.add(new DERInteger(x));
+
+            keyData = new DERSequence(v).getEncoded();
+        }
+        else if (obj instanceof PrivateKey && "ECDSA".equals(((PrivateKey)obj).getAlgorithm()))
+        {
+            type = "EC PRIVATE KEY";
+
+            PrivateKeyInfo      privInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(((PrivateKey)obj).getEncoded()));
+
+            keyData = privInfo.getPrivateKey().getEncoded();
+        }
+
+        if (type == null || keyData == null)
+        {
+            // TODO Support other types?
+            throw new IllegalArgumentException("Object type not supported: " + obj.getClass().getName());
+        }
+
+        String dekAlgName = Strings.toUpperCase(algorithm);
+
+        // Note: For backward compatibility
+        if (dekAlgName.equals("DESEDE"))
+        {
+            dekAlgName = "DES-EDE3-CBC";
+        }
+
+        int ivLength = dekAlgName.startsWith("AES-") ? 16 : 8;
+
+        byte[] iv = new byte[ivLength];
+        random.nextBytes(iv);
+
+        byte[] encData = PEMUtilities.crypt(true, provider, keyData, password, dekAlgName, iv);
+
+        List headers = new ArrayList(2);
+
+        headers.add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
+        headers.add(new PemHeader("DEK-Info", dekAlgName + "," + getHexEncoded(iv)));
+
+        return new PemObject(type, headers, encData);
+    }
+
+    public PemObject generate()
+        throws PemGenerationException
+    {
+        try
+        {
+            if (algorithm != null)
+            {
+                return createPemObject(obj, algorithm, password, random);
+            }
+
+            return createPemObject(obj);
+        }
+        catch (IOException e)
+        {
+            throw new PemGenerationException("encoding exception: " + e.getMessage(), e);
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/openssl/PEMException.java b/src/main/java/org/bouncycastle/openssl/PEMException.java
new file mode 100644
index 0000000..3753aec
--- /dev/null
+++ b/src/main/java/org/bouncycastle/openssl/PEMException.java
@@ -0,0 +1,34 @@
+package org.bouncycastle.openssl;
+
+import java.io.IOException;
+
+public class PEMException
+    extends IOException
+{
+    Exception    underlying;
+
+    public PEMException(
+        String    message)
+    {
+        super(message);
+    }
+
+    public PEMException(
+        String        message,
+        Exception    underlying)
+    {
+        super(message);
+        this.underlying = underlying;
+    }
+
+    public Exception getUnderlyingException()
+    {
+        return underlying;
+    }
+
+
+    public Throwable getCause()
+    {
+        return underlying;
+    }
+}
diff --git a/src/main/java/org/bouncycastle/openssl/PEMReader.java b/src/main/java/org/bouncycastle/openssl/PEMReader.java
new file mode 100644
index 0000000..92bf8f9
--- /dev/null
+++ b/src/main/java/org/bouncycastle/openssl/PEMReader.java
@@ -0,0 +1,804 @@
+package org.bouncycastle.openssl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.cert.CertificateFactory;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.cms.ContentInfo;
+import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.EncryptionScheme;
+import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
+import org.bouncycastle.asn1.pkcs.PBEParameter;
+import org.bouncycastle.asn1.pkcs.PBES2Parameters;
+import org.bouncycastle.asn1.pkcs.PBKDF2Params;
+import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jce.ECNamedCurveTable;
+import org.bouncycastle.jce.PKCS10CertificationRequest;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.io.pem.PemHeader;
+import org.bouncycastle.util.io.pem.PemObject;
+import org.bouncycastle.util.io.pem.PemObjectParser;
+import org.bouncycastle.util.io.pem.PemReader;
+import org.bouncycastle.x509.X509V2AttributeCertificate;
+
+/**
+ * Class for reading OpenSSL PEM encoded streams containing
+ * X509 certificates, PKCS8 encoded keys and PKCS7 objects.
+ * <p>
+ * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Keys and
+ * Certificates will be returned using the appropriate java.security type (KeyPair, PublicKey, X509Certificate,
+ * or X509CRL). In the case of a Certificate Request a PKCS10CertificationRequest will be returned.
+ * </p>
+ */
+public class PEMReader
+    extends PemReader
+{
+    private final Map parsers = new HashMap();
+
+    private PasswordFinder pFinder;
+
+
+    /**
+     * Create a new PEMReader
+     *
+     * @param reader the Reader
+     */
+    public PEMReader(
+        Reader reader)
+    {
+        this(reader, null, "BC");
+    }
+
+    /**
+     * Create a new PEMReader with a password finder
+     *
+     * @param reader  the Reader
+     * @param pFinder the password finder
+     */
+    public PEMReader(
+        Reader reader,
+        PasswordFinder pFinder)
+    {
+        this(reader, pFinder, "BC");
+    }
+
+    /**
+     * Create a new PEMReader with a password finder
+     *
+     * @param reader   the Reader
+     * @param pFinder  the password finder
+     * @param provider the cryptography provider to use
+     */
+    public PEMReader(
+        Reader reader,
+        PasswordFinder pFinder,
+        String provider)
+    {
+        this(reader, pFinder, provider, provider);
+    }
+
+    /**
+     * Create a new PEMReader with a password finder and differing providers for secret and public key
+     * operations.
+     *
+     * @param reader   the Reader
+     * @param pFinder  the password finder
+     * @param symProvider  provider to use for symmetric operations
+     * @param asymProvider provider to use for asymmetric (public/private key) operations
+     */
+    public PEMReader(
+        Reader reader,
+        PasswordFinder pFinder,
+        String symProvider,
+        String asymProvider)
+    {
+        super(reader);
+
+        this.pFinder = pFinder;
+
+        parsers.put("CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
+        parsers.put("NEW CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
+        parsers.put("CERTIFICATE", new X509CertificateParser(asymProvider));
+        parsers.put("X509 CERTIFICATE", new X509CertificateParser(asymProvider));
+        parsers.put("X509 CRL", new X509CRLParser(asymProvider));
+        parsers.put("PKCS7", new PKCS7Parser());
+        parsers.put("ATTRIBUTE CERTIFICATE", new X509AttributeCertificateParser());
+        parsers.put("EC PARAMETERS", new ECNamedCurveSpecParser());
+        parsers.put("PUBLIC KEY", new PublicKeyParser(asymProvider));
+        parsers.put("RSA PUBLIC KEY", new RSAPublicKeyParser(asymProvider));
+        parsers.put("RSA PRIVATE KEY", new RSAKeyPairParser(asymProvider));
+        parsers.put("DSA PRIVATE KEY", new DSAKeyPairParser(asymProvider));
+        parsers.put("EC PRIVATE KEY", new ECDSAKeyPairParser(asymProvider));
+        parsers.put("ENCRYPTED PRIVATE KEY", new EncryptedPrivateKeyParser(symProvider, asymProvider));
+        parsers.put("PRIVATE KEY", new PrivateKeyParser(asymProvider));
+    }
+
+    public Object readObject()
+        throws IOException
+    {
+        PemObject obj = readPemObject();
+
+        if (obj != null)
+        {
+            String type = obj.getType();
+            if (parsers.containsKey(type))
+            {
+                return ((PemObjectParser)parsers.get(type)).parseObject(obj);
+            }
+            else
+            {
+                throw new IOException("unrecognised object: " + type);
+            }
+        }
+
+        return null;
+    }
+
+    private abstract class KeyPairParser
+        implements PemObjectParser
+    {
+        protected String provider;
+
+        public KeyPairParser(String provider)
+        {
+            this.provider = provider;
+        }
+
+        /**
+         * Read a Key Pair
+         */
+        protected ASN1Sequence readKeyPair(
+            PemObject obj)
+            throws IOException
+        {
+            boolean isEncrypted = false;
+            String dekInfo = null;
+            List headers = obj.getHeaders();
+
+            for (Iterator it = headers.iterator(); it.hasNext();)
+            {
+                PemHeader hdr = (PemHeader)it.next();
+
+                if (hdr.getName().equals("Proc-Type") && hdr.getValue().equals("4,ENCRYPTED"))
+                {
+                    isEncrypted = true;
+                }
+                else if (hdr.getName().equals("DEK-Info"))
+                {
+                    dekInfo = hdr.getValue();
+                }
+            }
+
+            //
+            // extract the key
+            //
+            byte[] keyBytes = obj.getContent();
+
+            if (isEncrypted)
+            {
+                if (pFinder == null)
+                {
+                    throw new PasswordException("No password finder specified, but a password is required");
+                }
+
+                char[] password = pFinder.getPassword();
+
+                if (password == null)
+                {
+                    throw new PasswordException("Password is null, but a password is required");
+                }
+
+                StringTokenizer tknz = new StringTokenizer(dekInfo, ",");
+                String dekAlgName = tknz.nextToken();
+                byte[] iv = Hex.decode(tknz.nextToken());
+
+                keyBytes = PEMUtilities.crypt(false, provider, keyBytes, password, dekAlgName, iv);
+            }
+
+            try
+            {
+                return (ASN1Sequence)ASN1Object.fromByteArray(keyBytes);
+            }
+            catch (IOException e)
+            {
+                if (isEncrypted)
+                {
+                    throw new PEMException("exception decoding - please check password and data.", e);
+                }
+                else
+                {
+                    throw new PEMException(e.getMessage(), e);
+                }
+            }
+            catch (ClassCastException e)
+            {
+                if (isEncrypted)
+                {
+                    throw new PEMException("exception decoding - please check password and data.", e);
+                }
+                else
+                {
+                    throw new PEMException(e.getMessage(), e);
+                }
+            }
+        }
+    }
+
+    private class DSAKeyPairParser
+        extends KeyPairParser
+    {
+        public DSAKeyPairParser(String provider)
+        {
+            super(provider);
+        }
+
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            try
+            {
+                ASN1Sequence seq = readKeyPair(obj);
+
+                if (seq.size() != 6)
+                {
+                    throw new PEMException("malformed sequence in DSA private key");
+                }
+
+                //            DERInteger              v = (DERInteger)seq.getObjectAt(0);
+                DERInteger p = (DERInteger)seq.getObjectAt(1);
+                DERInteger q = (DERInteger)seq.getObjectAt(2);
+                DERInteger g = (DERInteger)seq.getObjectAt(3);
+                DERInteger y = (DERInteger)seq.getObjectAt(4);
+                DERInteger x = (DERInteger)seq.getObjectAt(5);
+
+                DSAPrivateKeySpec privSpec = new DSAPrivateKeySpec(
+                    x.getValue(), p.getValue(),
+                    q.getValue(), g.getValue());
+                DSAPublicKeySpec pubSpec = new DSAPublicKeySpec(
+                    y.getValue(), p.getValue(),
+                    q.getValue(), g.getValue());
+
+                KeyFactory fact = KeyFactory.getInstance("DSA", provider);
+
+                return new KeyPair(
+                    fact.generatePublic(pubSpec),
+                    fact.generatePrivate(privSpec));
+            }
+            catch (IOException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PEMException(
+                    "problem creating DSA private key: " + e.toString(), e);
+            }
+        }
+    }
+
+    private class ECDSAKeyPairParser
+        extends KeyPairParser
+    {
+        public ECDSAKeyPairParser(String provider)
+        {
+            super(provider);
+        }
+
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            try
+            {
+                ASN1Sequence seq = readKeyPair(obj);
+
+                ECPrivateKeyStructure pKey = new ECPrivateKeyStructure(seq);
+                AlgorithmIdentifier algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParameters());
+                PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.getDERObject());
+                SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.getPublicKey().getBytes());
+
+                PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privInfo.getEncoded());
+                X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded());
+
+
+                KeyFactory fact = KeyFactory.getInstance("ECDSA", provider);
+
+
+                return new KeyPair(
+                    fact.generatePublic(pubSpec),
+                    fact.generatePrivate(privSpec));
+            }
+            catch (IOException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PEMException(
+                    "problem creating EC private key: " + e.toString(), e);
+            }
+        }
+    }
+
+    private class RSAKeyPairParser
+        extends KeyPairParser
+    {
+        public RSAKeyPairParser(String provider)
+        {
+            super(provider);
+        }
+
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            try
+            {
+                ASN1Sequence seq = readKeyPair(obj);
+
+                if (seq.size() != 9)
+                {
+                    throw new PEMException("malformed sequence in RSA private key");
+                }
+
+                //            DERInteger              v = (DERInteger)seq.getObjectAt(0);
+                DERInteger mod = (DERInteger)seq.getObjectAt(1);
+                DERInteger pubExp = (DERInteger)seq.getObjectAt(2);
+                DERInteger privExp = (DERInteger)seq.getObjectAt(3);
+                DERInteger p1 = (DERInteger)seq.getObjectAt(4);
+                DERInteger p2 = (DERInteger)seq.getObjectAt(5);
+                DERInteger exp1 = (DERInteger)seq.getObjectAt(6);
+                DERInteger exp2 = (DERInteger)seq.getObjectAt(7);
+                DERInteger crtCoef = (DERInteger)seq.getObjectAt(8);
+
+                RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(
+                    mod.getValue(), pubExp.getValue());
+                RSAPrivateCrtKeySpec privSpec = new RSAPrivateCrtKeySpec(
+                    mod.getValue(), pubExp.getValue(), privExp.getValue(),
+                    p1.getValue(), p2.getValue(),
+                    exp1.getValue(), exp2.getValue(),
+                    crtCoef.getValue());
+
+
+                KeyFactory fact = KeyFactory.getInstance("RSA", provider);
+
+
+                return new KeyPair(
+                    fact.generatePublic(pubSpec),
+                    fact.generatePrivate(privSpec));
+            }
+            catch (IOException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PEMException(
+                    "problem creating RSA private key: " + e.toString(), e);
+            }
+        }
+    }
+
+    private class PublicKeyParser
+        implements PemObjectParser
+    {
+        private String provider;
+
+        public PublicKeyParser(String provider)
+        {
+            this.provider = provider;
+        }
+
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            KeySpec keySpec = new X509EncodedKeySpec(obj.getContent());
+            String[] algorithms = {"DSA", "RSA"};
+            for (int i = 0; i < algorithms.length; i++)
+            {
+                try
+                {
+                    KeyFactory keyFact = KeyFactory.getInstance(algorithms[i], provider);
+                    PublicKey pubKey = keyFact.generatePublic(keySpec);
+
+                    return pubKey;
+                }
+                catch (NoSuchAlgorithmException e)
+                {
+                    // ignore
+                }
+                catch (InvalidKeySpecException e)
+                {
+                    // ignore
+                }
+                catch (NoSuchProviderException e)
+                {
+                    throw new RuntimeException("can't find provider " + provider);
+                }
+            }
+
+            return null;
+        }
+    }
+
+    private class RSAPublicKeyParser
+        implements PemObjectParser
+    {
+        private String provider;
+
+        public RSAPublicKeyParser(String provider)
+        {
+            this.provider = provider;
+        }
+
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            try
+            {
+                ASN1InputStream ais = new ASN1InputStream(obj.getContent());
+                Object asnObject = ais.readObject();
+                ASN1Sequence sequence = (ASN1Sequence)asnObject;
+                RSAPublicKeyStructure rsaPubStructure = new RSAPublicKeyStructure(sequence);
+                RSAPublicKeySpec keySpec = new RSAPublicKeySpec(
+                    rsaPubStructure.getModulus(),
+                    rsaPubStructure.getPublicExponent());
+
+
+                    KeyFactory keyFact = KeyFactory.getInstance("RSA", provider);
+
+                    return keyFact.generatePublic(keySpec);
+            }
+            catch (IOException e)
+            {
+                throw e;
+            }
+            catch (NoSuchProviderException e)
+            {
+                throw new IOException("can't find provider " + provider);
+            }
+            catch (Exception e)
+            {
+                throw new PEMException("problem extracting key: " + e.toString(), e);
+            }
+        }
+    }
+
+    private class X509CertificateParser
+        implements PemObjectParser
+    {
+        private String provider;
+
+        public X509CertificateParser(String provider)
+        {
+            this.provider = provider;
+        }
+
+        /**
+         * Reads in a X509Certificate.
+         *
+         * @return the X509Certificate
+         * @throws IOException if an I/O error occured
+         */
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            ByteArrayInputStream bIn = new ByteArrayInputStream(obj.getContent());
+
+            try
+            {
+                CertificateFactory certFact
+                    = CertificateFactory.getInstance("X.509", provider);
+
+                return certFact.generateCertificate(bIn);
+            }
+            catch (Exception e)
+            {
+                throw new PEMException("problem parsing cert: " + e.toString(), e);
+            }
+        }
+    }
+
+    private class X509CRLParser
+        implements PemObjectParser
+    {
+        private String provider;
+
+        public X509CRLParser(String provider)
+        {
+            this.provider = provider;
+        }
+
+        /**
+         * Reads in a X509CRL.
+         *
+         * @return the X509Certificate
+         * @throws IOException if an I/O error occured
+         */
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            ByteArrayInputStream bIn = new ByteArrayInputStream(obj.getContent());
+
+            try
+            {
+                CertificateFactory certFact
+                    = CertificateFactory.getInstance("X.509", provider);
+
+                return certFact.generateCRL(bIn);
+            }
+            catch (Exception e)
+            {
+                throw new PEMException("problem parsing cert: " + e.toString(), e);
+            }
+        }
+    }
+
+    private class PKCS10CertificationRequestParser
+        implements PemObjectParser
+    {
+        /**
+         * Reads in a PKCS10 certification request.
+         *
+         * @return the certificate request.
+         * @throws IOException if an I/O error occured
+         */
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            try
+            {
+                return new PKCS10CertificationRequest(obj.getContent());
+            }
+            catch (Exception e)
+            {
+                throw new PEMException("problem parsing certrequest: " + e.toString(), e);
+            }
+        }
+    }
+
+    private class PKCS7Parser
+        implements PemObjectParser
+    {
+        /**
+         * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS
+         * API.
+         *
+         * @return the X509Certificate
+         * @throws IOException if an I/O error occured
+         */
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            try
+            {
+                ASN1InputStream aIn = new ASN1InputStream(obj.getContent());
+
+                return ContentInfo.getInstance(aIn.readObject());
+            }
+            catch (Exception e)
+            {
+                throw new PEMException("problem parsing PKCS7 object: " + e.toString(), e);
+            }
+        }
+    }
+
+    private class X509AttributeCertificateParser
+        implements PemObjectParser
+    {
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            return new X509V2AttributeCertificate(obj.getContent());
+        }
+    }
+
+    private class ECNamedCurveSpecParser
+        implements PemObjectParser
+    {
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            try
+            {
+                DERObjectIdentifier oid = (DERObjectIdentifier)ASN1Object.fromByteArray(obj.getContent());
+
+                Object params = ECNamedCurveTable.getParameterSpec(oid.getId());
+
+                if (params == null)
+                {
+                    throw new IOException("object ID not found in EC curve table");
+                }
+
+                return params;
+            }
+            catch (IOException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PEMException("exception extracting EC named curve: " + e.toString());
+            }
+        }
+    }
+
+    private class EncryptedPrivateKeyParser
+        implements PemObjectParser
+    {
+        private String symProvider;
+        private String asymProvider;
+
+        public EncryptedPrivateKeyParser(String symProvider, String asymProvider)
+        {
+            this.symProvider = symProvider;
+            this.asymProvider = asymProvider;
+        }
+
+        /**
+         * Reads in a X509CRL.
+         *
+         * @return the X509Certificate
+         * @throws IOException if an I/O error occured
+         */
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            try
+            {
+                EncryptedPrivateKeyInfo info = EncryptedPrivateKeyInfo.getInstance(ASN1Object.fromByteArray(obj.getContent()));
+                AlgorithmIdentifier algId = info.getEncryptionAlgorithm();
+
+                if (pFinder == null)
+                {
+                    throw new PEMException("no PasswordFinder specified");
+                }
+
+                if (PEMUtilities.isPKCS5Scheme2(algId.getAlgorithm()))
+                {
+                    PBES2Parameters params = PBES2Parameters.getInstance(algId.getParameters());
+                    KeyDerivationFunc func = params.getKeyDerivationFunc();
+                    EncryptionScheme scheme = params.getEncryptionScheme();
+                    PBKDF2Params defParams = (PBKDF2Params)func.getParameters();
+
+                    int iterationCount = defParams.getIterationCount().intValue();
+                    byte[] salt = defParams.getSalt();
+
+                    String algorithm = scheme.getAlgorithm().getId();
+
+                    SecretKey key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(algorithm, pFinder.getPassword(), salt, iterationCount);
+
+                    Cipher cipher = Cipher.getInstance(algorithm, symProvider);
+                    AlgorithmParameters algParams = AlgorithmParameters.getInstance(algorithm, symProvider);
+
+                    algParams.init(scheme.getParameters().getDERObject().getEncoded());
+
+                    cipher.init(Cipher.DECRYPT_MODE, key, algParams);
+
+                    PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData())));
+                    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded());
+
+                    KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider);
+
+                    return keyFact.generatePrivate(keySpec);
+                }
+                else if (PEMUtilities.isPKCS12(algId.getAlgorithm()))
+                {
+                    PKCS12PBEParams params = PKCS12PBEParams.getInstance(algId.getParameters());
+                    String algorithm = algId.getAlgorithm().getId();
+                    PBEKeySpec pbeSpec = new PBEKeySpec(pFinder.getPassword());
+
+                    SecretKeyFactory secKeyFact = SecretKeyFactory.getInstance(algorithm, symProvider);
+                    PBEParameterSpec defParams = new PBEParameterSpec(params.getIV(), params.getIterations().intValue());
+
+                    Cipher cipher = Cipher.getInstance(algorithm, symProvider);
+
+                    cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams);
+
+                    PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData())));
+                    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded());
+
+                    KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider);
+
+                    return keyFact.generatePrivate(keySpec);
+                }
+                else if (PEMUtilities.isPKCS5Scheme1(algId.getAlgorithm()))
+                {
+                    PBEParameter params = PBEParameter.getInstance(algId.getParameters());
+                    String algorithm = algId.getAlgorithm().getId();
+                    PBEKeySpec pbeSpec = new PBEKeySpec(pFinder.getPassword());
+
+                    SecretKeyFactory secKeyFact = SecretKeyFactory.getInstance(algorithm, symProvider);
+                    PBEParameterSpec defParams = new PBEParameterSpec(params.getSalt(), params.getIterationCount().intValue());
+
+                    Cipher cipher = Cipher.getInstance(algorithm, symProvider);
+
+                    cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams);
+
+                    PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData())));
+                    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded());
+
+                    KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider);
+
+                    return keyFact.generatePrivate(keySpec);
+                }
+                else
+                {
+                    throw new PEMException("Unknown algorithm: " + algId.getAlgorithm());
+                }
+            }
+            catch (IOException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PEMException("problem parsing ENCRYPTED PRIVATE KEY: " + e.toString(), e);
+            }
+        }
+    }
+
+    private class PrivateKeyParser
+        implements PemObjectParser
+    {
+        private String provider;
+
+        public PrivateKeyParser(String provider)
+        {
+            this.provider = provider;
+        }
+
+        public Object parseObject(PemObject obj)
+            throws IOException
+        {
+            try
+            {
+                PrivateKeyInfo info = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(obj.getContent()));
+                PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(obj.getContent());
+
+                KeyFactory keyFact = KeyFactory.getInstance(info.getAlgorithmId().getAlgorithm().getId(), provider);
+
+                return keyFact.generatePrivate(keySpec);
+            }
+            catch (Exception e)
+            {
+                throw new PEMException("problem parsing PRIVATE KEY: " + e.toString(), e);
+            }
+        }
+    }
+}
diff --git a/src/main/java/org/bouncycastle/openssl/PEMUtilities.java b/src/main/java/org/bouncycastle/openssl/PEMUtilities.java
index eaed72e..c955e4d 100644
--- a/src/main/java/org/bouncycastle/openssl/PEMUtilities.java
+++ b/src/main/java/org/bouncycastle/openssl/PEMUtilities.java
@@ -1,22 +1,120 @@
 package org.bouncycastle.openssl;
 
-import org.bouncycastle.crypto.PBEParametersGenerator;
-import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
-import org.bouncycastle.crypto.params.KeyParameter;
+import java.io.IOException;
+import java.security.Key;
+import java.security.Provider;
+import java.security.Security;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 import javax.crypto.Cipher;
 import javax.crypto.SecretKey;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.RC2ParameterSpec;
-import java.io.IOException;
-import java.security.Key;
-import java.security.spec.AlgorithmParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
+import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.bouncycastle.crypto.params.KeyParameter;
 
 final class PEMUtilities
 {
+    private static final Map KEYSIZES = new HashMap();
+    private static final Set PKCS5_SCHEME_1 = new HashSet();
+    private static final Set PKCS5_SCHEME_2 = new HashSet();
+
+    static
+    {
+        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC);
+        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC);
+        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC);
+        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC);
+        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC);
+        PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC);
+
+        PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.id_PBES2);
+        PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.des_EDE3_CBC);
+        PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes128_CBC);
+        PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC);
+        PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC);
+
+        // BEGIN android-changed
+        KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integer.valueOf(192));
+        KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integer.valueOf(128));
+        KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integer.valueOf(192));
+        KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integer.valueOf(256));
+        // END android-changed
+    }
+
+    static int getKeySize(String algorithm)
+    {
+        if (!KEYSIZES.containsKey(algorithm))
+        {
+            throw new IllegalStateException("no key size for algorithm: " + algorithm);
+        }
+        
+        return ((Integer)KEYSIZES.get(algorithm)).intValue();
+    }
+
+    static boolean isPKCS5Scheme1(DERObjectIdentifier algOid)
+    {
+        return PKCS5_SCHEME_1.contains(algOid);
+    }
+
+    static boolean isPKCS5Scheme2(DERObjectIdentifier algOid)
+    {
+        return PKCS5_SCHEME_2.contains(algOid);
+    }
+
+    static boolean isPKCS12(DERObjectIdentifier algOid)
+    {
+        return algOid.getId().startsWith(PKCSObjectIdentifiers.pkcs_12PbeIds.getId());
+    }
+
+    static SecretKey generateSecretKeyForPKCS5Scheme2(String algorithm, char[] password, byte[] salt, int iterationCount)
+    {
+        PBEParametersGenerator generator = new PKCS5S2ParametersGenerator();
+
+        generator.init(
+            PBEParametersGenerator.PKCS5PasswordToBytes(password),
+            salt,
+            iterationCount);
+
+        return new SecretKeySpec(((KeyParameter)generator.generateDerivedParameters(PEMUtilities.getKeySize(algorithm))).getKey(), algorithm);
+    }
+
     static byte[] crypt(
         boolean encrypt,
-        String  provider,
+        String provider,
+        byte[]  bytes,
+        char[]  password,
+        String  dekAlgName,
+        byte[]  iv)
+        throws IOException
+    {
+        Provider prov = null;
+        if (provider != null)
+        {
+            prov = Security.getProvider(provider);
+            if (prov == null)
+            {
+                throw new EncryptionException("cannot find provider: " + provider);
+            }
+        }
+
+        return crypt(encrypt, prov, bytes, password, dekAlgName, iv);
+    }
+
+    static byte[] crypt(
+        boolean encrypt,
+        Provider provider,
         byte[]  bytes,
         char[]  password,
         String  dekAlgName,
@@ -29,7 +127,6 @@
         String                 padding = "PKCS5Padding";
         Key                    sKey;
 
-
         // Figure out block mode and padding.
         if (dekAlgName.endsWith("-CFB"))
         {
diff --git a/src/main/java/org/bouncycastle/openssl/PEMWriter.java b/src/main/java/org/bouncycastle/openssl/PEMWriter.java
index 5c057c6..834252f 100644
--- a/src/main/java/org/bouncycastle/openssl/PEMWriter.java
+++ b/src/main/java/org/bouncycastle/openssl/PEMWriter.java
@@ -1,44 +1,19 @@
 package org.bouncycastle.openssl;
 
-import java.io.BufferedWriter;
 import java.io.IOException;
 import java.io.Writer;
-import java.math.BigInteger;
-import java.security.Key;
-import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.PublicKey;
+import java.security.NoSuchProviderException;
 import java.security.SecureRandom;
-import java.security.cert.CRLException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509CRL;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.DSAParams;
-import java.security.interfaces.DSAPrivateKey;
-import java.security.interfaces.RSAPrivateCrtKey;
-import java.security.interfaces.RSAPrivateKey;
 
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.cms.ContentInfo;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
-import org.bouncycastle.asn1.x509.DSAParameter;
-import org.bouncycastle.jce.PKCS10CertificationRequest;
-import org.bouncycastle.util.Strings;
-import org.bouncycastle.util.encoders.Base64;
-import org.bouncycastle.util.encoders.Hex;
-import org.bouncycastle.x509.X509AttributeCertificate;
-import org.bouncycastle.x509.X509V2AttributeCertificate;
+import org.bouncycastle.util.io.pem.PemGenerationException;
+import org.bouncycastle.util.io.pem.PemObjectGenerator;
+import org.bouncycastle.util.io.pem.PemWriter;
 
 /**
  * General purpose writer for OpenSSL PEM objects.
  */
 public class PEMWriter
-    extends BufferedWriter
+    extends PemWriter
 {
     private String provider;
 
@@ -61,149 +36,30 @@
         this.provider = provider;
     }
 
-    private void writeHexEncoded(byte[] bytes)
-        throws IOException
-    {
-        bytes = Hex.encode(bytes);
-        
-        for (int i = 0; i != bytes.length; i++)
-        {
-            this.write((char)bytes[i]);
-        }
-    }
-
-    private void writeEncoded(byte[] bytes) 
-        throws IOException
-    {
-        char[]  buf = new char[64];
-        
-        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();
-        }
-    }
-    
     public void writeObject(
-        Object  o) 
+        Object  obj)
         throws IOException
     {
-        String  type;
-        byte[]  encoding;
-        
-        if (o instanceof X509Certificate)
+        try
         {
-            type = "CERTIFICATE";
-            try
-            {
-                encoding = ((X509Certificate)o).getEncoded();
-            }
-            catch (CertificateEncodingException e)
-            {
-                throw new IOException("Cannot encode object: " + e.toString());
-            }
+            super.writeObject(new MiscPEMGenerator(obj));
         }
-        else if (o instanceof X509CRL)
+        catch (PemGenerationException e)
         {
-            type = "X509 CRL";
-            try
+            if (e.getCause() instanceof IOException)
             {
-                encoding = ((X509CRL)o).getEncoded();
+                throw (IOException)e.getCause();
             }
-            catch (CRLException e)
-            {
-                throw new IOException("Cannot encode object: " + e.toString());
-            }
-        }
-        else if (o instanceof KeyPair)
-        {
-            writeObject(((KeyPair)o).getPrivate());
-            return;
-        }
-        else if (o instanceof PrivateKey)
-        {
-            PrivateKeyInfo info = new PrivateKeyInfo(
-                (ASN1Sequence) ASN1Object.fromByteArray(((Key)o).getEncoded()));
 
-            if (o instanceof RSAPrivateKey)
-            {
-                type = "RSA PRIVATE KEY";
+            throw e;
+        }
+    }
 
-                encoding = info.getPrivateKey().getEncoded();
-            }
-            else if (o instanceof DSAPrivateKey)
-            {
-                type = "DSA PRIVATE KEY";
-                
-                DSAParameter        p = DSAParameter.getInstance(info.getAlgorithmId().getParameters());
-                ASN1EncodableVector v = new ASN1EncodableVector();
-                
-                v.add(new DERInteger(0));
-                v.add(new DERInteger(p.getP()));
-                v.add(new DERInteger(p.getQ()));
-                v.add(new DERInteger(p.getG()));
-                
-                BigInteger x = ((DSAPrivateKey)o).getX();
-                BigInteger y = p.getG().modPow(x, p.getP());
-                
-                v.add(new DERInteger(y));
-                v.add(new DERInteger(x));
-
-                encoding = new DERSequence(v).getEncoded();
-            }
-            else if (((PrivateKey)o).getAlgorithm().equals("ECDSA"))
-            {
-                type = "EC PRIVATE KEY";
-
-                encoding = info.getPrivateKey().getEncoded();
-            }
-            else
-            {
-                throw new IOException("Cannot identify private key");
-            }
-        }
-        else if (o instanceof PublicKey)
-        {
-            type = "PUBLIC KEY";
-            
-            encoding = ((PublicKey)o).getEncoded();
-        }
-        else if (o instanceof X509AttributeCertificate)
-        {
-            type = "ATTRIBUTE CERTIFICATE";
-            encoding = ((X509V2AttributeCertificate)o).getEncoded();
-        }
-        else if (o instanceof PKCS10CertificationRequest)
-        {
-            type = "CERTIFICATE REQUEST";
-            encoding = ((PKCS10CertificationRequest)o).getEncoded();
-        }
-        else if (o instanceof ContentInfo)
-        {
-            type = "PKCS7";
-            encoding = ((ContentInfo)o).getEncoded();
-        }
-        else
-        {
-            throw new IOException("unknown object passed - can't encode.");
-        }
-
-        writeHeader(type);
-        writeEncoded(encoding);
-        writeFooter(type);
+    public void writeObject(
+        PemObjectGenerator obj)
+        throws IOException
+    {
+        super.writeObject(obj);
     }
 
     public void writeObject(
@@ -213,112 +69,13 @@
         SecureRandom random)
         throws IOException
     {
-        if (obj instanceof KeyPair)
+        try
         {
-            writeObject(((KeyPair)obj).getPrivate());
-            return;
+            super.writeObject(new MiscPEMGenerator(obj, algorithm, password, random, provider));
         }
-
-        String type = null;
-        byte[] keyData = null;
-
-        if (obj instanceof RSAPrivateCrtKey)
+        catch (NoSuchProviderException e)
         {
-            type = "RSA PRIVATE KEY";
-
-            RSAPrivateCrtKey k = (RSAPrivateCrtKey)obj;
-
-            RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure(
-                k.getModulus(),
-                k.getPublicExponent(),
-                k.getPrivateExponent(),
-                k.getPrimeP(),
-                k.getPrimeQ(),
-                k.getPrimeExponentP(),
-                k.getPrimeExponentQ(),
-                k.getCrtCoefficient());
-
-            // convert to bytearray
-            keyData = keyStruct.getEncoded();
+            throw new EncryptionException(e.getMessage(), e);
         }
-        else if (obj instanceof DSAPrivateKey)
-        {
-            type = "DSA PRIVATE KEY";
-
-            DSAPrivateKey       k = (DSAPrivateKey)obj;
-            DSAParams           p = k.getParams();
-            ASN1EncodableVector v = new ASN1EncodableVector();
-
-            v.add(new DERInteger(0));
-            v.add(new DERInteger(p.getP()));
-            v.add(new DERInteger(p.getQ()));
-            v.add(new DERInteger(p.getG()));
-
-            BigInteger x = k.getX();
-            BigInteger y = p.getG().modPow(x, p.getP());
-
-            v.add(new DERInteger(y));
-            v.add(new DERInteger(x));
-
-            keyData = new DERSequence(v).getEncoded();
-        }
-        else if (obj instanceof PrivateKey && "ECDSA".equals(((PrivateKey)obj).getAlgorithm()))
-        {
-            type = "EC PRIVATE KEY";
-
-            PrivateKeyInfo      privInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(((PrivateKey)obj).getEncoded()));
-
-            keyData = privInfo.getPrivateKey().getEncoded();
-        }
-
-        if (type == null || keyData == null)
-        {
-            // TODO Support other types?
-            throw new IllegalArgumentException("Object type not supported: " + obj.getClass().getName());
-        }
-
-
-        String dekAlgName = Strings.toUpperCase(algorithm);
-
-        // Note: For backward compatibility
-        if (dekAlgName.equals("DESEDE"))
-        {
-            dekAlgName = "DES-EDE3-CBC";
-        }
-
-        int ivLength = dekAlgName.startsWith("AES-") ? 16 : 8;
-
-        byte[] iv = new byte[ivLength];
-        random.nextBytes(iv);
-
-        byte[] encData = PEMUtilities.crypt(true, provider, keyData, password, dekAlgName, iv);
-
-
-        // write the data
-        writeHeader(type);
-        this.write("Proc-Type: 4,ENCRYPTED");
-        this.newLine();
-        this.write("DEK-Info: " + dekAlgName + ",");
-        this.writeHexEncoded(iv);
-        this.newLine();
-        this.newLine();
-        this.writeEncoded(encData);
-        writeFooter(type);
-    }
-
-    private void writeHeader(
-        String type)
-        throws IOException
-    {
-        this.write("-----BEGIN " + type + "-----");
-        this.newLine();
-    }
-
-    private void writeFooter(
-        String type)
-        throws IOException
-    {
-        this.write("-----END " + type + "-----");
-        this.newLine();
     }
 }
diff --git a/src/main/java/org/bouncycastle/openssl/PasswordException.java b/src/main/java/org/bouncycastle/openssl/PasswordException.java
new file mode 100644
index 0000000..c2b8ccd
--- /dev/null
+++ b/src/main/java/org/bouncycastle/openssl/PasswordException.java
@@ -0,0 +1,12 @@
+package org.bouncycastle.openssl;
+
+import java.io.IOException;
+
+public class PasswordException
+    extends IOException
+{
+    public PasswordException(String msg)
+    {
+        super(msg);
+    }
+}
diff --git a/src/main/java/org/bouncycastle/openssl/PasswordFinder.java b/src/main/java/org/bouncycastle/openssl/PasswordFinder.java
new file mode 100644
index 0000000..fb89cf0
--- /dev/null
+++ b/src/main/java/org/bouncycastle/openssl/PasswordFinder.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.openssl;
+
+/**
+ * call back to allow a password to be fetched when one is requested.
+ */
+public interface PasswordFinder
+{
+    public char[] getPassword();
+}
diff --git a/src/main/java/org/bouncycastle/util/Arrays.java b/src/main/java/org/bouncycastle/util/Arrays.java
index 9600fd5..9d6a43b 100644
--- a/src/main/java/org/bouncycastle/util/Arrays.java
+++ b/src/main/java/org/bouncycastle/util/Arrays.java
@@ -41,6 +41,36 @@
     }
 
     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)
     {
diff --git a/src/main/java/org/bouncycastle/util/Strings.java b/src/main/java/org/bouncycastle/util/Strings.java
index e69eade..0c081f7 100644
--- a/src/main/java/org/bouncycastle/util/Strings.java
+++ b/src/main/java/org/bouncycastle/util/Strings.java
@@ -199,6 +199,18 @@
         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()];
diff --git a/src/main/java/org/bouncycastle/util/io/pem/PemGenerationException.java b/src/main/java/org/bouncycastle/util/io/pem/PemGenerationException.java
new file mode 100644
index 0000000..69a773e
--- /dev/null
+++ b/src/main/java/org/bouncycastle/util/io/pem/PemGenerationException.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.util.io.pem;
+
+import java.io.IOException;
+
+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/src/main/java/org/bouncycastle/util/io/pem/PemHeader.java b/src/main/java/org/bouncycastle/util/io/pem/PemHeader.java
new file mode 100644
index 0000000..b201c13
--- /dev/null
+++ b/src/main/java/org/bouncycastle/util/io/pem/PemHeader.java
@@ -0,0 +1,66 @@
+package org.bouncycastle.util.io.pem;
+
+public class PemHeader
+{
+    private String name;
+    private String value;
+
+    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/src/main/java/org/bouncycastle/util/io/pem/PemObject.java b/src/main/java/org/bouncycastle/util/io/pem/PemObject.java
new file mode 100644
index 0000000..2199520
--- /dev/null
+++ b/src/main/java/org/bouncycastle/util/io/pem/PemObject.java
@@ -0,0 +1,61 @@
+package org.bouncycastle.util.io.pem;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+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/src/main/java/org/bouncycastle/util/io/pem/PemObjectGenerator.java b/src/main/java/org/bouncycastle/util/io/pem/PemObjectGenerator.java
new file mode 100644
index 0000000..6fffdc5
--- /dev/null
+++ b/src/main/java/org/bouncycastle/util/io/pem/PemObjectGenerator.java
@@ -0,0 +1,7 @@
+package org.bouncycastle.util.io.pem;
+
+public interface PemObjectGenerator
+{
+    PemObject generate()
+        throws PemGenerationException;
+}
diff --git a/src/main/java/org/bouncycastle/util/io/pem/PemObjectParser.java b/src/main/java/org/bouncycastle/util/io/pem/PemObjectParser.java
new file mode 100644
index 0000000..b18b550
--- /dev/null
+++ b/src/main/java/org/bouncycastle/util/io/pem/PemObjectParser.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.util.io.pem;
+
+import java.io.IOException;
+
+public interface PemObjectParser
+{
+    Object parseObject(PemObject obj)
+            throws IOException;
+}
diff --git a/src/main/java/org/bouncycastle/util/io/pem/PemReader.java b/src/main/java/org/bouncycastle/util/io/pem/PemReader.java
new file mode 100644
index 0000000..28f777d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/util/io/pem/PemReader.java
@@ -0,0 +1,79 @@
+package 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 org.bouncycastle.util.encoders.Base64;
+
+public class PemReader
+    extends BufferedReader
+{
+    private static final String BEGIN = "-----BEGIN ";
+    private static final String END = "-----END ";
+
+    public PemReader(Reader reader)
+    {
+        super(reader);
+    }
+
+    public PemObject readPemObject()
+        throws IOException
+    {
+        String line = readLine();
+
+        if (line != null && line.startsWith(BEGIN))
+        {
+            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/src/main/java/org/bouncycastle/util/io/pem/PemWriter.java b/src/main/java/org/bouncycastle/util/io/pem/PemWriter.java
new file mode 100644
index 0000000..ccefa36
--- /dev/null
+++ b/src/main/java/org/bouncycastle/util/io/pem/PemWriter.java
@@ -0,0 +1,137 @@
+package org.bouncycastle.util.io.pem;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Iterator;
+
+import org.bouncycastle.util.encoders.Base64;
+
+/**
+ * A generic PEM writer, based on RFC 1421
+ */
+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 = System.getProperty("line.separator");
+        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/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java b/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java
index 48ef720..2290484 100644
--- a/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java
+++ b/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java
@@ -1,5 +1,19 @@
 package 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 org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DERInteger;
@@ -15,19 +29,6 @@
 import org.bouncycastle.util.Arrays;
 import org.bouncycastle.util.Selector;
 
-import javax.security.auth.x500.X500Principal;
-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;
-
 /**
  * The Holder object.
  * 
@@ -43,7 +44,7 @@
  *                         -- for example, an executable
  *          }
  * </pre>
- * 
+ * @deprecated use org.bouncycastle.cert.AttributeCertificateHolder
  */
 public class AttributeCertificateHolder
     implements CertSelector, Selector
@@ -162,7 +163,7 @@
     {
         if (holder.getObjectDigestInfo() != null)
         {
-            holder.getObjectDigestInfo().getDigestAlgorithm().getObjectId()
+            return holder.getObjectDigestInfo().getDigestAlgorithm().getObjectId()
                 .getId();
         }
         return null;
@@ -177,7 +178,7 @@
     {
         if (holder.getObjectDigestInfo() != null)
         {
-            holder.getObjectDigestInfo().getObjectDigest().getBytes();
+            return holder.getObjectDigestInfo().getObjectDigest().getBytes();
         }
         return null;
     }
diff --git a/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java b/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java
index 9960c74..0c88b3f 100644
--- a/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java
+++ b/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java
@@ -1,5 +1,15 @@
 package 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 org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.x509.AttCertIssuer;
@@ -9,17 +19,9 @@
 import org.bouncycastle.jce.X509Principal;
 import org.bouncycastle.util.Selector;
 
-import javax.security.auth.x500.X500Principal;
-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;
-
 /**
  * Carrying class for an attribute certificate issuer.
+ * @deprecated use org.bouncycastle.cert.AttributeCertificateIssuer
  */
 public class AttributeCertificateIssuer
     implements CertSelector, Selector
diff --git a/src/main/java/org/bouncycastle/x509/X509Util.java b/src/main/java/org/bouncycastle/x509/X509Util.java
index 43b2d90..9ea50b4 100644
--- a/src/main/java/org/bouncycastle/x509/X509Util.java
+++ b/src/main/java/org/bouncycastle/x509/X509Util.java
@@ -1,22 +1,5 @@
 package org.bouncycastle.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.DEREncodable;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import org.bouncycastle.jce.X509Principal;
-import org.bouncycastle.util.Strings;
-
-import javax.security.auth.x500.X500Principal;
 import java.io.IOException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
@@ -35,6 +18,24 @@
 import java.util.List;
 import java.util.Set;
 
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.util.Strings;
+
 class X509Util
 {
     private static Hashtable algorithms = new Hashtable();
@@ -51,8 +52,10 @@
         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);
+        // BEGIN android-removed
+        // algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        // algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        // END android-removed
         algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
         algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
         algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
@@ -60,50 +63,70 @@
         algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
         algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
         algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
-        algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        // BEGIN android-removed
+        // algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+        // END android-removed
         algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
         algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
         algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
-        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);
+        // BEGIN android-removed
+        // 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
         algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
         algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
-        algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+        // BEGIN android-removed
+        // algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+        // END android-removed
         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);
+        // BEGIN android-removed
+        // algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+        // END android-removed
         algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
         algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
         algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
-        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);
+        // BEGIN android-removed
+        // 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
 
         //
         // 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);
+        // BEGIN android-removed
+        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+        // END android-removed
         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);
+        // BEGIN android-removed
+        // noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+        // END android-removed
         noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
-
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
+        
         //
         // RFC 4491
         //
-        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
-        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // BEGIN android-removed
+        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        // END android-removed
 
         //
         // explicit params
@@ -113,10 +136,12 @@
         // END android-changed
         params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
 
-        // BEGIN android-changed
-        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
-        // END android-changed
-        params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+        // BEGIN android-removed
+        // // BEGIN android-changed
+        // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+        // // END android-changed
+        // params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+        // END android-removed
 
         // BEGIN android-changed
         AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
diff --git a/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java b/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
index e25f359..5e99e76 100644
--- a/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
+++ b/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
@@ -1,23 +1,5 @@
 package org.bouncycastle.x509;
 
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERInteger;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.asn1.x509.TBSCertificateStructure;
-import org.bouncycastle.asn1.x509.Time;
-import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator;
-import org.bouncycastle.asn1.x509.X509CertificateStructure;
-import org.bouncycastle.asn1.x509.X509Name;
-import org.bouncycastle.jce.X509Principal;
-import org.bouncycastle.jce.provider.X509CertificateObject;
-
-import javax.security.auth.x500.X500Principal;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.math.BigInteger;
@@ -35,8 +17,28 @@
 import java.util.Date;
 import java.util.Iterator;
 
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.TBSCertificateStructure;
+import org.bouncycastle.asn1.x509.Time;
+import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.provider.X509CertificateObject;
+
 /**
  * class to produce an X.509 Version 1 certificate.
+ * @deprecated use org.bouncycastle.cert.X509v1CertificateBuilder.
  */
 public class X509V1CertificateGenerator
 {
diff --git a/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java b/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java
index e91e8ff..4d40dd9 100644
--- a/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java
+++ b/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java
@@ -1,15 +1,5 @@
 package org.bouncycastle.x509;
 
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.x509.AttributeCertificate;
-import org.bouncycastle.asn1.x509.X509Extension;
-import org.bouncycastle.asn1.x509.X509Extensions;
-import org.bouncycastle.util.Arrays;
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -31,8 +21,19 @@
 import java.util.List;
 import java.util.Set;
 
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.x509.AttributeCertificate;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.util.Arrays;
+
 /**
  * An implementation of a version 2 X.509 Attribute Certificate.
+ * @deprecated use org.bouncycastle.cert.X509AttributeCertificateHolder
  */
 public class X509V2AttributeCertificate
     implements X509AttributeCertificate
@@ -40,12 +41,29 @@
     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(AttributeCertificate.getInstance(new ASN1InputStream(encIn).readObject()));
+        this(getObject(encIn));
     }
     
     public X509V2AttributeCertificate(
diff --git a/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java b/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
index efe024d..1ac395c 100644
--- a/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
+++ b/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
@@ -1,5 +1,23 @@
 package org.bouncycastle.x509;
 
+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 org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1InputStream;
@@ -20,25 +38,9 @@
 import org.bouncycastle.jce.provider.X509CertificateObject;
 import org.bouncycastle.x509.extension.X509ExtensionUtil;
 
-import javax.security.auth.x500.X500Principal;
-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;
-
 /**
  * class to produce an X.509 Version 3 certificate.
+ *  @deprecated use org.bouncycastle.cert.X509v3CertificateBuilder.
  */
 public class X509V3CertificateGenerator
 {
diff --git a/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java b/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java
index b0d6e36..0acb666 100644
--- a/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java
+++ b/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java
@@ -1,15 +1,5 @@
 package org.bouncycastle.x509.extension;
 
-import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1OctetString;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.DERString;
-import org.bouncycastle.asn1.x509.GeneralName;
-import org.bouncycastle.asn1.x509.X509Extensions;
-import org.bouncycastle.asn1.x509.X509Name;
-
 import java.io.IOException;
 import java.security.cert.CertificateParsingException;
 import java.security.cert.X509Certificate;
@@ -19,6 +9,16 @@
 import java.util.Enumeration;
 import java.util.List;
 
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1String;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.asn1.x509.X509Name;
+
 
 public class X509ExtensionUtil
 {
@@ -78,7 +78,7 @@
                 case GeneralName.dNSName:
                 case GeneralName.rfc822Name:
                 case GeneralName.uniformResourceIdentifier:
-                    list.add(((DERString)genName.getName()).getString());
+                    list.add(((ASN1String)genName.getName()).getString());
                     break;
                 case GeneralName.registeredID:
                     list.add(DERObjectIdentifier.getInstance(genName.getName()).getId());