DO NOT MERGE bouncycastle: limit input length as specified by the NIST spec
am: 08e455bd61  -s ours

* commit '08e455bd61ddaa02255383e85480b0d9cde6e954':
  DO NOT MERGE bouncycastle: limit input length as specified by the NIST spec
diff --git a/Android.mk b/Android.mk
index 56c4b4f..0658ba2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -29,27 +29,34 @@
  bcprov/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java, \
  $(all_bcprov_src_files))
 
-include $(CLEAR_VARS)
-LOCAL_MODULE := bouncycastle
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(android_bcprov_src_files)
-LOCAL_JAVACFLAGS := -encoding UTF-8
-LOCAL_JAVA_LIBRARIES := conscrypt core
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_JAVA_LIBRARY)
+# These cannot build in the PDK, because the PDK requires all libraries
+# compile against SDK versions. LOCAL_NO_STANDARD_LIBRARIES conflicts with
+# this requirement.
+ifneq ($(TARGET_BUILD_PDK),true)
 
-# non-jarjar version to build okhttp-tests
-include $(CLEAR_VARS)
-LOCAL_MODULE := bouncycastle-nojarjar
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(android_bcprov_src_files)
-LOCAL_JAVACFLAGS := -encoding UTF-8
-LOCAL_JAVA_LIBRARIES := conscrypt core
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_JAVA_LIBRARY)
+    include $(CLEAR_VARS)
+    LOCAL_MODULE := bouncycastle
+    LOCAL_MODULE_TAGS := optional
+    LOCAL_SRC_FILES := $(android_bcprov_src_files)
+    LOCAL_JAVACFLAGS := -encoding UTF-8
+    LOCAL_JAVA_LIBRARIES := conscrypt core
+    LOCAL_NO_STANDARD_LIBRARIES := true
+    LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
+    LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+    include $(BUILD_JAVA_LIBRARY)
+
+    # non-jarjar version to build okhttp-tests
+    include $(CLEAR_VARS)
+    LOCAL_MODULE := bouncycastle-nojarjar
+    LOCAL_MODULE_TAGS := optional
+    LOCAL_SRC_FILES := $(android_bcprov_src_files)
+    LOCAL_JAVACFLAGS := -encoding UTF-8
+    LOCAL_JAVA_LIBRARIES := conscrypt core
+    LOCAL_NO_STANDARD_LIBRARIES := true
+    LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+    include $(BUILD_STATIC_JAVA_LIBRARY)
+
+endif # TARGET_BUILD_PDK != true
 
 # This is used to generate a list of what is unused so it can be removed when bouncycastle is updated.
 # Based on "Finding dead code" example in ProGuard manual at http://proguard.sourceforge.net/
@@ -91,18 +98,21 @@
 		    public java.lang.String getPaddingName(); \
 		}"
 
+# Conscrypt isn't built in the PDK, so this cannot be built because it has a
+# dependency on conscrypt-hostdex.
 ifeq ($(WITH_HOST_DALVIK),true)
+ifneq ($(TARGET_BUILD_PDK),true)
     include $(CLEAR_VARS)
     LOCAL_MODULE := bouncycastle-hostdex
     LOCAL_MODULE_TAGS := optional
     LOCAL_SRC_FILES := $(all_bcprov_src_files)
     LOCAL_JAVACFLAGS := -encoding UTF-8
-    LOCAL_BUILD_HOST_DEX := true
     LOCAL_MODULE_TAGS := optional
     LOCAL_JAVA_LIBRARIES := conscrypt-hostdex
     LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
     LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-    include $(BUILD_HOST_JAVA_LIBRARY)
+    include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
+endif
 endif
 
 include $(CLEAR_VARS)
diff --git a/NOTICE b/NOTICE
index d89ebe3..b7e58c1 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,4 +1,4 @@
-Copyright (c) 2000-2013 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
+Copyright (c) 2000-2013 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org)
 
 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,
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedData.java b/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedData.java
index ae71f31..0c52082 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedData.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedData.java
@@ -3,11 +3,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.Provider;
-import java.security.cert.CertStore;
-import java.security.cert.CertStoreException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
@@ -25,15 +20,10 @@
 import org.bouncycastle.asn1.cms.ContentInfo;
 import org.bouncycastle.asn1.cms.SignedData;
 import org.bouncycastle.asn1.cms.SignerInfo;
-// BEGIN android-removed
-// import org.bouncycastle.cert.jcajce.JcaCertStoreBuilder;
-// END android-removed
 import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
 import org.bouncycastle.operator.OperatorCreationException;
 import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder;
 import org.bouncycastle.util.Store;
-import org.bouncycastle.x509.NoSuchStoreException;
-import org.bouncycastle.x509.X509Store;
 
 /**
  * general class for handling a pkcs7-signature message.
@@ -71,9 +61,7 @@
     ContentInfo             contentInfo;
     CMSTypedData            signedContent;
     SignerInformationStore  signerInfoStore;
-    X509Store               attributeStore;
-    X509Store               certificateStore;
-    X509Store               crlStore;
+
     private Map             hashes;
 
     private CMSSignedData(
@@ -268,194 +256,6 @@
     }
 
     /**
-     * return a X509Store containing the attribute certificates, if any, contained
-     * in this message.
-     *
-     * @param type type of store to create
-     * @param provider name of provider to use
-     * @return a store of attribute certificates
-     * @exception NoSuchProviderException if the provider requested isn't available.
-     * @exception NoSuchStoreException if the store type isn't available.
-     * @exception CMSException if a general exception prevents creation of the X509Store
-     * @deprecated use base Store returning method
-     */
-    public X509Store getAttributeCertificates(
-        String type,
-        String provider)
-        throws NoSuchStoreException, NoSuchProviderException, CMSException
-    {
-        return getAttributeCertificates(type, CMSUtils.getProvider(provider));
-    }
-
-    /**
-     * return a X509Store containing the attribute certificates, if any, contained
-     * in this message.
-     *
-     * @param type type of store to create
-     * @param provider provider to use
-     * @return a store of attribute certificates
-     * @exception NoSuchStoreException if the store type isn't available.
-     * @exception CMSException if a general exception prevents creation of the X509Store
-     * @deprecated use base Store returning method
-     */
-    public X509Store getAttributeCertificates(
-        String type,
-        Provider provider)
-        throws NoSuchStoreException, CMSException
-    {
-        if (attributeStore == null)
-        {
-            attributeStore = HELPER.createAttributeStore(type, provider, this.getAttributeCertificates());
-        }
-
-        return attributeStore;
-    }
-
-    // BEGIN android-removed
-    // /**
-    //  * return a X509Store containing the public key certificates, if any, contained
-    //  * in this message.
-    //  *
-    //  * @param type type of store to create
-    //  * @param provider name of provider to use
-    //  * @return a store of public key certificates
-    //  * @exception NoSuchProviderException if the provider requested isn't available.
-    //  * @exception NoSuchStoreException if the store type isn't available.
-    //  * @exception CMSException if a general exception prevents creation of the X509Store
-    //  * @deprecated use base Store returning method
-    //  */
-    // public X509Store getCertificates(
-    //     String type,
-    //     String provider)
-    //     throws NoSuchStoreException, NoSuchProviderException, CMSException
-    // {
-    //     return getCertificates(type, CMSUtils.getProvider(provider));
-    // }
-    //
-    // /**
-    //  * return a X509Store containing the public key certificates, if any, contained
-    //  * in this message.
-    //  *
-    //  * @param type type of store to create
-    //  * @param provider provider to use
-    //  * @return a store of public key certificates
-    //  * @exception NoSuchStoreException if the store type isn't available.
-    //  * @exception CMSException if a general exception prevents creation of the X509Store
-    //  * @deprecated use base Store returning method
-    //  */
-    // public X509Store getCertificates(
-    //     String type,
-    //     Provider provider)
-    //     throws NoSuchStoreException, CMSException
-    // {
-    //     if (certificateStore == null)
-    //     {
-    //         certificateStore = HELPER.createCertificateStore(type, provider, this.getCertificates());
-    //     }
-    //
-    //     return certificateStore;
-    // }
-    //
-    // /**
-    //  * return a X509Store containing CRLs, if any, contained
-    //  * in this message.
-    //  *
-    //  * @param type type of store to create
-    //  * @param provider name of provider to use
-    //  * @return a store of CRLs
-    //  * @exception NoSuchProviderException if the provider requested isn't available.
-    //  * @exception NoSuchStoreException if the store type isn't available.
-    //  * @exception CMSException if a general exception prevents creation of the X509Store
-    //  * @deprecated use base Store returning method
-    //  */
-    // public X509Store getCRLs(
-    //     String type,
-    //     String provider)
-    //     throws NoSuchStoreException, NoSuchProviderException, CMSException
-    // {
-    //     return getCRLs(type, CMSUtils.getProvider(provider));
-    // }
-    //
-    // /**
-    //  * return a X509Store containing CRLs, if any, contained
-    //  * in this message.
-    //  *
-    //  * @param type type of store to create
-    //  * @param provider provider to use
-    //  * @return a store of CRLs
-    //  * @exception NoSuchStoreException if the store type isn't available.
-    //  * @exception CMSException if a general exception prevents creation of the X509Store
-    //  * @deprecated use base Store returning method
-    //  */
-    // public X509Store getCRLs(
-    //     String type,
-    //     Provider provider)
-    //     throws NoSuchStoreException, CMSException
-    // {
-    //     if (crlStore == null)
-    //     {
-    //         crlStore = HELPER.createCRLsStore(type, provider, getCRLs());
-    //     }
-    //
-    //     return crlStore;
-    // }
-    //
-    // /**
-    //  * return a CertStore containing the certificates and CRLs associated with
-    //  * this message.
-    //  *
-    //  * @exception NoSuchProviderException if the provider requested isn't available.
-    //  * @exception NoSuchAlgorithmException if the cert store isn't available.
-    //  * @exception CMSException if a general exception prevents creation of the CertStore
-    //  * @deprecated use base Store returning method and org.bouncycastle.cert.jcajce.JcaCertStoreBuilder
-    //  */
-    // public CertStore getCertificatesAndCRLs(
-    //     String  type,
-    //     String  provider)
-    //     throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
-    // {
-    //     return getCertificatesAndCRLs(type, CMSUtils.getProvider(provider));
-    // }
-    //
-    // /**
-    //  * return a CertStore containing the certificates and CRLs associated with
-    //  * this message.
-    //  *
-    //  * @exception NoSuchAlgorithmException if the cert store isn't available.
-    //  * @exception CMSException if a general exception prevents creation of the CertStore
-    //  * @deprecated use base Store returning method and org.bouncycastle.cert.jcajce.JcaCertStoreBuilder
-    //  */
-    // public CertStore getCertificatesAndCRLs(
-    //     String  type,
-    //     Provider  provider)
-    //     throws NoSuchAlgorithmException, CMSException
-    // {
-    //     try
-    //     {
-    //         JcaCertStoreBuilder certStoreBuilder = new JcaCertStoreBuilder().setType(type);
-    //
-    //         if (provider != null)
-    //         {
-    //             certStoreBuilder.setProvider(provider);
-    //         }
-    //
-    //         certStoreBuilder.addCertificates(this.getCertificates());
-    //         certStoreBuilder.addCRLs(this.getCRLs());
-    //
-    //         return certStoreBuilder.build();
-    //     }
-    //     catch (NoSuchAlgorithmException e)
-    //     {
-    //         throw e;
-    //     }
-    //     catch (Exception e)
-    //     {
-    //         throw new CMSException("exception creating CertStore: " + e.getMessage(), e);
-    //     }
-    // }
-    // END android-removed
-
-    /**
      * Return any X.509 certificate objects in this SignedData structure as a Store of X509CertificateHolder objects.
      *
      * @return a Store of X509CertificateHolder objects.
@@ -518,15 +318,6 @@
 
     /**
      * return the ContentInfo
-     * @deprecated use toASN1Structure()
-     */
-    public ContentInfo getContentInfo()
-    {
-        return contentInfo;
-    }
-
-    /**
-     * return the ContentInfo
      */
     public ContentInfo toASN1Structure()
     {
@@ -680,77 +471,6 @@
     /**
      * Replace the certificate and CRL information associated with this
      * CMSSignedData object with the new one passed in.
-     * 
-     * @param signedData the signed data object to be used as a base.
-     * @param certsAndCrls the new certificates and CRLs to be used.
-     * @return a new signed data object.
-     * @exception CMSException if there is an error processing the CertStore
-     * @deprecated use method taking Store arguments.
-     */
-    public static CMSSignedData replaceCertificatesAndCRLs(
-        CMSSignedData   signedData,
-        CertStore       certsAndCrls)
-        throws CMSException
-    {
-        //
-        // copy
-        //
-        CMSSignedData   cms = new CMSSignedData(signedData);
-        
-        //
-        // replace the certs and crls in the SignedData object
-        //
-        ASN1Set             certs = null;
-        ASN1Set             crls = null;
-
-        try
-        {
-            ASN1Set set = CMSUtils.createBerSetFromList(CMSUtils.getCertificatesFromStore(certsAndCrls));
-
-            if (set.size() != 0)
-            {
-                certs = set;
-            }
-        }
-        catch (CertStoreException e)
-        {
-            throw new CMSException("error getting certs from certStore", e);
-        }
-
-        try
-        {
-            ASN1Set set = CMSUtils.createBerSetFromList(CMSUtils.getCRLsFromStore(certsAndCrls));
-
-            if (set.size() != 0)
-            {
-                crls = set;
-            }
-        }
-        catch (CertStoreException e)
-        {
-            throw new CMSException("error getting crls from certStore", e);
-        }
-        
-        //
-        // replace the CMS structure.
-        //
-        cms.signedData = new SignedData(signedData.signedData.getDigestAlgorithms(), 
-                                   signedData.signedData.getEncapContentInfo(),
-                                   certs,
-                                   crls,
-                                   signedData.signedData.getSignerInfos());
-        
-        //
-        // replace the contentInfo with the new one
-        //
-        cms.contentInfo = new ContentInfo(cms.contentInfo.getContentType(), cms.signedData);
-        
-        return cms;
-    }
-
-    /**
-     * Replace the certificate and CRL information associated with this
-     * CMSSignedData object with the new one passed in.
      *
      * @param signedData the signed data object to be used as a base.
      * @param certificates the new certificates to be used.
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java b/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java
index 9692e15..eea8a1a 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java
@@ -3,13 +3,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.PrivateKey;
-import java.security.Provider;
-import java.security.SecureRandom;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -20,16 +13,10 @@
 import org.bouncycastle.asn1.ASN1Set;
 import org.bouncycastle.asn1.BEROctetString;
 import org.bouncycastle.asn1.DERSet;
-import org.bouncycastle.asn1.cms.AttributeTable;
 import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
 import org.bouncycastle.asn1.cms.ContentInfo;
 import org.bouncycastle.asn1.cms.SignedData;
 import org.bouncycastle.asn1.cms.SignerInfo;
-import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
 
 /**
  * general class for generating a pkcs7-signature message.
@@ -62,80 +49,6 @@
 {
     private List signerInfs = new ArrayList();
 
-    private class SignerInf
-    {
-        final PrivateKey                  key;
-        final Object                      signerIdentifier;
-        final String                      digestOID;
-        final String                      encOID;
-        final CMSAttributeTableGenerator  sAttr;
-        final CMSAttributeTableGenerator  unsAttr;
-        final AttributeTable              baseSignedTable;
-
-        SignerInf(
-            PrivateKey                 key,
-            Object                     signerIdentifier,
-            String                     digestOID,
-            String                     encOID,
-            CMSAttributeTableGenerator sAttr,
-            CMSAttributeTableGenerator unsAttr,
-            AttributeTable             baseSignedTable)
-        {
-            this.key = key;
-            this.signerIdentifier = signerIdentifier;
-            this.digestOID = digestOID;
-            this.encOID = encOID;
-            this.sAttr = sAttr;
-            this.unsAttr = unsAttr;
-            this.baseSignedTable = baseSignedTable;
-        }
-
-        SignerInfoGenerator toSignerInfoGenerator(
-            SecureRandom        random,
-            Provider sigProvider,
-            boolean             addDefaultAttributes)
-            throws IOException, CertificateEncodingException, CMSException, OperatorCreationException, NoSuchAlgorithmException
-        {
-            String              digestName = CMSSignedHelper.INSTANCE.getDigestAlgName(digestOID);
-            String              signatureName = digestName + "with" + CMSSignedHelper.INSTANCE.getEncryptionAlgName(encOID);
-
-            JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new BcDigestCalculatorProvider());
-
-            if (addDefaultAttributes)
-            {
-                builder.setSignedAttributeGenerator(sAttr);
-            }
-            builder.setDirectSignature(!addDefaultAttributes);
-
-            builder.setUnsignedAttributeGenerator(unsAttr);
-
-            JcaContentSignerBuilder signerBuilder;
-
-            try
-            {
-                signerBuilder = new JcaContentSignerBuilder(signatureName).setSecureRandom(random);
-            }
-            catch (IllegalArgumentException e)
-            {
-                throw new NoSuchAlgorithmException(e.getMessage());
-            }
-
-            if (sigProvider != null)
-            {
-                signerBuilder.setProvider(sigProvider);
-            }
-
-            ContentSigner contentSigner = signerBuilder.build(key);
-            if (signerIdentifier instanceof X509Certificate)
-            {
-                return builder.build(contentSigner, (X509Certificate)signerIdentifier);
-            }
-            else
-            {
-                return builder.build(contentSigner, (byte[])signerIdentifier);
-            }
-        }
-    }
     /**
      * base constructor
      */
@@ -144,456 +57,10 @@
     }
 
     /**
-     * constructor allowing specific source of randomness
-     * @param rand instance of SecureRandom to use
-     * @deprecated  rand ignored in new API, use base constructor.
-     */
-    public CMSSignedDataGenerator(
-        SecureRandom rand)
-    {
-        super(rand);
-    }
-
-    /**
-     * add a signer - no attributes other than the default ones will be
-     * provided here.
+     * Generate a CMS Signed Data object carrying a detached CMS signature.
      *
-     * @param key signing key to use
-     * @param cert certificate containing corresponding public key
-     * @param digestOID digest algorithm OID
-     * @deprecated use addSignerInfoGenerator
+     * @param content the content to be signed.
      */
-    public void addSigner(
-        PrivateKey      key,
-        X509Certificate cert,
-        String          digestOID)
-        throws IllegalArgumentException
-    {
-        addSigner(key, cert, getEncOID(key, digestOID), digestOID);
-    }
-
-    /**
-     * add a signer, specifying the digest encryption algorithm to use - no attributes other than the default ones will be
-     * provided here.
-     *
-     * @param key signing key to use
-     * @param cert certificate containing corresponding public key
-     * @param encryptionOID digest encryption algorithm OID
-     * @param digestOID digest algorithm OID
-     * @deprecated use addSignerInfoGenerator
-     */
-    public void addSigner(
-        PrivateKey      key,
-        X509Certificate cert,
-        String          encryptionOID,
-        String          digestOID)
-        throws IllegalArgumentException
-    {
-        doAddSigner(key, cert, encryptionOID, digestOID,
-            new DefaultSignedAttributeTableGenerator(), null, null);
-    }
-
-    /**
-     * add a signer - no attributes other than the default ones will be
-     * provided here.
-     * @deprecated use addSignerInfoGenerator
-     */
-    public void addSigner(
-        PrivateKey      key,
-        byte[]          subjectKeyID,
-        String          digestOID)
-        throws IllegalArgumentException
-    {
-        addSigner(key, subjectKeyID, getEncOID(key, digestOID), digestOID);
-    }
-
-    /**
-     * add a signer, specifying the digest encryption algorithm to use - no attributes other than the default ones will be
-     * provided here.
-     * @deprecated use addSignerInfoGenerator
-     */
-    public void addSigner(
-        PrivateKey      key,
-        byte[]          subjectKeyID,
-        String          encryptionOID,
-        String          digestOID)
-        throws IllegalArgumentException
-    {
-        doAddSigner(key, subjectKeyID, encryptionOID, digestOID,
-            new DefaultSignedAttributeTableGenerator(), null, null);
-    }
-
-    /**
-     * add a signer with extra signed/unsigned attributes.
-     *
-     * @param key signing key to use
-     * @param cert certificate containing corresponding public key
-     * @param digestOID digest algorithm OID
-     * @param signedAttr table of attributes to be included in signature
-     * @param unsignedAttr table of attributes to be included as unsigned
-     * @deprecated use addSignerInfoGenerator
-     */
-    public void addSigner(
-        PrivateKey      key,
-        X509Certificate cert,
-        String          digestOID,
-        AttributeTable  signedAttr,
-        AttributeTable  unsignedAttr)
-        throws IllegalArgumentException
-    {
-        addSigner(key, cert, getEncOID(key, digestOID), digestOID, signedAttr, unsignedAttr);
-    }
-
-    /**
-     * add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes.
-     *
-     * @param key signing key to use
-     * @param cert certificate containing corresponding public key
-     * @param encryptionOID digest encryption algorithm OID
-     * @param digestOID digest algorithm OID
-     * @param signedAttr table of attributes to be included in signature
-     * @param unsignedAttr table of attributes to be included as unsigned
-     * @deprecated use addSignerInfoGenerator
-     */
-    public void addSigner(
-        PrivateKey      key,
-        X509Certificate cert,
-        String          encryptionOID,
-        String          digestOID,
-        AttributeTable  signedAttr,
-        AttributeTable  unsignedAttr)
-        throws IllegalArgumentException
-    {
-        doAddSigner(key, cert, encryptionOID, digestOID,
-          new DefaultSignedAttributeTableGenerator(signedAttr),
-          new SimpleAttributeTableGenerator(unsignedAttr), signedAttr);
-    }
-
-    /**
-     * add a signer with extra signed/unsigned attributes.
-     *
-     * @param key signing key to use
-     * @param subjectKeyID subjectKeyID of corresponding public key
-     * @param digestOID digest algorithm OID
-     * @param signedAttr table of attributes to be included in signature
-     * @param unsignedAttr table of attributes to be included as unsigned
-     * @deprecated use addSignerInfoGenerator
-     */
-    public void addSigner(
-        PrivateKey      key,
-        byte[]          subjectKeyID,
-        String          digestOID,
-        AttributeTable  signedAttr,
-        AttributeTable  unsignedAttr)
-        throws IllegalArgumentException
-    {
-        addSigner(key, subjectKeyID, getEncOID(key, digestOID), digestOID, signedAttr,
-            unsignedAttr); 
-    }
-
-    /**
-     * add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes.
-     *
-     * @param key signing key to use
-     * @param subjectKeyID subjectKeyID of corresponding public key
-     * @param encryptionOID digest encryption algorithm OID
-     * @param digestOID digest algorithm OID
-     * @param signedAttr table of attributes to be included in signature
-     * @param unsignedAttr table of attributes to be included as unsigned
-     * @deprecated use addSignerInfoGenerator
-     */
-    public void addSigner(
-        PrivateKey      key,
-        byte[]          subjectKeyID,
-        String          encryptionOID,
-        String          digestOID,
-        AttributeTable  signedAttr,
-        AttributeTable  unsignedAttr)
-        throws IllegalArgumentException
-    {
-        doAddSigner(key, subjectKeyID, encryptionOID, digestOID,
-            new DefaultSignedAttributeTableGenerator(signedAttr),
-            new SimpleAttributeTableGenerator(unsignedAttr), signedAttr);
-    }
-
-    /**
-     * add a signer with extra signed/unsigned attributes based on generators.
-     * @deprecated use addSignerInfoGenerator
-     */
-    public void addSigner(
-        PrivateKey                  key,
-        X509Certificate             cert,
-        String                      digestOID,
-        CMSAttributeTableGenerator  signedAttrGen,
-        CMSAttributeTableGenerator  unsignedAttrGen)
-        throws IllegalArgumentException
-    {
-        addSigner(key, cert, getEncOID(key, digestOID), digestOID, signedAttrGen, unsignedAttrGen);
-    }
-
-    /**
-     * add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes based on generators.
-     * @deprecated use addSignerInfoGenerator
-     */
-    public void addSigner(
-        PrivateKey                  key,
-        X509Certificate             cert,
-        String                      encryptionOID,
-        String                      digestOID,
-        CMSAttributeTableGenerator  signedAttrGen,
-        CMSAttributeTableGenerator  unsignedAttrGen)
-        throws IllegalArgumentException
-    {
-        doAddSigner(key, cert, encryptionOID, digestOID, signedAttrGen,
-            unsignedAttrGen, null);
-    }
-
-    /**
-     * add a signer with extra signed/unsigned attributes based on generators.
-     * @deprecated use addSignerInfoGenerator
-     */
-    public void addSigner(
-        PrivateKey                  key,
-        byte[]                      subjectKeyID,
-        String                      digestOID,
-        CMSAttributeTableGenerator  signedAttrGen,
-        CMSAttributeTableGenerator  unsignedAttrGen)
-        throws IllegalArgumentException
-    {
-        addSigner(key, subjectKeyID, getEncOID(key, digestOID), digestOID, signedAttrGen,
-            unsignedAttrGen);
-    }
-
-    /**
-     * add a signer, including digest encryption algorithm, with extra signed/unsigned attributes based on generators.
-     * @deprecated use addSignerInfoGenerator
-     */
-    public void addSigner(
-        PrivateKey                  key,
-        byte[]                      subjectKeyID,
-        String                      encryptionOID,
-        String                      digestOID,
-        CMSAttributeTableGenerator  signedAttrGen,
-        CMSAttributeTableGenerator  unsignedAttrGen)
-        throws IllegalArgumentException
-    {
-        doAddSigner(key, subjectKeyID, encryptionOID, digestOID,
-            signedAttrGen, unsignedAttrGen, null);
-    }
-
-    private void doAddSigner(
-        PrivateKey                  key,
-        Object                      signerIdentifier,
-        String                      encryptionOID,
-        String                      digestOID,
-        CMSAttributeTableGenerator  signedAttrGen,
-        CMSAttributeTableGenerator  unsignedAttrGen,
-        AttributeTable              baseSignedTable)
-        throws IllegalArgumentException
-    {
-        signerInfs.add(new SignerInf(key, signerIdentifier, digestOID, encryptionOID,
-            signedAttrGen, unsignedAttrGen, baseSignedTable));
-    }
-
-    /**
-     * generate a signed object that for a CMS Signed Data
-     * object using the given provider.
-     * @deprecated use generate() method not taking provider.
-     */
-    public CMSSignedData generate(
-        CMSProcessable content,
-        String         sigProvider)
-        throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
-    {
-        return generate(content, CMSUtils.getProvider(sigProvider));
-    }
-
-    /**
-     * generate a signed object that for a CMS Signed Data
-     * object using the given provider.
-     * @deprecated use generate() method not taking provider.
-     */
-    public CMSSignedData generate(
-        CMSProcessable content,
-        Provider       sigProvider)
-        throws NoSuchAlgorithmException, CMSException
-    {
-        return generate(content, false, sigProvider);
-    }
-
-    /**
-     * generate a signed object that for a CMS Signed Data
-     * object using the given provider - if encapsulate is true a copy
-     * of the message will be included in the signature. The content type
-     * is set according to the OID represented by the string signedContentType.
-     * @deprecated use generate(CMSTypedData, boolean)
-     */
-    public CMSSignedData generate(
-        String          eContentType,
-        CMSProcessable  content,
-        boolean         encapsulate,
-        String          sigProvider)
-        throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
-    {
-        return generate(eContentType, content, encapsulate, CMSUtils.getProvider(sigProvider),
-            true);
-    }
-
-    /**
-     * generate a signed object that for a CMS Signed Data
-     * object using the given provider - if encapsulate is true a copy
-     * of the message will be included in the signature. The content type
-     * is set according to the OID represented by the string signedContentType.
-     * @deprecated use generate(CMSTypedData, boolean)
-     */
-    public CMSSignedData generate(
-        String          eContentType,
-        CMSProcessable  content,
-        boolean         encapsulate,
-        Provider        sigProvider)
-        throws NoSuchAlgorithmException, CMSException
-    {
-        return generate(eContentType, content, encapsulate, sigProvider, true);
-    }
-
-    /**
-     * Similar method to the other generate methods. The additional argument
-     * addDefaultAttributes indicates whether or not a default set of signed attributes
-     * need to be added automatically. If the argument is set to false, no
-     * attributes will get added at all.
-     * @deprecated use generate(CMSTypedData, boolean)
-     */
-    public CMSSignedData generate(
-        String                  eContentType,
-        CMSProcessable          content,
-        boolean                 encapsulate,
-        String                  sigProvider,
-        boolean                 addDefaultAttributes)
-        throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
-    {
-        return generate(eContentType, content, encapsulate, CMSUtils.getProvider(sigProvider),
-            addDefaultAttributes);
-    }
-
-    /**
-     * Similar method to the other generate methods. The additional argument
-     * addDefaultAttributes indicates whether or not a default set of signed attributes
-     * need to be added automatically. If the argument is set to false, no
-     * attributes will get added at all.
-     * @deprecated use setDirectSignature() on SignerInformationGenerator.
-     */
-    public CMSSignedData generate(
-        String                  eContentType,
-        final CMSProcessable    content,
-        boolean                 encapsulate,
-        Provider                sigProvider,
-        boolean                 addDefaultAttributes)
-        throws NoSuchAlgorithmException, CMSException
-    {
-        boolean isCounterSignature = (eContentType == null);
-
-        final ASN1ObjectIdentifier contentTypeOID = isCounterSignature
-            ?   null
-            :   new ASN1ObjectIdentifier(eContentType);
-
-        for (Iterator it = signerInfs.iterator(); it.hasNext();)
-        {
-            SignerInf signer = (SignerInf)it.next();
-
-            try
-            {
-                signerGens.add(signer.toSignerInfoGenerator(rand, sigProvider,
-                    addDefaultAttributes));
-            }
-            catch (OperatorCreationException e)
-            {
-                throw new CMSException("exception creating signerInf", e);
-            }
-            catch (IOException e)
-            {
-                throw new CMSException("exception encoding attributes", e);
-            }
-            catch (CertificateEncodingException e)
-            {
-                throw new CMSException("error creating sid.", e);
-            }
-        }
-
-        signerInfs.clear();
-
-        if (content != null)
-        {
-            return generate(new CMSTypedData()
-            {
-                public ASN1ObjectIdentifier getContentType()
-                {
-                    return contentTypeOID;
-                }
-
-                public void write(OutputStream out)
-                    throws IOException, CMSException
-                {
-                    content.write(out);
-                }
-
-                public Object getContent()
-                {
-                    return content.getContent();
-                }
-            }, encapsulate);
-        }
-        else
-        {
-            return generate(new CMSAbsentContent(contentTypeOID), encapsulate);
-        }
-    }
-    
-    /**
-     * generate a signed object that for a CMS Signed Data
-     * object using the given provider - if encapsulate is true a copy
-     * of the message will be included in the signature with the
-     * default content type "data".
-     * @deprecated use generate(CMSTypedData, boolean)
-     */
-    public CMSSignedData generate(
-        CMSProcessable  content,
-        boolean         encapsulate,
-        String          sigProvider)
-        throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
-    {
-        if (content instanceof CMSTypedData)
-        {
-            return this.generate(((CMSTypedData)content).getContentType().getId(), content, encapsulate, sigProvider);
-        }
-        else
-        {
-            return this.generate(DATA, content, encapsulate, sigProvider);
-        }
-    }
-
-    /**
-     * generate a signed object that for a CMS Signed Data
-     * object using the given provider - if encapsulate is true a copy
-     * of the message will be included in the signature with the
-     * default content type "data".
-     * @deprecated use generate(CMSTypedData, boolean)
-     */
-    public CMSSignedData generate(
-        CMSProcessable  content,
-        boolean         encapsulate,
-        Provider        sigProvider)
-        throws NoSuchAlgorithmException, CMSException
-    {
-        if (content instanceof CMSTypedData)
-        {
-            return this.generate(((CMSTypedData)content).getContentType().getId(), content, encapsulate, sigProvider);
-        }
-        else
-        {
-            return this.generate(DATA, content, encapsulate, sigProvider);
-        }
-    }
-
     public CMSSignedData generate(
         CMSTypedData content)
         throws CMSException
@@ -601,6 +68,13 @@
         return generate(content, false);
     }
 
+    /**
+     * Generate a CMS Signed Data object which can be carrying a detached CMS signature, or have encapsulated data, depending on the value
+     * of the encapsulated parameter.
+     *
+     * @param content the content to be signed.
+     * @param encapsulate true if the content should be encapsulated in the signature, false otherwise.
+     */
     public CMSSignedData generate(
         // FIXME Avoid accessing more than once to support CMSProcessableInputStream
         CMSTypedData content,
@@ -747,36 +221,6 @@
      * the passed in SignerInformation object.
      *
      * @param signer the signer to be countersigned
-     * @param sigProvider the provider to be used for counter signing.
-     * @return a store containing the signers.
-     * @deprecated use generateCounterSigners(SignerInformation)
-     */
-    public SignerInformationStore generateCounterSigners(SignerInformation signer, Provider sigProvider)
-        throws NoSuchAlgorithmException, CMSException
-    {
-        return this.generate(null, new CMSProcessableByteArray(signer.getSignature()), false, sigProvider).getSignerInfos();
-    }
-
-    /**
-     * generate a set of one or more SignerInformation objects representing counter signatures on
-     * the passed in SignerInformation object.
-     *
-     * @param signer the signer to be countersigned
-     * @param sigProvider the provider to be used for counter signing.
-     * @return a store containing the signers.
-     * @deprecated use generateCounterSigners(SignerInformation)
-     */
-    public SignerInformationStore generateCounterSigners(SignerInformation signer, String sigProvider)
-        throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
-    {
-        return this.generate(null, new CMSProcessableByteArray(signer.getSignature()), false, CMSUtils.getProvider(sigProvider)).getSignerInfos();
-    }
-
-    /**
-     * generate a set of one or more SignerInformation objects representing counter signatures on
-     * the passed in SignerInformation object.
-     *
-     * @param signer the signer to be countersigned
      * @return a store containing the signers.
      */
     public SignerInformationStore generateCounterSigners(SignerInformation signer)
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedGenerator.java b/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedGenerator.java
index 8b9d4ce..f180c09 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedGenerator.java
@@ -1,12 +1,5 @@
 package org.bouncycastle.cms;
 
-import java.io.IOException;
-import java.security.PrivateKey;
-import java.security.SecureRandom;
-import java.security.cert.CertStore;
-import java.security.cert.CertStoreException;
-import java.security.interfaces.DSAPrivateKey;
-import java.security.interfaces.RSAPrivateKey;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -17,11 +10,7 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.ASN1Set;
-import org.bouncycastle.asn1.DERSet;
 import org.bouncycastle.asn1.DERTaggedObject;
-import org.bouncycastle.asn1.cms.AttributeTable;
 import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
 // BEGIN android-removed
 // import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat;
@@ -32,18 +21,12 @@
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x509.AttributeCertificate;
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.cert.X509AttributeCertificateHolder;
 import org.bouncycastle.cert.X509CRLHolder;
 import org.bouncycastle.cert.X509CertificateHolder;
-// BEGIN android-removed
-// import org.bouncycastle.jce.interfaces.GOST3410PrivateKey;
-// END android-removed
 import org.bouncycastle.util.Arrays;
 import org.bouncycastle.util.Store;
-import org.bouncycastle.x509.X509AttributeCertificate;
-import org.bouncycastle.x509.X509Store;
 
 public class CMSSignedGenerator
 {
@@ -53,9 +36,7 @@
     public static final String  DATA = CMSObjectIdentifiers.data.getId();
     
     public static final String  DIGEST_SHA1 = OIWObjectIdentifiers.idSHA1.getId();
-    // BEGIN android-removed
-    // public static final String  DIGEST_SHA224 = NISTObjectIdentifiers.id_sha224.getId();
-    // END android-removed
+    public static final String  DIGEST_SHA224 = NISTObjectIdentifiers.id_sha224.getId();
     public static final String  DIGEST_SHA256 = NISTObjectIdentifiers.id_sha256.getId();
     public static final String  DIGEST_SHA384 = NISTObjectIdentifiers.id_sha384.getId();
     public static final String  DIGEST_SHA512 = NISTObjectIdentifiers.id_sha512.getId();
@@ -77,9 +58,7 @@
     // END android-removed
 
     private static final String  ENCRYPTION_ECDSA_WITH_SHA1 = X9ObjectIdentifiers.ecdsa_with_SHA1.getId();
-    // BEGIN android-removed
-    // private static final String  ENCRYPTION_ECDSA_WITH_SHA224 = X9ObjectIdentifiers.ecdsa_with_SHA224.getId();
-    // END android-removed
+    private static final String  ENCRYPTION_ECDSA_WITH_SHA224 = X9ObjectIdentifiers.ecdsa_with_SHA224.getId();
     private static final String  ENCRYPTION_ECDSA_WITH_SHA256 = X9ObjectIdentifiers.ecdsa_with_SHA256.getId();
     private static final String  ENCRYPTION_ECDSA_WITH_SHA384 = X9ObjectIdentifiers.ecdsa_with_SHA384.getId();
     private static final String  ENCRYPTION_ECDSA_WITH_SHA512 = X9ObjectIdentifiers.ecdsa_with_SHA512.getId();
@@ -92,17 +71,13 @@
         NO_PARAMS.add(ENCRYPTION_DSA);
         NO_PARAMS.add(ENCRYPTION_ECDSA);
         NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA1);
-        // BEGIN android-removed
-        // NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA224);
-        // END android-removed
+        NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA224);
         NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA256);
         NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA384);
         NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA512);
 
         EC_ALGORITHMS.put(DIGEST_SHA1, ENCRYPTION_ECDSA_WITH_SHA1);
-        // BEGIN android-removed
-        // EC_ALGORITHMS.put(DIGEST_SHA224, ENCRYPTION_ECDSA_WITH_SHA224);
-        // END android-removed
+        EC_ALGORITHMS.put(DIGEST_SHA224, ENCRYPTION_ECDSA_WITH_SHA224);
         EC_ALGORITHMS.put(DIGEST_SHA256, ENCRYPTION_ECDSA_WITH_SHA256);
         EC_ALGORITHMS.put(DIGEST_SHA384, ENCRYPTION_ECDSA_WITH_SHA384);
         EC_ALGORITHMS.put(DIGEST_SHA512, ENCRYPTION_ECDSA_WITH_SHA512);
@@ -114,64 +89,11 @@
     protected List signerGens = new ArrayList();
     protected Map digests = new HashMap();
 
-    protected final SecureRandom rand;
-
     /**
      * base constructor
      */
     protected CMSSignedGenerator()
     {
-        this(new SecureRandom());
-    }
-
-    /**
-     * constructor allowing specific source of randomness
-     * @param rand instance of SecureRandom to use
-     */
-    protected CMSSignedGenerator(
-        SecureRandom rand)
-    {
-        this.rand = rand;
-    }
-    
-    protected String getEncOID(
-        PrivateKey key,
-        String     digestOID)
-    {
-        String encOID = null;
-        
-        if (key instanceof RSAPrivateKey || "RSA".equalsIgnoreCase(key.getAlgorithm()))
-        {
-            encOID = ENCRYPTION_RSA;
-        }
-        else if (key instanceof DSAPrivateKey || "DSA".equalsIgnoreCase(key.getAlgorithm()))
-        {
-            encOID = ENCRYPTION_DSA;
-            if (!digestOID.equals(DIGEST_SHA1))
-            {
-                throw new IllegalArgumentException("can't mix DSA with anything but SHA1");
-            }
-        }
-        else if ("ECDSA".equalsIgnoreCase(key.getAlgorithm()) || "EC".equalsIgnoreCase(key.getAlgorithm()))
-        {
-            encOID = (String)EC_ALGORITHMS.get(digestOID);
-            if (encOID == null)
-            {
-                throw new IllegalArgumentException("can't mix ECDSA with anything but SHA family digests");
-            }
-        }
-        // BEGIN android-removed
-        // else if (key instanceof GOST3410PrivateKey || "GOST3410".equalsIgnoreCase(key.getAlgorithm()))
-        // {
-        //     encOID = ENCRYPTION_GOST3410;
-        // }
-        // else if ("ECGOST3410".equalsIgnoreCase(key.getAlgorithm()))
-        // {
-        //     encOID = ENCRYPTION_ECGOST3410;
-        // }
-        // END android-removed
-        
-        return encOID;
     }
 
     protected Map getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, byte[] hash)
@@ -183,36 +105,6 @@
         return param;
     }
 
-    protected ASN1Set getAttributeSet(
-        AttributeTable attr)
-    {
-        if (attr != null)
-        {
-            return new DERSet(attr.toASN1EncodableVector());
-        }
-        
-        return null;
-    }
-
-    /**
-     * add the certificates and CRLs contained in the given CertStore
-     * to the pool that will be included in the encoded signature block.
-     * <p>
-     * Note: this assumes the CertStore will support null in the get
-     * methods.
-     * @param certStore CertStore containing the public key certificates and CRLs
-     * @throws java.security.cert.CertStoreException  if an issue occurs processing the CertStore
-     * @throws CMSException  if an issue occurse transforming data from the CertStore into the message
-     * @deprecated use addCertificates and addCRLs
-     */
-    public void addCertificatesAndCRLs(
-        CertStore certStore)
-        throws CertStoreException, CMSException
-    {
-        certs.addAll(CMSUtils.getCertificatesFromStore(certStore));
-        crls.addAll(CMSUtils.getCRLsFromStore(certStore));
-    }
-
     /**
      * Add a certificate to the certificate set to be included with the generated SignedData message.
      *
@@ -317,40 +209,7 @@
     // END android-removed
 
     /**
-     * Add the attribute certificates contained in the passed in store to the
-     * generator.
-     *
-     * @param store a store of Version 2 attribute certificates
-     * @throws CMSException if an error occurse processing the store.
-     * @deprecated use basic Store method
-     */
-    public void addAttributeCertificates(
-        X509Store store)
-        throws CMSException
-    {
-        try
-        {
-            for (Iterator it = store.getMatches(null).iterator(); it.hasNext();)
-            {
-                X509AttributeCertificate attrCert = (X509AttributeCertificate)it.next();
-
-                certs.add(new DERTaggedObject(false, 2,
-                             AttributeCertificate.getInstance(ASN1Primitive.fromByteArray(attrCert.getEncoded()))));
-            }
-        }
-        catch (IllegalArgumentException e)
-        {
-            throw new CMSException("error processing attribute certs", e);
-        }
-        catch (IOException e)
-        {
-            throw new CMSException("error processing attribute certs", e);
-        }
-    }
-
-
-    /**
-     * Add a store of precalculated signers to the generator.
+     * Add a store of pre-calculated signers to the generator.
      *
      * @param signerStore store of signers
      */
@@ -365,6 +224,11 @@
         }
     }
 
+    /**
+     * Add a generator for a particular signer to this CMS SignedData generator.
+     *
+     * @param infoGen the generator representing the particular signer.
+     */
     public void addSignerInfoGenerator(SignerInfoGenerator infoGen)
     {
          signerGens.add(infoGen);
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedHelper.java b/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedHelper.java
index 7612b5f..11a927c 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedHelper.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedHelper.java
@@ -1,14 +1,8 @@
 package org.bouncycastle.cms;
 
-import java.io.IOException;
-import java.security.Provider;
-import java.security.cert.CRLException;
-import java.security.cert.CertificateException;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -37,16 +31,8 @@
 import org.bouncycastle.cert.X509AttributeCertificateHolder;
 import org.bouncycastle.cert.X509CRLHolder;
 import org.bouncycastle.cert.X509CertificateHolder;
-// BEGIN android-removed
-// import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
-// import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-// END android-removed
 import org.bouncycastle.util.CollectionStore;
 import org.bouncycastle.util.Store;
-import org.bouncycastle.x509.NoSuchStoreException;
-import org.bouncycastle.x509.X509CollectionStoreParameters;
-import org.bouncycastle.x509.X509Store;
-import org.bouncycastle.x509.X509V2AttributeCertificate;
 
 class CMSSignedHelper
 {
@@ -64,9 +50,7 @@
 
     static
     {
-        // BEGIN android-removed
-        // addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA");
-        // END android-removed
+        addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA");
         addEntries(NISTObjectIdentifiers.dsa_with_sha256, "SHA256", "DSA");
         addEntries(NISTObjectIdentifiers.dsa_with_sha384, "SHA384", "DSA");
         addEntries(NISTObjectIdentifiers.dsa_with_sha512, "SHA512", "DSA");
@@ -83,24 +67,18 @@
         // END android-removed
         addEntries(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5", "RSA");
         addEntries(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1", "RSA");
-        // BEGIN android-removed
-        // addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
-        // END android-removed
+        addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
         addEntries(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256", "RSA");
         addEntries(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384", "RSA");
         addEntries(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512", "RSA");
         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1", "ECDSA");
-        // BEGIN android-removed
-        // addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA");
-        // END android-removed
+        addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA");
         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256", "ECDSA");
         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384", "ECDSA");
         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512", "ECDSA");
         addEntries(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1", "DSA");
         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1", "ECDSA");
-        // BEGIN android-removed
-        // addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
-        // END android-removed
+        addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256", "ECDSA");
         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384", "ECDSA");
         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512", "ECDSA");
@@ -127,9 +105,7 @@
         // END android-removed
         digestAlgs.put(PKCSObjectIdentifiers.md5.getId(), "MD5");
         digestAlgs.put(OIWObjectIdentifiers.idSHA1.getId(), "SHA1");
-        // BEGIN android-removed
-        // digestAlgs.put(NISTObjectIdentifiers.id_sha224.getId(), "SHA224");
-        // END android-removed
+        digestAlgs.put(NISTObjectIdentifiers.id_sha224.getId(), "SHA224");
         digestAlgs.put(NISTObjectIdentifiers.id_sha256.getId(), "SHA256");
         digestAlgs.put(NISTObjectIdentifiers.id_sha384.getId(), "SHA384");
         digestAlgs.put(NISTObjectIdentifiers.id_sha512.getId(), "SHA512");
@@ -142,30 +118,12 @@
         // END android-removed
 
         digestAliases.put("SHA1", new String[] { "SHA-1" });
-        // BEGIN android-removed
-        // digestAliases.put("SHA224", new String[] { "SHA-224" });
-        // END android-removed
+        digestAliases.put("SHA224", new String[] { "SHA-224" });
         digestAliases.put("SHA256", new String[] { "SHA-256" });
         digestAliases.put("SHA384", new String[] { "SHA-384" });
         digestAliases.put("SHA512", new String[] { "SHA-512" });
     }
-    
-    /**
-     * Return the digest algorithm using one of the standard JCA string
-     * representations rather than the algorithm identifier (if possible).
-     */
-    String getDigestAlgName(
-        String digestAlgOID)
-    {
-        String algName = (String)digestAlgs.get(digestAlgOID);
 
-        if (algName != null)
-        {
-            return algName;
-        }
-
-        return digestAlgOID;
-    }
 
     /**
      * Return the digest encryption algorithm using one of the standard
@@ -185,97 +143,6 @@
         return encryptionAlgOID;
     }
 
-    X509Store createAttributeStore(
-        String type,
-        Provider provider,
-        Store certStore)
-        throws NoSuchStoreException, CMSException
-    {
-        try
-        {
-            Collection certHldrs = certStore.getMatches(null);
-            List       certs = new ArrayList(certHldrs.size());
-
-            for (Iterator it = certHldrs.iterator(); it.hasNext();)
-            {
-                certs.add(new X509V2AttributeCertificate(((X509AttributeCertificateHolder)it.next()).getEncoded()));
-            }
-
-            return X509Store.getInstance(
-                         "AttributeCertificate/" +type, new X509CollectionStoreParameters(certs), provider);
-        }
-        catch (IllegalArgumentException e)
-        {
-            throw new CMSException("can't setup the X509Store", e);
-        }
-        catch (IOException e)
-        {
-            throw new CMSException("can't setup the X509Store", e);
-        }
-    }
-
-    // BEGIN android-removed
-    // X509Store createCertificateStore(
-    //     String type,
-    //     Provider provider,
-    //     Store certStore)
-    //     throws NoSuchStoreException, CMSException
-    // {
-    //     try
-    //     {
-    //         JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider(provider);
-    //         Collection certHldrs = certStore.getMatches(null);
-    //         List       certs = new ArrayList(certHldrs.size());
-    //
-    //         for (Iterator it = certHldrs.iterator(); it.hasNext();)
-    //         {
-    //             certs.add(converter.getCertificate((X509CertificateHolder)it.next()));
-    //         }
-    //
-    //         return X509Store.getInstance(
-    //                      "Certificate/" +type, new X509CollectionStoreParameters(certs), provider);
-    //     }
-    //     catch (IllegalArgumentException e)
-    //     {
-    //         throw new CMSException("can't setup the X509Store", e);
-    //     }
-    //     catch (CertificateException e)
-    //     {
-    //         throw new CMSException("can't setup the X509Store", e);
-    //     }
-    // }
-    //
-    // X509Store createCRLsStore(
-    //     String type,
-    //     Provider provider,
-    //     Store    crlStore)
-    //     throws NoSuchStoreException, CMSException
-    // {
-    //     try
-    //     {
-    //         JcaX509CRLConverter converter = new JcaX509CRLConverter().setProvider(provider);
-    //         Collection crlHldrs = crlStore.getMatches(null);
-    //         List       crls = new ArrayList(crlHldrs.size());
-    //
-    //         for (Iterator it = crlHldrs.iterator(); it.hasNext();)
-    //         {
-    //             crls.add(converter.getCRL((X509CRLHolder)it.next()));
-    //         }
-    //
-    //         return X509Store.getInstance(
-    //                      "CRL/" +type, new X509CollectionStoreParameters(crls), provider);
-    //     }
-    //     catch (IllegalArgumentException e)
-    //     {
-    //         throw new CMSException("can't setup the X509Store", e);
-    //     }
-    //     catch (CRLException e)
-    //     {
-    //         throw new CMSException("can't setup the X509Store", e);
-    //     }
-    // }
-    // END android-removed
-
     AlgorithmIdentifier fixAlgID(AlgorithmIdentifier algId)
     {
         if (algId.getParameters() == null)
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/CMSUtils.java b/bcpkix/src/main/java/org/bouncycastle/cms/CMSUtils.java
index ccfab32..d6126b6 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/CMSUtils.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/CMSUtils.java
@@ -3,15 +3,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.security.NoSuchProviderException;
-import java.security.Provider;
-import java.security.Security;
-import java.security.cert.CRLException;
-import java.security.cert.CertStore;
-import java.security.cert.CertStoreException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509CRL;
-import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
@@ -21,7 +12,6 @@
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1InputStream;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Set;
 import org.bouncycastle.asn1.BEROctetStringGenerator;
 import org.bouncycastle.asn1.BERSet;
@@ -29,15 +19,11 @@
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
 import org.bouncycastle.asn1.cms.ContentInfo;
-import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
 // BEGIN android-removed
 // import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat;
 // import org.bouncycastle.asn1.ocsp.OCSPResponse;
 // import org.bouncycastle.asn1.ocsp.OCSPResponseStatus;
 // END android-removed
-import org.bouncycastle.asn1.x509.Certificate;
-import org.bouncycastle.asn1.x509.CertificateList;
-import org.bouncycastle.asn1.x509.TBSCertificate;
 import org.bouncycastle.cert.X509AttributeCertificateHolder;
 import org.bouncycastle.cert.X509CRLHolder;
 import org.bouncycastle.cert.X509CertificateHolder;
@@ -65,36 +51,6 @@
         return readContentInfo(new ASN1InputStream(input));
     } 
 
-    static List getCertificatesFromStore(CertStore certStore)
-        throws CertStoreException, CMSException
-    {
-        List certs = new ArrayList();
-
-        try
-        {
-            for (Iterator it = certStore.getCertificates(null).iterator(); it.hasNext();)
-            {
-                X509Certificate c = (X509Certificate)it.next();
-
-                certs.add(Certificate.getInstance(ASN1Primitive.fromByteArray(c.getEncoded())));
-            }
-
-            return certs;
-        }
-        catch (IllegalArgumentException e)
-        {
-            throw new CMSException("error processing certs", e);
-        }
-        catch (IOException e)
-        {
-            throw new CMSException("error processing certs", e);
-        }
-        catch (CertificateEncodingException e)
-        {
-            throw new CMSException("error encoding certs", e);
-        }
-    }
-
     static List getCertificatesFromStore(Store certStore)
         throws CMSException
     {
@@ -139,35 +95,6 @@
         }
     }
 
-    static List getCRLsFromStore(CertStore certStore)
-        throws CertStoreException, CMSException
-    {
-        List crls = new ArrayList();
-
-        try
-        {
-            for (Iterator it = certStore.getCRLs(null).iterator(); it.hasNext();)
-            {
-                X509CRL c = (X509CRL)it.next();
-
-                crls.add(CertificateList.getInstance(ASN1Primitive.fromByteArray(c.getEncoded())));
-            }
-
-            return crls;
-        }
-        catch (IllegalArgumentException e)
-        {
-            throw new CMSException("error processing crls", e);
-        }
-        catch (IOException e)
-        {
-            throw new CMSException("error processing crls", e);
-        }
-        catch (CRLException e)
-        {
-            throw new CMSException("error encoding crls", e);
-        }
-    }
 
     static List getCRLsFromStore(Store crlStore)
         throws CMSException
@@ -254,27 +181,6 @@
         return octGen.getOctetOutputStream();
     }
 
-    static TBSCertificate getTBSCertificateStructure(
-        X509Certificate cert)
-    {
-        try
-        {
-            return TBSCertificate.getInstance(
-                ASN1Primitive.fromByteArray(cert.getTBSCertificate()));
-        }
-        catch (Exception e)
-        {
-            throw new IllegalArgumentException(
-                "can't extract TBS structure from this cert");
-        }
-    }
-
-    static IssuerAndSerialNumber getIssuerAndSerialNumber(X509Certificate cert)
-    {
-        TBSCertificate tbsCert = getTBSCertificateStructure(cert);
-        return new IssuerAndSerialNumber(tbsCert.getIssuer(), tbsCert.getSerialNumber().getValue());
-    }
-
     private static ContentInfo readContentInfo(
         ASN1InputStream in)
         throws CMSException
@@ -312,24 +218,6 @@
         return Streams.readAllLimited(in, limit);
     }
 
-    public static Provider getProvider(String providerName)
-        throws NoSuchProviderException
-    {
-        if (providerName != null)
-        {
-            Provider prov = Security.getProvider(providerName);
-
-            if (prov != null)
-            {
-                return prov;
-            }
-
-            throw new NoSuchProviderException("provider " + providerName + " not found.");
-        }
-
-        return null; 
-    }
-
     static InputStream attachDigestsToInputStream(Collection digests, InputStream s)
     {
         InputStream result = s;
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java b/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java
index bb20ee6..a9997a4 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java
@@ -30,9 +30,7 @@
 
     public DefaultCMSSignatureAlgorithmNameGenerator()
     {
-        // BEGIN android-removed
-        // addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA");
-        // END android-removed
+        addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA");
         addEntries(NISTObjectIdentifiers.dsa_with_sha256, "SHA256", "DSA");
         addEntries(NISTObjectIdentifiers.dsa_with_sha384, "SHA384", "DSA");
         addEntries(NISTObjectIdentifiers.dsa_with_sha512, "SHA512", "DSA");
@@ -49,24 +47,18 @@
         // END android-removed
         addEntries(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5", "RSA");
         addEntries(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1", "RSA");
-        // BEGIN android-removed
-        // addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
-        // END android-removed
+        addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
         addEntries(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256", "RSA");
         addEntries(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384", "RSA");
         addEntries(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512", "RSA");
         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1", "ECDSA");
-        // BEGIN android-removed
-        // addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA");
-        // END android-removed
+        addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA");
         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256", "ECDSA");
         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384", "ECDSA");
         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512", "ECDSA");
         addEntries(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1", "DSA");
         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1", "ECDSA");
-        // BEGIN android-removed
-        // addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
-        // END android-removed
+        addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256", "ECDSA");
         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384", "ECDSA");
         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512", "ECDSA");
@@ -93,9 +85,7 @@
         // END android-removed
         digestAlgs.put(PKCSObjectIdentifiers.md5, "MD5");
         digestAlgs.put(OIWObjectIdentifiers.idSHA1, "SHA1");
-        // BEGIN android-removed
-        // digestAlgs.put(NISTObjectIdentifiers.id_sha224, "SHA224");
-        // END android-removed
+        digestAlgs.put(NISTObjectIdentifiers.id_sha224, "SHA224");
         digestAlgs.put(NISTObjectIdentifiers.id_sha256, "SHA256");
         digestAlgs.put(NISTObjectIdentifiers.id_sha384, "SHA384");
         digestAlgs.put(NISTObjectIdentifiers.id_sha512, "SHA512");
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java b/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java
index c51523a..e8ebc83 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java
@@ -22,9 +22,7 @@
         // END android-removed
         RSA_PKCS1d5.add(PKCSObjectIdentifiers.md5WithRSAEncryption);
         RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha1WithRSAEncryption);
-        // BEGIN android-removed
-        // RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
-        // END android-removed
+        RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
         RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha256WithRSAEncryption);
         RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha384WithRSAEncryption);
         RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha512WithRSAEncryption);
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java b/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java
index 8ba3686..837edd8 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java
@@ -1,6 +1,7 @@
 package org.bouncycastle.cms;
 
 import java.util.Date;
+import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Map;
 
@@ -59,7 +60,7 @@
     protected Hashtable createStandardAttributeTable(
         Map parameters)
     {
-        Hashtable std = (Hashtable)table.clone();
+        Hashtable std = copyHashTable(table);
 
         if (!std.containsKey(CMSAttributes.contentType))
         {
@@ -103,4 +104,18 @@
     {
         return new AttributeTable(createStandardAttributeTable(parameters));
     }
+
+    private static Hashtable copyHashTable(Hashtable paramsMap)
+    {
+        Hashtable newTable = new Hashtable();
+
+        Enumeration keys = paramsMap.keys();
+        while (keys.hasMoreElements())
+        {
+            Object key = keys.nextElement();
+            newTable.put(key, paramsMap.get(key));
+        }
+
+        return newTable;
+    }
 }
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGenerator.java b/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGenerator.java
index e378629..f264729 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGenerator.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGenerator.java
@@ -7,7 +7,6 @@
 import java.util.Map;
 
 import org.bouncycastle.asn1.ASN1Encoding;
-import org.bouncycastle.asn1.ASN1Integer;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1Set;
 import org.bouncycastle.asn1.DEROctetString;
@@ -23,6 +22,7 @@
 import org.bouncycastle.operator.DigestCalculator;
 import org.bouncycastle.operator.DigestCalculatorProvider;
 import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.util.Arrays;
 import org.bouncycastle.util.io.TeeOutputStream;
 
 public class SignerInfoGenerator
@@ -126,9 +126,9 @@
         return signerIdentifier;
     }
 
-    public ASN1Integer getGeneratedVersion()
+    public int getGeneratedVersion()
     {
-        return new ASN1Integer(signerIdentifier.isTagged() ? 3 : 1);
+        return signerIdentifier.isTagged() ? 3 : 1;
     }
 
     public boolean hasAssociatedCertificate()
@@ -221,7 +221,7 @@
             if (unsAttrGen != null)
             {
                 Map parameters = getBaseParameters(contentType, digestAlg, calculatedDigest);
-                parameters.put(CMSAttributeTableGenerator.SIGNATURE, sigBytes.clone());
+                parameters.put(CMSAttributeTableGenerator.SIGNATURE, Arrays.clone(sigBytes));
 
                 AttributeTable unsigned = unsAttrGen.getAttributes(Collections.unmodifiableMap(parameters));
 
@@ -265,7 +265,7 @@
         }
 
         param.put(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER, digAlgId);
-        param.put(CMSAttributeTableGenerator.DIGEST,  hash.clone());
+        param.put(CMSAttributeTableGenerator.DIGEST,  Arrays.clone(hash));
         return param;
     }
 
@@ -273,7 +273,7 @@
     {
         if (calculatedDigest != null)
         {
-            return (byte[])calculatedDigest.clone();
+            return Arrays.clone(calculatedDigest);
         }
 
         return null;
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformation.java b/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformation.java
index bd9703a..7e178d6 100644
--- a/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformation.java
+++ b/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformation.java
@@ -2,13 +2,6 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.Provider;
-import java.security.PublicKey;
-import java.security.cert.CertificateExpiredException;
-import java.security.cert.CertificateNotYetValidException;
-import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.Iterator;
@@ -33,13 +26,10 @@
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.DigestInfo;
 import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cms.jcajce.JcaSignerInfoVerifierBuilder;
-import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
 import org.bouncycastle.operator.ContentVerifier;
 import org.bouncycastle.operator.DigestCalculator;
 import org.bouncycastle.operator.OperatorCreationException;
 import org.bouncycastle.operator.RawContentVerifier;
-import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
 import org.bouncycastle.util.Arrays;
 import org.bouncycastle.util.io.TeeOutputStream;
 
@@ -172,7 +162,7 @@
             throw new IllegalStateException("method can only be called after verify.");
         }
         
-        return (byte[])resultDigest.clone();
+        return Arrays.clone(resultDigest);
     }
     
     /**
@@ -232,7 +222,7 @@
      */
     public byte[] getSignature()
     {
-        return (byte[])signature.clone();
+        return Arrays.clone(signature);
     }
 
     /**
@@ -318,42 +308,6 @@
         return null;
     }
 
-    /**
-     * @deprecated
-     */
-    private boolean doVerify(
-        PublicKey       key,
-        Provider        sigProvider)
-        throws CMSException, NoSuchAlgorithmException
-    {
-        try
-        {
-            SignerInformationVerifier verifier;
-
-            if (sigProvider != null)
-            {
-                if (!sigProvider.getName().equalsIgnoreCase("BC"))
-                {
-                    verifier = new JcaSignerInfoVerifierBuilder(new JcaDigestCalculatorProviderBuilder().build()).setProvider(sigProvider).build(key);
-                }
-                else
-                {
-                    verifier = new JcaSimpleSignerInfoVerifierBuilder().setProvider(sigProvider).build(key);
-                }
-            }
-            else
-            {
-                verifier = new JcaSimpleSignerInfoVerifierBuilder().build(key);
-            }
-
-            return doVerify(verifier);
-        }
-        catch (OperatorCreationException e)
-        {
-            throw new CMSException("unable to create verifier: " + e.getMessage(), e);
-        }
-    }
-
     private boolean doVerify(
         SignerInformationVerifier verifier)
         throws CMSException
@@ -555,75 +509,6 @@
     }
 
     /**
-     * verify that the given public key successfully handles and confirms the
-     * signature associated with this signer.
-     * @deprecated use verify(ContentVerifierProvider)
-     */
-    public boolean verify(
-        PublicKey   key,
-        String      sigProvider)
-        throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
-    {
-        return verify(key, CMSUtils.getProvider(sigProvider));
-    }
-
-    /**
-     * verify that the given public key successfully handles and confirms the
-     * signature associated with this signer
-     * @deprecated use verify(ContentVerifierProvider)
-     */
-    public boolean verify(
-        PublicKey   key,
-        Provider    sigProvider)
-        throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
-    {
-        // Optional, but still need to validate if present
-        getSigningTime();
-
-        return doVerify(key, sigProvider);
-    }
-
-    /**
-     * verify that the given certificate successfully handles and confirms
-     * the signature associated with this signer and, if a signingTime
-     * attribute is available, that the certificate was valid at the time the
-     * signature was generated.
-     * @deprecated use verify(ContentVerifierProvider)
-     */
-    public boolean verify(
-        X509Certificate cert,
-        String          sigProvider)
-        throws NoSuchAlgorithmException, NoSuchProviderException,
-            CertificateExpiredException, CertificateNotYetValidException,
-            CMSException
-    {
-        return verify(cert, CMSUtils.getProvider(sigProvider));
-    }
-
-    /**
-     * verify that the given certificate successfully handles and confirms
-     * the signature associated with this signer and, if a signingTime
-     * attribute is available, that the certificate was valid at the time the
-     * signature was generated.
-     * @deprecated use verify(ContentVerifierProvider)
-     */
-    public boolean verify(
-        X509Certificate cert,
-        Provider        sigProvider)
-        throws NoSuchAlgorithmException,
-            CertificateExpiredException, CertificateNotYetValidException,
-            CMSException
-    {
-        Time signingTime = getSigningTime();
-        if (signingTime != null)
-        {
-            cert.checkValidity(signingTime.getDate());
-        }
-
-        return doVerify(cert.getPublicKey(), sigProvider); 
-    }
-
-    /**
      * Verify that the given verifier can successfully verify the signature on
      * this SignerInformation object.
      *
@@ -654,17 +539,6 @@
     }
 
     /**
-     * Return the base ASN.1 CMS structure that this object contains.
-     * 
-     * @return an object containing a CMS SignerInfo structure.
-     * @deprecated use toASN1Structure()
-     */
-    public SignerInfo toSignerInfo()
-    {
-        return info;
-    }
-
-    /**
      * Return the underlying ASN.1 object defining this SignerInformation object.
      *
      * @return a SignerInfo.
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java b/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
index 8e4d2b7..293370f 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
@@ -33,9 +33,7 @@
         // END android-removed
         digestOids.put(OIWObjectIdentifiers.sha1WithRSA, OIWObjectIdentifiers.idSHA1);
 
-        // BEGIN android-removed
-        // digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
-        // END android-removed
+        digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
         digestOids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256);
         digestOids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384);
         digestOids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512);
@@ -47,17 +45,13 @@
         digestOids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, OIWObjectIdentifiers.idSHA1);
 
         digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, OIWObjectIdentifiers.idSHA1);
-        // BEGIN android-removed
-        // digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, NISTObjectIdentifiers.id_sha224);
-        // END android-removed
+        digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, NISTObjectIdentifiers.id_sha224);
         digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, NISTObjectIdentifiers.id_sha256);
         digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, NISTObjectIdentifiers.id_sha384);
         digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, NISTObjectIdentifiers.id_sha512);
         digestOids.put(X9ObjectIdentifiers.id_dsa_with_sha1, OIWObjectIdentifiers.idSHA1);
 
-        // BEGIN android-removed
-        // digestOids.put(NISTObjectIdentifiers.dsa_with_sha224, NISTObjectIdentifiers.id_sha224);
-        // END android-removed
+        digestOids.put(NISTObjectIdentifiers.dsa_with_sha224, NISTObjectIdentifiers.id_sha224);
         digestOids.put(NISTObjectIdentifiers.dsa_with_sha256, NISTObjectIdentifiers.id_sha256);
         digestOids.put(NISTObjectIdentifiers.dsa_with_sha384, NISTObjectIdentifiers.id_sha384);
         digestOids.put(NISTObjectIdentifiers.dsa_with_sha512, NISTObjectIdentifiers.id_sha512);
@@ -72,9 +66,7 @@
         // END android-removed
 
         digestNameToOids.put("SHA-1", OIWObjectIdentifiers.idSHA1);
-        // BEGIN android-removed
-        // digestNameToOids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
-        // END android-removed
+        digestNameToOids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
         digestNameToOids.put("SHA-256", NISTObjectIdentifiers.id_sha256);
         digestNameToOids.put("SHA-384", NISTObjectIdentifiers.id_sha384);
         digestNameToOids.put("SHA-512", NISTObjectIdentifiers.id_sha512);
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java b/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
index b73c5ce..808eb4e 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
@@ -49,10 +49,8 @@
         algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
         algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
         algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-        // algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-        // END android-removed
+        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
         algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
         algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
         algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
@@ -60,9 +58,7 @@
         algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
         algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
         algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
-        // END android-removed
+        algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
         algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
         algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
         algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
@@ -76,17 +72,13 @@
         // END android-removed
         algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
         algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
-        // END android-removed
+        algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
         algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
         algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
         algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
         algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
         algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
-        // END android-removed
+        algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
         algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
         algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
         algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
@@ -103,16 +95,12 @@
         // The parameters field SHALL be NULL for RSA based signature algorithms.
         //
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
-        // BEGIN android-removed
-        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
-        // END android-removed
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
         noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
-        // BEGIN android-removed
-        // noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
-        // END android-removed
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
         noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
         noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
         noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
@@ -129,9 +117,7 @@
         // PKCS 1.5 encrypted  algorithms
         //
         pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha1WithRSAEncryption);
-        // BEGIN android-removed
-        // pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
-        // END android-removed
+        pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
         pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha256WithRSAEncryption);
         pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha384WithRSAEncryption);
         pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha512WithRSAEncryption);
@@ -147,10 +133,8 @@
         AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
         params.put("SHA1WITHRSAANDMGF1", createPSSParams(sha1AlgId, 20));
 
-        // BEGIN android-removed
-        // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
-        // params.put("SHA224WITHRSAANDMGF1", createPSSParams(sha224AlgId, 28));
-        // END android-removed
+        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+        params.put("SHA224WITHRSAANDMGF1", createPSSParams(sha224AlgId, 28));
 
         AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
         params.put("SHA256WITHRSAANDMGF1", createPSSParams(sha256AlgId, 32));
@@ -164,9 +148,7 @@
         //
         // digests
         //
-        // BEGIN android-removed
-        // digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
-        // END android-removed
+        digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
         digestOids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256);
         digestOids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384);
         digestOids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512);
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java b/bcpkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java
index a2c47c2..805dc47 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java
@@ -25,9 +25,7 @@
 // import org.bouncycastle.crypto.digests.RIPEMD256Digest;
 // END android-removed
 import org.bouncycastle.crypto.digests.SHA1Digest;
-// BEGIN android-removed
-// import org.bouncycastle.crypto.digests.SHA224Digest;
-// END android-removed
+import org.bouncycastle.crypto.digests.SHA224Digest;
 import org.bouncycastle.crypto.digests.SHA256Digest;
 import org.bouncycastle.crypto.digests.SHA384Digest;
 import org.bouncycastle.crypto.digests.SHA512Digest;
@@ -49,15 +47,13 @@
                 return new SHA1Digest();
             }
         });
-        // BEGIN android-removed
-        // table.put(NISTObjectIdentifiers.id_sha224, new BcDigestProvider()
-        // {
-        //     public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
-        //     {
-        //         return new SHA224Digest();
-        //     }
-        // });
-        // END android-removed
+        table.put(NISTObjectIdentifiers.id_sha224, new BcDigestProvider()
+        {
+            public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+            {
+                return new SHA224Digest();
+            }
+        });
         table.put(NISTObjectIdentifiers.id_sha256, new BcDigestProvider()
         {
             public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java b/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
index 56c3771..87a6699 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
@@ -12,6 +12,7 @@
 import java.security.cert.X509Certificate;
 
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.cert.X509CertificateHolder;
 import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
 import org.bouncycastle.jcajce.DefaultJcaJceHelper;
@@ -144,6 +145,12 @@
         };
     }
 
+    public ContentVerifierProvider build(SubjectPublicKeyInfo publicKey)
+        throws OperatorCreationException
+    {
+        return this.build(helper.convertPublicKey(publicKey));
+    }
+
     private SignatureOutputStream createSignatureStream(AlgorithmIdentifier algorithm, PublicKey publicKey)
         throws OperatorCreationException
     {
diff --git a/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java b/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java
index 2520f95..74c1b28 100644
--- a/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java
+++ b/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java
@@ -4,14 +4,18 @@
 import java.io.IOException;
 import java.security.AlgorithmParameters;
 import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
+import java.security.PublicKey;
 import java.security.Signature;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PSSParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -31,9 +35,11 @@
 import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
 import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 import org.bouncycastle.cert.X509CertificateHolder;
 import org.bouncycastle.jcajce.JcaJceHelper;
+import org.bouncycastle.jcajce.JcaJceUtils;
 import org.bouncycastle.operator.OperatorCreationException;
 
 class OperatorHelper
@@ -49,9 +55,7 @@
         // reverse mappings
         //
         oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
-        // BEGIN android-removed
-        // oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
-        // END android-removed
+        oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
         oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
         oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
         oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
@@ -66,17 +70,13 @@
         // END android-removed
         oids.put(new ASN1ObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
-        // BEGIN android-removed
-        // oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
-        // END android-removed
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
         oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
         oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA");
-        // BEGIN android-removed
-        // oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
-        // END android-removed
+        oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
         oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
 
         oids.put(OIWObjectIdentifiers.idSHA1, "SHA-1");
@@ -193,6 +193,41 @@
         }
     }
 
+    AlgorithmParameters createAlgorithmParameters(AlgorithmIdentifier cipherAlgId)
+        throws OperatorCreationException
+    {
+        AlgorithmParameters parameters;
+
+        if (cipherAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption))
+        {
+            return null;
+        }
+
+        try
+        {
+            parameters = helper.createAlgorithmParameters(cipherAlgId.getAlgorithm().getId());
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            return null;   // There's a good chance there aren't any!
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new OperatorCreationException("cannot create algorithm parameters: " + e.getMessage(), e);
+        }
+
+        try
+        {
+            parameters.init(cipherAlgId.getParameters().toASN1Primitive().getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new OperatorCreationException("cannot initialise algorithm parameters: " + e.getMessage(), e);
+        }
+
+        return parameters;
+    }
+
     MessageDigest createDigest(AlgorithmIdentifier digAlgId)
         throws GeneralSecurityException
     {
@@ -270,7 +305,7 @@
             {
                 AlgorithmParameters params = helper.createAlgorithmParameters(algName);
 
-                params.init(algorithm.getParameters().toASN1Primitive().getEncoded(), "ASN.1");
+                JcaJceUtils.loadParameters(params, algorithm.getParameters());
 
                 PSSParameterSpec spec = (PSSParameterSpec)params.getParameterSpec(PSSParameterSpec.class);
                 sig.setParameter(spec);
@@ -317,12 +352,10 @@
         {
             return "SHA1";
         }
-        // BEGIN android-removed
-        // else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
-        // {
-        //     return "SHA224";
-        // }
-        // END android-removed
+        else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+        {
+            return "SHA224";
+        }
         else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
         {
             return "SHA256";
@@ -383,6 +416,33 @@
         }
     }
 
+    public PublicKey convertPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+        throws OperatorCreationException
+    {
+        try
+        {
+            KeyFactory keyFact = helper.createKeyFactory(publicKeyInfo.getAlgorithm().getAlgorithm().getId());
+
+            return keyFact.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded()));
+        }
+        catch (IOException e)
+        {
+            throw new OperatorCreationException("cannot get encoded form of key: " + e.getMessage(), e);
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new OperatorCreationException("cannot find factory provider: " + e.getMessage(), e);
+        }
+        catch (InvalidKeySpecException e)
+        {
+            throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
+        }
+    }
+
     // TODO: put somewhere public so cause easily accessed
     private static class OpCertificateException
         extends CertificateException
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java
index 7281a6a..98ab0d6 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java
@@ -11,9 +11,9 @@
     public static final int EXTERNAL            = 0x08;
     public static final int ENUMERATED          = 0x0a;
     public static final int SEQUENCE            = 0x10;
-    public static final int SEQUENCE_OF         = 0x10; // for completeness
+    public static final int SEQUENCE_OF         = 0x10; // for completeness - used to model a SEQUENCE of the same type.
     public static final int SET                 = 0x11;
-    public static final int SET_OF              = 0x11; // for completeness
+    public static final int SET_OF              = 0x11; // for completeness - used to model a SET of the same type.
 
 
     public static final int NUMERIC_STRING      = 0x12;
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java
index 74acda6..634f5a8 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java
@@ -177,7 +177,7 @@
     {
         if (value.length != 1)
         {
-            throw new IllegalArgumentException("byte value should have 1 byte in it");
+            throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it");
         }
 
         if (value[0] == 0)
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java b/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
index 2f299ee..9b1ef55 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
@@ -5,6 +5,9 @@
 
 import org.bouncycastle.util.Arrays;
 
+/**
+ * Use ASN1Enumerated instead of this.
+ */
 public class DEREnumerated
     extends ASN1Primitive
 {
@@ -52,7 +55,7 @@
      * @exception IllegalArgumentException if the tagged object cannot
      *               be converted.
      */
-    public static DEREnumerated getInstance(
+    public static ASN1Enumerated getInstance(
         ASN1TaggedObject obj,
         boolean          explicit)
     {
@@ -68,18 +71,27 @@
         }
     }
 
+    /**
+     * @deprecated use ASN1Enumerated
+     */
     public DEREnumerated(
         int         value)
     {
         bytes = BigInteger.valueOf(value).toByteArray();
     }
 
+    /**
+     * @deprecated use ASN1Enumerated
+     */
     public DEREnumerated(
         BigInteger   value)
     {
         bytes = value.toByteArray();
     }
 
+    /**
+     * @deprecated use ASN1Enumerated
+     */
     public DEREnumerated(
         byte[]   bytes)
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java
index 3804450..57cc84a 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java
@@ -5,6 +5,9 @@
 
 import org.bouncycastle.util.Arrays;
 
+/**
+ * Use ASN1Integer instead of this,
+ */
 public class DERInteger
     extends ASN1Primitive
 {
@@ -67,18 +70,27 @@
         }
     }
 
+    /**
+     * @deprecated use ASN1Integer constructor
+     */
     public DERInteger(
         long         value)
     {
         bytes = BigInteger.valueOf(value).toByteArray();
     }
 
+    /**
+     * @deprecated use ASN1Integer constructor
+     */
     public DERInteger(
         BigInteger   value)
     {
         bytes = value.toByteArray();
     }
 
+    /**
+     * @deprecated use ASN1Integer constructor
+     */
     public DERInteger(
         byte[]   bytes)
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
index 13e1195..b82647e 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
@@ -6,6 +6,9 @@
 
 import org.bouncycastle.util.Arrays;
 
+/**
+ * Use ASN1ObjectIdentifier instead of this,
+ */
 public class DERObjectIdentifier
     extends ASN1Primitive
 {
@@ -38,7 +41,22 @@
 
         if (obj instanceof byte[])
         {
-            return ASN1ObjectIdentifier.fromOctetString((byte[])obj);
+            byte[] enc = (byte[])obj;
+            if (enc[0] == BERTags.OBJECT_IDENTIFIER)
+            {
+                try
+                {
+                    return (ASN1ObjectIdentifier)fromByteArray(enc);
+                }
+                catch (IOException e)
+                {
+                    throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
+                }
+            }
+            else
+            {    // TODO: this really shouldn't be supported here...
+                return ASN1ObjectIdentifier.fromOctetString((byte[])obj);
+            }
         }
 
         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
@@ -154,6 +172,9 @@
         this.body = Arrays.clone(bytes);
     }
 
+    /**
+     * @deprecated use ASN1ObjectIdentifier constructor.
+     */
     public DERObjectIdentifier(
         String identifier)
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java
index bb8ec4e..b5cc59a 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java
@@ -3,20 +3,23 @@
 import java.io.IOException;
 import java.util.Enumeration;
 
+/**
+ * The DLSequence encodes a SEQUENCE using definite length form.
+ */
 public class DLSequence
     extends ASN1Sequence
 {
     private int bodyLength = -1;
 
     /**
-     * create an empty sequence
+     * Create an empty sequence
      */
     public DLSequence()
     {
     }
 
     /**
-     * create a sequence containing one object
+     * Create a sequence containing one object
      */
     public DLSequence(
         ASN1Encodable obj)
@@ -25,7 +28,7 @@
     }
 
     /**
-     * create a sequence containing a vector of objects.
+     * Create a sequence containing a vector of objects.
      */
     public DLSequence(
         ASN1EncodableVector v)
@@ -34,7 +37,7 @@
     }
 
     /**
-     * create a sequence containing an array of objects.
+     * Create a sequence containing an array of objects.
      */
     public DLSequence(
         ASN1Encodable[] array)
@@ -51,7 +54,7 @@
 
             for (Enumeration e = this.getObjects(); e.hasMoreElements();)
             {
-                Object    obj = e.nextElement();
+                Object obj = e.nextElement();
 
                 length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength();
             }
@@ -65,12 +68,12 @@
     int encodedLength()
         throws IOException
     {
-        int    length = getBodyLength();
+        int length = getBodyLength();
 
         return 1 + StreamUtil.calculateBodyLength(length) + length;
     }
 
-    /*
+    /**
      * A note on the implementation:
      * <p>
      * As DL requires the constructed, definite-length model to
@@ -82,17 +85,17 @@
         ASN1OutputStream out)
         throws IOException
     {
-        ASN1OutputStream       dOut = out.getDLSubStream();
-        int                    length = getBodyLength();
+        ASN1OutputStream dOut = out.getDLSubStream();
+        int length = getBodyLength();
 
         out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
         out.writeLength(length);
 
         for (Enumeration e = this.getObjects(); e.hasMoreElements();)
         {
-            Object    obj = e.nextElement();
+            Object obj = e.nextElement();
 
             dOut.writeObject((ASN1Encodable)obj);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java
index 755754b..91e83fa 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java
@@ -4,7 +4,52 @@
 import java.util.Enumeration;
 
 /**
- * A DER encoded set object
+ * The DLSet encodes ASN.1 SET value without element ordering,
+ * and always using definite length form.
+ * <hr>
+ * <h2>X.690</h2>
+ * <h3>8: Basic encoding rules</h3>
+ * <h4>8.11 Encoding of a set value </h4>
+ * <b>8.11.1</b> The encoding of a set value shall be constructed
+ * <p/>
+ * <b>8.11.2</b> The contents octets shall consist of the complete
+ * encoding of a data value from each of the types listed in the
+ * ASN.1 definition of the set type, in an order chosen by the sender,
+ * unless the type was referenced with the keyword
+ * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
+ * <p/>
+ * <b>8.11.3</b> The encoding of a data value may, but need not,
+ * be present for a type which was referenced with the keyword
+ * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
+ * <blockquote>
+ * NOTE &mdash; The order of data values in a set value is not significant,
+ * and places no constraints on the order during transfer
+ * </blockquote>
+ * <h3>9: Canonical encoding rules</h3>
+ * <h4>9.3 Set components</h4>
+ * The encodings of the component values of a set value shall
+ * appear in an order determined by their tags as specified
+ * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
+ * Additionally, for the purposes of determining the order in which
+ * components are encoded when one or more component is an untagged
+ * choice type, each untagged choice type is ordered as though it
+ * has a tag equal to that of the smallest tag in that choice type
+ * or any untagged choice types nested within.
+ * <h3>10: Distinguished encoding rules</h3>
+ * <h4>10.3 Set components</h4>
+ * The encodings of the component values of a set value shall appear
+ * in an order determined by their tags as specified
+ * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
+ * <blockquote>
+ * NOTE &mdash; Where a component of the set is an untagged choice type,
+ * the location of that component in the ordering will depend on
+ * the tag of the choice component being encoded.
+ * </blockquote>
+ * <h3>11: Restrictions on BER employed by both CER and DER</h3>
+ * <h4>11.5 Set and sequence components with default value </h4>
+ * The encoding of a set value or sequence value shall not include
+ * an encoding for any component value which is equal to
+ * its default value.
  */
 public class DLSet
     extends ASN1Set
@@ -54,7 +99,7 @@
 
             for (Enumeration e = this.getObjects(); e.hasMoreElements();)
             {
-                Object    obj = e.nextElement();
+                Object obj = e.nextElement();
 
                 length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength();
             }
@@ -68,12 +113,12 @@
     int encodedLength()
         throws IOException
     {
-        int                     length = getBodyLength();
+        int length = getBodyLength();
 
         return 1 + StreamUtil.calculateBodyLength(length) + length;
     }
 
-    /*
+    /**
      * A note on the implementation:
      * <p>
      * As DL requires the constructed, definite-length model to
@@ -85,17 +130,17 @@
         ASN1OutputStream out)
         throws IOException
     {
-        ASN1OutputStream        dOut = out.getDLSubStream();
-        int                     length = getBodyLength();
+        ASN1OutputStream dOut = out.getDLSubStream();
+        int length = getBodyLength();
 
         out.write(BERTags.SET | BERTags.CONSTRUCTED);
         out.writeLength(length);
 
         for (Enumeration e = this.getObjects(); e.hasMoreElements();)
         {
-            Object    obj = e.nextElement();
+            Object obj = e.nextElement();
 
             dOut.writeObject((ASN1Encodable)obj);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
index 18fc66c..16a6768 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
@@ -2,50 +2,70 @@
 
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
+/**
+ *  iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle
+ * <p>
+ *  1.3.6.1.4.1.22554
+ */
 public interface BCObjectIdentifiers
 {
     /**
      *  iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle
-     *
+     *<p>
      *  1.3.6.1.4.1.22554
      */
     public static final ASN1ObjectIdentifier bc = new ASN1ObjectIdentifier("1.3.6.1.4.1.22554");
 
     /**
      * pbe(1) algorithms
+     * <p>
+     * 1.3.6.1.4.1.22554.1
      */
-    public static final ASN1ObjectIdentifier bc_pbe = new ASN1ObjectIdentifier(bc.getId() + ".1");
+    public static final ASN1ObjectIdentifier bc_pbe        = bc.branch("1");
 
     /**
      * SHA-1(1)
+     * <p>
+     * 1.3.6.1.4.1.22554.1.1
      */
-    public static final ASN1ObjectIdentifier bc_pbe_sha1 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".1");
+    public static final ASN1ObjectIdentifier bc_pbe_sha1   = bc_pbe.branch("1");
 
-    /**
-     * SHA-2(2) . (SHA-256(1)|SHA-384(2)|SHA-512(3)|SHA-224(4))
-     */
-    public static final ASN1ObjectIdentifier bc_pbe_sha256 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.1");
-    public static final ASN1ObjectIdentifier bc_pbe_sha384 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.2");
-    public static final ASN1ObjectIdentifier bc_pbe_sha512 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.3");
-    public static final ASN1ObjectIdentifier bc_pbe_sha224 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.4");
+    /** SHA-2.SHA-256; 1.3.6.1.4.1.22554.1.2.1 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256 = bc_pbe.branch("2.1");
+    /** SHA-2.SHA-384; 1.3.6.1.4.1.22554.1.2.2 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha384 = bc_pbe.branch("2.2");
+    /** SHA-2.SHA-512; 1.3.6.1.4.1.22554.1.2.3 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha512 = bc_pbe.branch("2.3");
+    /** SHA-2.SHA-224; 1.3.6.1.4.1.22554.1.2.4 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha224 = bc_pbe.branch("2.4");
 
     /**
      * PKCS-5(1)|PKCS-12(2)
      */
-    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs5 = new ASN1ObjectIdentifier(bc_pbe_sha1.getId() + ".1");
-    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12 = new ASN1ObjectIdentifier(bc_pbe_sha1.getId() + ".2");
+    /** SHA-1.PKCS5;  1.3.6.1.4.1.22554.1.1.1 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs5    = bc_pbe_sha1.branch("1");
+    /** SHA-1.PKCS12; 1.3.6.1.4.1.22554.1.1.2 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12   = bc_pbe_sha1.branch("2");
 
-    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs5 = new ASN1ObjectIdentifier(bc_pbe_sha256.getId() + ".1");
-    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12 = new ASN1ObjectIdentifier(bc_pbe_sha256.getId() + ".2");
+    /** SHA-256.PKCS12; 1.3.6.1.4.1.22554.1.2.1.1 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs5  = bc_pbe_sha256.branch("1");
+    /** SHA-256.PKCS12; 1.3.6.1.4.1.22554.1.2.1.2 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12 = bc_pbe_sha256.branch("2");
 
     /**
      * AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42))
      */
-    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.2");
-    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.22");
-    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.42");
+    /** 1.3.6.1.4.1.22554.1.1.2.1.2 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc   = bc_pbe_sha1_pkcs12.branch("1.2");
+    /** 1.3.6.1.4.1.22554.1.1.2.1.22 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc   = bc_pbe_sha1_pkcs12.branch("1.22");
+    /** 1.3.6.1.4.1.22554.1.1.2.1.42 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc   = bc_pbe_sha1_pkcs12.branch("1.42");
 
-    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.2");
-    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.22");
-    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.42");
+    /** 1.3.6.1.4.1.22554.1.1.2.2.2 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = bc_pbe_sha256_pkcs12.branch("1.2");
+    /** 1.3.6.1.4.1.22554.1.1.2.2.22 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = bc_pbe_sha256_pkcs12.branch("1.22");
+    /** 1.3.6.1.4.1.22554.1.1.2.2.42 */
+    public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = bc_pbe_sha256_pkcs12.branch("1.42");
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java
index b5a2f34..066cf69 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java
@@ -10,6 +10,27 @@
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSequence;
 
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#page-14">RFC 5652</a>:
+ * Attribute is a pair of OID (as type identifier) + set of values.
+ * <p>
+ * <pre>
+ * Attribute ::= SEQUENCE {
+ *     attrType OBJECT IDENTIFIER,
+ *     attrValues SET OF AttributeValue
+ * }
+ * 
+ * AttributeValue ::= ANY
+ * </pre>
+ * <p>
+ * General rule on values is that same AttributeValue must not be included
+ * multiple times into the set. That is, if the value is a SET OF INTEGERs,
+ * then having same value repeated is wrong: (1, 1), but different values is OK: (1, 2).
+ * Normally the AttributeValue syntaxes are more complicated than that.
+ * <p>
+ * General rule of Attribute usage is that the {@link Attributes} containers
+ * must not have multiple Attribute:s with same attrType (OID) there.
+ */
 public class Attribute
     extends ASN1Object
 {
@@ -17,7 +38,14 @@
     private ASN1Set             attrValues;
 
     /**
-     * return an Attribute object from the given object.
+     * Return an Attribute object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link Attribute} object
+     * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with Attribute structure inside
+     * </ul>
      *
      * @param o the object we want converted.
      * @exception IllegalArgumentException if the object cannot be converted.
@@ -81,12 +109,6 @@
 
     /** 
      * Produce an object suitable for an ASN1OutputStream.
-     * <pre>
-     * Attribute ::= SEQUENCE {
-     *     attrType OBJECT IDENTIFIER,
-     *     attrValues SET OF AttributeValue
-     * }
-     * </pre>
      */
     public ASN1Primitive toASN1Primitive()
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java
index f114623..02b6cc1 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java
@@ -11,6 +11,9 @@
 import org.bouncycastle.asn1.DERObjectIdentifier;
 import org.bouncycastle.asn1.DERSet;
 
+/**
+ * This is helper tool to construct {@link Attributes} sets.
+ */
 public class AttributeTable
 {
     private Hashtable attributes = new Hashtable();
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java
index 614e224..e21c8a7 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java
@@ -6,6 +6,21 @@
 import org.bouncycastle.asn1.ASN1Set;
 import org.bouncycastle.asn1.DLSet;
 
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652">RFC 5652</a> defines
+ * 5 "SET OF Attribute" entities with 5 different names.
+ * This is common implementation for them all:
+ * <pre>
+ *   SignedAttributes      ::= SET SIZE (1..MAX) OF Attribute
+ *   UnsignedAttributes    ::= SET SIZE (1..MAX) OF Attribute
+ *   UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *   AuthAttributes        ::= SET SIZE (1..MAX) OF Attribute
+ *   UnauthAttributes      ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * Attributes ::=
+ *   SET SIZE(1..MAX) OF Attribute
+ * </pre>
+ */
 public class Attributes
     extends ASN1Object
 {
@@ -21,6 +36,19 @@
         attributes = new DLSet(v);
     }
 
+    /**
+     * Return an Attribute set object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link Attributes} object
+     * <li> {@link org.bouncycastle.asn1.ASN1Set#getInstance(java.lang.Object) ASN1Set} input formats with Attributes structure inside
+     * </ul>
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
     public static Attributes getInstance(Object obj)
     {
         if (obj instanceof Attributes)
@@ -47,12 +75,8 @@
         return rv;
     }
 
-    /**
-     * <pre>
-     * Attributes ::=
-     *   SET SIZE(1..MAX) OF Attribute -- according to RFC 5652
-     * </pre>
-     * @return
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
      */
     public ASN1Primitive toASN1Primitive()
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java
index 5e97324..d2fc7d1 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java
@@ -3,11 +3,28 @@
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652">RFC 5652</a> CMS attribute OID constants.
+ * <pre>
+ * contentType      ::= 1.2.840.113549.1.9.3
+ * messageDigest    ::= 1.2.840.113549.1.9.4
+ * signingTime      ::= 1.2.840.113549.1.9.5
+ * counterSignature ::= 1.2.840.113549.1.9.6
+ *
+ * contentHint      ::= 1.2.840.113549.1.9.16.2.4 
+ * </pre>
+ */
+
 public interface CMSAttributes
 {
+    /** PKCS#9: 1.2.840.113549.1.9.3 */
     public static final ASN1ObjectIdentifier  contentType = PKCSObjectIdentifiers.pkcs_9_at_contentType;
+    /** PKCS#9: 1.2.840.113549.1.9.4 */
     public static final ASN1ObjectIdentifier  messageDigest = PKCSObjectIdentifiers.pkcs_9_at_messageDigest;
+    /** PKCS#9: 1.2.840.113549.1.9.5 */
     public static final ASN1ObjectIdentifier  signingTime = PKCSObjectIdentifiers.pkcs_9_at_signingTime;
+    /** PKCS#9: 1.2.840.113549.1.9.6 */
     public static final ASN1ObjectIdentifier  counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature;
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.4 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */
     public static final ASN1ObjectIdentifier  contentHint = PKCSObjectIdentifiers.id_aa_contentHint;
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
index 6294d97..b88bf6e 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
@@ -5,24 +5,39 @@
 
 public interface CMSObjectIdentifiers
 {
+    /** PKCS#7: 1.2.840.113549.1.7.1 */
     static final ASN1ObjectIdentifier    data = PKCSObjectIdentifiers.data;
+    /** PKCS#7: 1.2.840.113549.1.7.2 */
     static final ASN1ObjectIdentifier    signedData = PKCSObjectIdentifiers.signedData;
+    /** PKCS#7: 1.2.840.113549.1.7.3 */
     static final ASN1ObjectIdentifier    envelopedData = PKCSObjectIdentifiers.envelopedData;
+    /** PKCS#7: 1.2.840.113549.1.7.4 */
     static final ASN1ObjectIdentifier    signedAndEnvelopedData = PKCSObjectIdentifiers.signedAndEnvelopedData;
+    /** PKCS#7: 1.2.840.113549.1.7.5 */
     static final ASN1ObjectIdentifier    digestedData = PKCSObjectIdentifiers.digestedData;
+    /** PKCS#7: 1.2.840.113549.1.7.6 */
     static final ASN1ObjectIdentifier    encryptedData = PKCSObjectIdentifiers.encryptedData;
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.2 -- smime ct authData */
     static final ASN1ObjectIdentifier    authenticatedData = PKCSObjectIdentifiers.id_ct_authData;
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.9 -- smime ct compressedData */
     static final ASN1ObjectIdentifier    compressedData = PKCSObjectIdentifiers.id_ct_compressedData;
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.23 -- smime ct authEnvelopedData */
     static final ASN1ObjectIdentifier    authEnvelopedData = PKCSObjectIdentifiers.id_ct_authEnvelopedData;
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.31 -- smime ct timestampedData*/
     static final ASN1ObjectIdentifier    timestampedData = PKCSObjectIdentifiers.id_ct_timestampedData;
 
     /**
      * The other Revocation Info arc
+     * <p>
+     * <pre>
      * id-ri OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
-     *                                   dod(6) internet(1) security(5) mechanisms(5) pkix(7) ri(16) }
+     *        dod(6) internet(1) security(5) mechanisms(5) pkix(7) ri(16) }
+     * </pre>
      */
     static final ASN1ObjectIdentifier    id_ri = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.16");
 
+    /** 1.3.6.1.5.5.7.16.2 */
     static final ASN1ObjectIdentifier    id_ri_ocsp_response = id_ri.branch("2");
+    /** 1.3.6.1.5.5.7.16.4 */
     static final ASN1ObjectIdentifier    id_ri_scvp = id_ri.branch("4");
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
index 688ac58..1592c75 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
@@ -10,6 +10,22 @@
 import org.bouncycastle.asn1.BERSequence;
 import org.bouncycastle.asn1.BERTaggedObject;
 
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-3">RFC 5652</a> ContentInfo, and 
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.2">RFC 5652</a> EncapsulatedContentInfo objects.
+ *
+ * <pre>
+ * ContentInfo ::= SEQUENCE {
+ *     contentType ContentType,
+ *     content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
+ * }
+ *
+ * EncapsulatedContentInfo ::= SEQUENCE {
+ *     eContentType ContentType,
+ *     eContent [0] EXPLICIT OCTET STRING OPTIONAL
+ * }
+ * </pre>
+ */
 public class ContentInfo
     extends ASN1Object
     // BEGIN android-removed
@@ -19,6 +35,19 @@
     private ASN1ObjectIdentifier contentType;
     private ASN1Encodable        content;
 
+    /**
+     * Return an ContentInfo object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link ContentInfo} object
+     * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with ContentInfo structure inside
+     * </ul>
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
     public static ContentInfo getInstance(
         Object  obj)
     {
@@ -86,12 +115,6 @@
 
     /**
      * Produce an object suitable for an ASN1OutputStream.
-     * <pre>
-     * ContentInfo ::= SEQUENCE {
-     *          contentType ContentType,
-     *          content
-     *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
-     * </pre>
      */
     public ASN1Primitive toASN1Primitive()
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/GCMParameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/GCMParameters.java
new file mode 100644
index 0000000..0f03c87
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/GCMParameters.java
@@ -0,0 +1,102 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * <a href="http://tools.ietf.org/html/rfc5084">RFC 5084</a>: GCMParameters object.
+ * <p>
+ * <pre>
+ GCMParameters ::= SEQUENCE {
+   aes-nonce        OCTET STRING, -- recommended size is 12 octets
+   aes-ICVlen       AES-GCM-ICVlen DEFAULT 12 }
+ * </pre>
+ */
+public class GCMParameters
+    extends ASN1Object
+{
+    private byte[] nonce;
+    private int icvLen;
+
+    /**
+     * Return an GCMParameters object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link org.bouncycastle.asn1.cms.GCMParameters} object
+     * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(Object) ASN1Sequence} input formats with GCMParameters structure inside
+     * </ul>
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static GCMParameters getInstance(
+        Object  obj)
+    {
+        if (obj instanceof GCMParameters)
+        {
+            return (GCMParameters)obj;
+        }
+        else if (obj != null)
+        {
+            return new GCMParameters(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    private GCMParameters(
+        ASN1Sequence seq)
+    {
+        this.nonce = ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets();
+
+        if (seq.size() == 2)
+        {
+            this.icvLen = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue().intValue();
+        }
+        else
+        {
+            this.icvLen = 12;
+        }
+    }
+
+    public GCMParameters(
+        byte[] nonce,
+        int    icvLen)
+    {
+        this.nonce = Arrays.clone(nonce);
+        this.icvLen = icvLen;
+    }
+
+    public byte[] getNonce()
+    {
+        return Arrays.clone(nonce);
+    }
+
+    public int getIcvLen()
+    {
+        return icvLen;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(new DEROctetString(nonce));
+
+        if (icvLen != 12)
+        {
+            v.add(new ASN1Integer(icvLen));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java
index ad0dbb1..d46cbfb 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java
@@ -13,12 +13,37 @@
 import org.bouncycastle.asn1.x509.X509CertificateStructure;
 import org.bouncycastle.asn1.x509.X509Name;
 
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-10.2.4">RFC 5652</a>: IssuerAndSerialNumber object.
+ * <p>
+ * <pre>
+ * IssuerAndSerialNumber ::= SEQUENCE {
+ *     issuer Name,
+ *     serialNumber CertificateSerialNumber
+ * }
+ *
+ * CertificateSerialNumber ::= INTEGER  -- See RFC 5280
+ * </pre>
+ */
 public class IssuerAndSerialNumber
     extends ASN1Object
 {
     private X500Name    name;
     private ASN1Integer  serialNumber;
 
+    /**
+     * Return an IssuerAndSerialNumber object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link IssuerAndSerialNumber} object
+     * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with IssuerAndSerialNumber structure inside
+     * </ul>
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
     public static IssuerAndSerialNumber getInstance(
         Object  obj)
     {
@@ -36,7 +61,6 @@
 
     /**
      * @deprecated  use getInstance() method.
-     * @param seq
      */
     public IssuerAndSerialNumber(
         ASN1Sequence    seq)
@@ -52,6 +76,9 @@
         this.serialNumber = certificate.getSerialNumber();
     }
 
+    /**
+     * @deprecated use constructor taking Certificate
+     */
     public IssuerAndSerialNumber(
         X509CertificateStructure certificate)
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java
index fd2718a..8c7fcc2 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java
@@ -16,7 +16,45 @@
 import org.bouncycastle.asn1.DERTaggedObject;
 
 /**
- * a signed data object.
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.1">RFC 5652</a>:
+ * <p>
+ * A signed data object containing multitude of {@link SignerInfo}s.
+ * <pre>
+ * SignedData ::= SEQUENCE {
+ *     version CMSVersion,
+ *     digestAlgorithms DigestAlgorithmIdentifiers,
+ *     encapContentInfo EncapsulatedContentInfo,
+ *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
+ *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ *     signerInfos SignerInfos
+ *   }
+ * 
+ * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
+ * 
+ * SignerInfos ::= SET OF SignerInfo
+ * </pre>
+ * <p>
+ * The version calculation uses following ruleset from RFC 3852 section 5.1:
+ * <pre>
+ * IF ((certificates is present) AND
+ *    (any certificates with a type of other are present)) OR
+ *    ((crls is present) AND
+ *    (any crls with a type of other are present))
+ * THEN version MUST be 5
+ * ELSE
+ *    IF (certificates is present) AND
+ *       (any version 2 attribute certificates are present)
+ *    THEN version MUST be 4
+ *    ELSE
+ *       IF ((certificates is present) AND
+ *          (any version 1 attribute certificates are present)) OR
+ *          (any SignerInfo structures are version 3) OR
+ *          (encapContentInfo eContentType is other than id-data)
+ *       THEN version MUST be 3
+ *       ELSE version MUST be 1
+ * </pre>
+ * <p>
+ * @todo Check possible update for this to RFC 5652 level
  */
 public class SignedData
     extends ASN1Object
@@ -35,6 +73,19 @@
     private boolean certsBer;
     private boolean        crlsBer;
 
+    /**
+     * Return a SignedData object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link SignedData} object
+     * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SignedData structure inside
+     * </ul>
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
     public static SignedData getInstance(
         Object  o)
     {
@@ -68,24 +119,6 @@
     }
 
 
-    // RFC3852, section 5.1:
-    // IF ((certificates is present) AND
-    //    (any certificates with a type of other are present)) OR
-    //    ((crls is present) AND
-    //    (any crls with a type of other are present))
-    // THEN version MUST be 5
-    // ELSE
-    //    IF (certificates is present) AND
-    //       (any version 2 attribute certificates are present)
-    //    THEN version MUST be 4
-    //    ELSE
-    //       IF ((certificates is present) AND
-    //          (any version 1 attribute certificates are present)) OR
-    //          (any SignerInfo structures are version 3) OR
-    //          (encapContentInfo eContentType is other than id-data)
-    //       THEN version MUST be 3
-    //       ELSE version MUST be 1
-    //
     private ASN1Integer calculateVersion(
         ASN1ObjectIdentifier contentOid,
         ASN1Set certs,
@@ -257,16 +290,6 @@
 
     /**
      * Produce an object suitable for an ASN1OutputStream.
-     * <pre>
-     * SignedData ::= SEQUENCE {
-     *     version CMSVersion,
-     *     digestAlgorithms DigestAlgorithmIdentifiers,
-     *     encapContentInfo EncapsulatedContentInfo,
-     *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
-     *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
-     *     signerInfos SignerInfos
-     *   }
-     * </pre>
      */
     public ASN1Primitive toASN1Primitive()
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java
index 37b6b31..2543eb1 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java
@@ -8,6 +8,21 @@
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.DERTaggedObject;
 
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.3">RFC 5652</a>:
+ * Identify who signed the containing {@link SignerInfo} object.
+ * <p>
+ * The certificates referred to by this are at containing {@link SignedData} structure.
+ * <p>
+ * <pre>
+ * SignerIdentifier ::= CHOICE {
+ *     issuerAndSerialNumber IssuerAndSerialNumber,
+ *     subjectKeyIdentifier [0] SubjectKeyIdentifier 
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ * </pre>
+ */
 public class SignerIdentifier
     extends ASN1Object
     implements ASN1Choice
@@ -33,7 +48,16 @@
     }
     
     /**
-     * return a SignerIdentifier object from the given object.
+     * Return a SignerIdentifier object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link SignerIdentifier} object
+     * <li> {@link IssuerAndSerialNumber} object
+     * <li> {@link org.bouncycastle.asn1.ASN1OctetString#getInstance(java.lang.Object) ASN1OctetString} input formats with SignerIdentifier structure inside
+     * <li> {@link org.bouncycastle.asn1.ASN1Primitive ASN1Primitive} for SignerIdentifier constructor.
+     * </ul>
      *
      * @param o the object we want converted.
      * @exception IllegalArgumentException if the object cannot be converted.
@@ -82,14 +106,6 @@
 
     /** 
      * Produce an object suitable for an ASN1OutputStream.
-     * <pre>
-     * SignerIdentifier ::= CHOICE {
-     *     issuerAndSerialNumber IssuerAndSerialNumber,
-     *     subjectKeyIdentifier [0] SubjectKeyIdentifier 
-     * }
-     *
-     * SubjectKeyIdentifier ::= OCTET STRING
-     * </pre>
      */
     public ASN1Primitive toASN1Primitive()
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java
index 8aafd67..4209045 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java
@@ -15,6 +15,63 @@
 import org.bouncycastle.asn1.DERTaggedObject;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-5.3">RFC 5652</a>:
+ * Signature container per Signer, see {@link SignerIdentifier}.
+ * <pre>
+ * PKCS#7:
+ *
+ * SignerInfo ::= SEQUENCE {
+ *     version                   Version,
+ *     sid                       SignerIdentifier,
+ *     digestAlgorithm           DigestAlgorithmIdentifier,
+ *     authenticatedAttributes   [0] IMPLICIT Attributes OPTIONAL,
+ *     digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ *     encryptedDigest           EncryptedDigest,
+ *     unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+ * }
+ *
+ * EncryptedDigest ::= OCTET STRING
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * -----------------------------------------
+ *
+ * RFC 5256:
+ *
+ * SignerInfo ::= SEQUENCE {
+ *     version            CMSVersion,
+ *     sid                SignerIdentifier,
+ *     digestAlgorithm    DigestAlgorithmIdentifier,
+ *     signedAttrs        [0] IMPLICIT SignedAttributes OPTIONAL,
+ *     signatureAlgorithm SignatureAlgorithmIdentifier,
+ *     signature          SignatureValue,
+ *     unsignedAttrs      [1] IMPLICIT UnsignedAttributes OPTIONAL
+ * }
+ *
+ * -- {@link SignerIdentifier} referenced certificates are at containing
+ * -- {@link SignedData} certificates element.
+ *
+ * SignerIdentifier ::= CHOICE {
+ *     issuerAndSerialNumber {@link IssuerAndSerialNumber},
+ *     subjectKeyIdentifier  [0] SubjectKeyIdentifier }
+ *
+ * -- See {@link Attributes} for generalized SET OF {@link Attribute}
+ *
+ * SignedAttributes   ::= SET SIZE (1..MAX) OF Attribute
+ * UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute
+ * 
+ * {@link Attribute} ::= SEQUENCE {
+ *     attrType   OBJECT IDENTIFIER,
+ *     attrValues SET OF AttributeValue }
+ *
+ * AttributeValue ::= ANY
+ * 
+ * SignatureValue ::= OCTET STRING
+ * </pre>
+ */
 public class SignerInfo
     extends ASN1Object
 {
@@ -26,22 +83,44 @@
     private ASN1OctetString         encryptedDigest;
     private ASN1Set                 unauthenticatedAttributes;
 
+    /**
+     * Return a SignerInfo object from the given input
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link SignerInfo} object
+     * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SignerInfo structure inside
+     * </ul>
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
     public static SignerInfo getInstance(
         Object  o)
         throws IllegalArgumentException
     {
-        if (o == null || o instanceof SignerInfo)
+        if (o instanceof SignerInfo)
         {
             return (SignerInfo)o;
         }
-        else if (o instanceof ASN1Sequence)
+        else if (o != null)
         {
-            return new SignerInfo((ASN1Sequence)o);
+            return new SignerInfo(ASN1Sequence.getInstance(o));
         }
 
-        throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName());
+        return null;
     }
 
+    /**
+     *
+     * @param sid
+     * @param digAlgorithm            CMS knows as 'digestAlgorithm'
+     * @param authenticatedAttributes CMS knows as 'signedAttrs'
+     * @param digEncryptionAlgorithm  CMS knows as 'signatureAlgorithm'
+     * @param encryptedDigest         CMS knows as 'signature'
+     * @param unauthenticatedAttributes CMS knows as 'unsignedAttrs'
+     */
     public SignerInfo(
         SignerIdentifier        sid,
         AlgorithmIdentifier     digAlgorithm,
@@ -67,6 +146,15 @@
         this.unauthenticatedAttributes = unauthenticatedAttributes;
     }
 
+    /**
+     *
+     * @param sid
+     * @param digAlgorithm            CMS knows as 'digestAlgorithm'
+     * @param authenticatedAttributes CMS knows as 'signedAttrs'
+     * @param digEncryptionAlgorithm  CMS knows as 'signatureAlgorithm'
+     * @param encryptedDigest         CMS knows as 'signature'
+     * @param unauthenticatedAttributes CMS knows as 'unsignedAttrs'
+     */
     public SignerInfo(
         SignerIdentifier        sid,
         AlgorithmIdentifier     digAlgorithm,
@@ -167,23 +255,6 @@
 
     /**
      * Produce an object suitable for an ASN1OutputStream.
-     * <pre>
-     *  SignerInfo ::= SEQUENCE {
-     *      version Version,
-     *      SignerIdentifier sid,
-     *      digestAlgorithm DigestAlgorithmIdentifier,
-     *      authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
-     *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
-     *      encryptedDigest EncryptedDigest,
-     *      unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
-     *  }
-     *
-     *  EncryptedDigest ::= OCTET STRING
-     *
-     *  DigestAlgorithmIdentifier ::= AlgorithmIdentifier
-     *
-     *  DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
-     * </pre>
      */
     public ASN1Primitive toASN1Primitive()
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java
index 2087248..977fce6 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java
@@ -12,6 +12,22 @@
 import org.bouncycastle.asn1.DERGeneralizedTime;
 import org.bouncycastle.asn1.DERUTCTime;
 
+/**
+ * <a href="http://tools.ietf.org/html/rfc5652#section-11.3">RFC 5652</a>:
+ * Dual-mode timestamp format producing either UTCTIme or GeneralizedTime.
+ * <p>
+ * <pre>
+ * Time ::= CHOICE {
+ *     utcTime        UTCTime,
+ *     generalTime    GeneralizedTime }
+ * </pre>
+ * <p>
+ * This has a constructor using java.util.Date for input which generates
+ * a {@link org.bouncycastle.asn1.DERUTCTime DERUTCTime} object if the
+ * supplied datetime is in range 1950-01-01-00:00:00 UTC until 2049-12-31-23:59:60 UTC.
+ * If the datetime value is outside that range, the generated object will be
+ * {@link org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime}.
+ */
 public class Time
     extends ASN1Object
     implements ASN1Choice
@@ -25,6 +41,9 @@
         return getInstance(obj.getObject());
     }
 
+    /**
+     * @deprecated use getInstance()
+     */
     public Time(
         ASN1Primitive   time)
     {
@@ -38,7 +57,7 @@
     }
 
     /**
-     * creates a time object from a given date - if the date is between 1950
+     * Create a time object from a given date - if the year is in between 1950
      * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime
      * is used.
      */
@@ -63,6 +82,20 @@
         }
     }
 
+    /**
+     * Return a Time object from the given object.
+     * <p>
+     * Accepted inputs:
+     * <ul>
+     * <li> null &rarr; null
+     * <li> {@link Time} object
+     * <li> {@link org.bouncycastle.asn1.DERUTCTime DERUTCTime} object
+     * <li> {@link org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime} object
+     * </ul>
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
     public static Time getInstance(
         Object  obj)
     {
@@ -82,6 +115,9 @@
         throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
     }
 
+    /**
+     * Get the date+tine as a String in full form century format.
+     */
     public String getTime()
     {
         if (time instanceof DERUTCTime)
@@ -94,6 +130,9 @@
         }
     }
 
+    /**
+     * Get java.util.Date version of date+time.
+     */
     public Date getDate()
     {
         try
@@ -115,11 +154,6 @@
 
     /**
      * Produce an object suitable for an ASN1OutputStream.
-     * <pre>
-     * Time ::= CHOICE {
-     *             utcTime        UTCTime,
-     *             generalTime    GeneralizedTime }
-     * </pre>
      */
     public ASN1Primitive toASN1Primitive()
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java
index bef8620..77416dc 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java
@@ -2,54 +2,109 @@
 
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
+/**
+ * German Federal Office for Information Security
+ * (Bundesamt für Sicherheit in der Informationstechnik)
+ * <a href="http://www.bsi.bund.de/">http://www.bsi.bund.de/</a>
+ * <p>
+ * <a href="https://www.bsi.bund.de/EN/Publications/TechnicalGuidelines/TR03110/BSITR03110.html">BSI TR-03110</a>
+ * Technical Guideline Advanced Security Mechanisms for Machine Readable Travel Documents
+ * <p>
+ * <a href="https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TR03110/TR-03110_v2.1_P3pdf.pdf?__blob=publicationFile">Technical Guideline TR-03110-3</a>
+ * Advanced Security Mechanisms for Machine Readable Travel Documents;
+ * Part 3: Common Specifications.
+ */
+
 public interface EACObjectIdentifiers
 {
-    // bsi-de OBJECT IDENTIFIER ::= {
-    //         itu-t(0) identified-organization(4) etsi(0)
-    //         reserved(127) etsi-identified-organization(0) 7
-    //     }
+    /**
+     * <pre>
+     * bsi-de OBJECT IDENTIFIER ::= {
+     *     itu-t(0) identified-organization(4) etsi(0)
+     *     reserved(127) etsi-identified-organization(0) 7
+     * }
+     * </pre>
+     * OID: 0.4.0.127.0.7
+     */
     static final ASN1ObjectIdentifier    bsi_de      = new ASN1ObjectIdentifier("0.4.0.127.0.7");
 
-    // id-PK OBJECT IDENTIFIER ::= {
-    //         bsi-de protocols(2) smartcard(2) 1
-    //     }
-    static final ASN1ObjectIdentifier    id_PK = bsi_de.branch("2.2.1");
+    /**
+     * <pre>
+     * id-PK OBJECT IDENTIFIER ::= {
+     *     bsi-de protocols(2) smartcard(2) 1
+     * }
+     * </pre>
+     * OID: 0.4.0.127.0.7.2.2.1
+     */
+    static final ASN1ObjectIdentifier    id_PK      = bsi_de.branch("2.2.1");
 
-    static final ASN1ObjectIdentifier    id_PK_DH = id_PK.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.1.1 */
+    static final ASN1ObjectIdentifier    id_PK_DH   = id_PK.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.1.2 */
     static final ASN1ObjectIdentifier    id_PK_ECDH = id_PK.branch("2");
 
-    // id-CA OBJECT IDENTIFIER ::= {
-    //         bsi-de protocols(2) smartcard(2) 3
-    //     }
-    static final ASN1ObjectIdentifier    id_CA = bsi_de.branch("2.2.3");
-    static final ASN1ObjectIdentifier    id_CA_DH = id_CA.branch("1");
-    static final ASN1ObjectIdentifier    id_CA_DH_3DES_CBC_CBC = id_CA_DH.branch("1");
-    static final ASN1ObjectIdentifier    id_CA_ECDH = id_CA.branch("2");
+    /**
+     * <pre>
+     * id-CA OBJECT IDENTIFIER ::= {
+     *     bsi-de protocols(2) smartcard(2) 3
+     * }
+     * </pre>
+     * OID: 0.4.0.127.0.7.2.2.3
+     */
+    static final ASN1ObjectIdentifier    id_CA                   = bsi_de.branch("2.2.3");
+    /** OID: 0.4.0.127.0.7.2.2.3.1 */
+    static final ASN1ObjectIdentifier    id_CA_DH                = id_CA.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.3.1.1 */
+    static final ASN1ObjectIdentifier    id_CA_DH_3DES_CBC_CBC   = id_CA_DH.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.3.2 */
+    static final ASN1ObjectIdentifier    id_CA_ECDH              = id_CA.branch("2");
+    /** OID: 0.4.0.127.0.7.2.2.3.2.1 */
     static final ASN1ObjectIdentifier    id_CA_ECDH_3DES_CBC_CBC = id_CA_ECDH.branch("1");
 
-    //
-    // id-TA OBJECT IDENTIFIER ::= {
-    //     bsi-de protocols(2) smartcard(2) 2
-    // }
+    /**
+     * <pre>
+     * id-TA OBJECT IDENTIFIER ::= {
+     *     bsi-de protocols(2) smartcard(2) 2
+     * }
+     * </pre>
+     * OID: 0.4.0.127.0.7.2.2.2
+     */
     static final ASN1ObjectIdentifier    id_TA = bsi_de.branch("2.2.2");
 
-    static final ASN1ObjectIdentifier    id_TA_RSA = id_TA.branch("1");
-    static final ASN1ObjectIdentifier    id_TA_RSA_v1_5_SHA_1 = id_TA_RSA .branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.2.1 */
+    static final ASN1ObjectIdentifier    id_TA_RSA              = id_TA.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.1 */
+    static final ASN1ObjectIdentifier    id_TA_RSA_v1_5_SHA_1   = id_TA_RSA.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.2 */
     static final ASN1ObjectIdentifier    id_TA_RSA_v1_5_SHA_256 = id_TA_RSA.branch("2");
-    static final ASN1ObjectIdentifier    id_TA_RSA_PSS_SHA_1 = id_TA_RSA.branch("3");
-    static final ASN1ObjectIdentifier    id_TA_RSA_PSS_SHA_256 = id_TA_RSA.branch("4");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.3 */
+    static final ASN1ObjectIdentifier    id_TA_RSA_PSS_SHA_1    = id_TA_RSA.branch("3");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.4 */
+    static final ASN1ObjectIdentifier    id_TA_RSA_PSS_SHA_256  = id_TA_RSA.branch("4");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.5 */
     static final ASN1ObjectIdentifier    id_TA_RSA_v1_5_SHA_512 = id_TA_RSA.branch("5");
-    static final ASN1ObjectIdentifier    id_TA_RSA_PSS_SHA_512 = id_TA_RSA.branch("6");
-    static final ASN1ObjectIdentifier    id_TA_ECDSA = id_TA.branch("2");
-    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_1 = id_TA_ECDSA.branch("1");
-    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_224 = id_TA_ECDSA.branch("2");
-    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_256 = id_TA_ECDSA.branch("3");
-    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_384 = id_TA_ECDSA.branch("4");
-    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_512 = id_TA_ECDSA.branch("5");
+    /** OID: 0.4.0.127.0.7.2.2.2.1.6 */
+    static final ASN1ObjectIdentifier    id_TA_RSA_PSS_SHA_512  = id_TA_RSA.branch("6");
+    /** OID: 0.4.0.127.0.7.2.2.2.2 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA            = id_TA.branch("2");
+    /** OID: 0.4.0.127.0.7.2.2.2.2.1 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_1      = id_TA_ECDSA.branch("1");
+    /** OID: 0.4.0.127.0.7.2.2.2.2.2 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_224    = id_TA_ECDSA.branch("2");
+    /** OID: 0.4.0.127.0.7.2.2.2.2.3 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_256    = id_TA_ECDSA.branch("3");
+    /** OID: 0.4.0.127.0.7.2.2.2.2.4 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_384    = id_TA_ECDSA.branch("4");
+    /** OID: 0.4.0.127.0.7.2.2.2.2.5 */
+    static final ASN1ObjectIdentifier    id_TA_ECDSA_SHA_512    = id_TA_ECDSA.branch("5");
 
     /**
+     * <pre>
      * id-EAC-ePassport OBJECT IDENTIFIER ::= {
-     * bsi-de applications(3) mrtd(1) roles(2) 1}
+     *     bsi-de applications(3) mrtd(1) roles(2) 1
+     * }
+     * </pre>
+     * OID: 0.4.0.127.0.7.3.1.2.1
      */
     static final ASN1ObjectIdentifier id_EAC_ePassport = bsi_de.branch("3.1.2.1");
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
index e9ab8d6..5bfdbab 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
@@ -2,19 +2,59 @@
 
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
+/**
+ * IANA:
+ *  { iso(1) identifier-organization(3) dod(6) internet(1) } == IETF defined things
+ */
 public interface IANAObjectIdentifiers
 {
+
+    /** { iso(1) identifier-organization(3) dod(6) internet(1) } == IETF defined things */
+    static final ASN1ObjectIdentifier   internet       = new ASN1ObjectIdentifier("1.3.6.1");
+    /** 1.3.6.1.1: Internet directory: X.500 */
+    static final ASN1ObjectIdentifier   directory      = internet.branch("1");
+    /** 1.3.6.1.2: Internet management */
+    static final ASN1ObjectIdentifier   mgmt           = internet.branch("2");
+    /** 1.3.6.1.3: */
+    static final ASN1ObjectIdentifier   experimental   = internet.branch("3");
+    /** 1.3.6.1.4: */
+    static final ASN1ObjectIdentifier   _private       = internet.branch("4");
+    /** 1.3.6.1.5: Security services */
+    static final ASN1ObjectIdentifier   security       = internet.branch("5");
+    /** 1.3.6.1.6: SNMPv2 -- never really used */
+    static final ASN1ObjectIdentifier   SNMPv2         = internet.branch("6");
+    /** 1.3.6.1.7: mail -- never really used */
+    static final ASN1ObjectIdentifier   mail           = internet.branch("7");
+
+
     // id-SHA1 OBJECT IDENTIFIER ::=    
     // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)}
     //
 
-    static final ASN1ObjectIdentifier    isakmpOakley  = new ASN1ObjectIdentifier("1.3.6.1.5.5.8.1");
 
-    static final ASN1ObjectIdentifier    hmacMD5       = new ASN1ObjectIdentifier(isakmpOakley + ".1");
-    static final ASN1ObjectIdentifier    hmacSHA1     = new ASN1ObjectIdentifier(isakmpOakley + ".2");
+    /** IANA security mechanisms; 1.3.6.1.5.5 */
+    static final ASN1ObjectIdentifier    security_mechanisms  = security.branch("5");
+    /** IANA security nametypes;  1.3.6.1.5.6 */
+    static final ASN1ObjectIdentifier    security_nametypes   = security.branch("6");
+
+    /** PKIX base OID:            1.3.6.1.5.6.6 */
+    static final ASN1ObjectIdentifier    pkix                 = security_mechanisms.branch("6");
+
+
+    /** IPSEC base OID:                        1.3.6.1.5.5.8 */
+    static final ASN1ObjectIdentifier    ipsec                = security_mechanisms.branch("8");
+    /** IPSEC ISAKMP-Oakley OID:               1.3.6.1.5.5.8.1 */
+    static final ASN1ObjectIdentifier    isakmpOakley         = ipsec.branch("1");
+
+    /** IPSEC ISAKMP-Oakley hmacMD5 OID:       1.3.6.1.5.5.8.1.1 */
+    static final ASN1ObjectIdentifier    hmacMD5              = isakmpOakley.branch("1");
+    /** IPSEC ISAKMP-Oakley hmacSHA1 OID:      1.3.6.1.5.5.8.1.2 */
+    static final ASN1ObjectIdentifier    hmacSHA1             = isakmpOakley.branch("2");
     
-    static final ASN1ObjectIdentifier    hmacTIGER     = new ASN1ObjectIdentifier(isakmpOakley + ".3");
+    /** IPSEC ISAKMP-Oakley hmacTIGER OID:     1.3.6.1.5.5.8.1.3 */
+    static final ASN1ObjectIdentifier    hmacTIGER            = isakmpOakley.branch("3");
     
-    static final ASN1ObjectIdentifier    hmacRIPEMD160 = new ASN1ObjectIdentifier(isakmpOakley + ".4");
+    /** IPSEC ISAKMP-Oakley hmacRIPEMD160 OID: 1.3.6.1.5.5.8.1.4 */
+    static final ASN1ObjectIdentifier    hmacRIPEMD160        = isakmpOakley.branch("4");
 
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java
index bc2ac8d..6b75fde 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java
@@ -2,11 +2,16 @@
 
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
+/**
+ * ISISMT -- Industrial Signature Interoperability Specification
+ */
 public interface ISISMTTObjectIdentifiers
 {
 
+    /** 1.3.36.8 */
     static final ASN1ObjectIdentifier id_isismtt = new ASN1ObjectIdentifier("1.3.36.8");
 
+    /** 1.3.36.8.1 */
     static final ASN1ObjectIdentifier id_isismtt_cp = id_isismtt.branch("1");
 
     /**
@@ -15,29 +20,37 @@
      * Parliament and of the Council of 13 December 1999 on a Community
      * Framework for Electronic Signatures, which additionally conforms the
      * special requirements of the SigG and has been issued by an accredited CA.
+     * <p>
+     * 1.3.36.8.1.1
      */
+
     static final ASN1ObjectIdentifier id_isismtt_cp_accredited = id_isismtt_cp.branch("1");
 
+    /** 1.3.36.8.3 */
     static final ASN1ObjectIdentifier id_isismtt_at = id_isismtt.branch("3");
 
     /**
      * Certificate extensionDate of certificate generation
-     * 
      * <pre>
-     *                DateOfCertGenSyntax ::= GeneralizedTime
+     *     DateOfCertGenSyntax ::= GeneralizedTime
      * </pre>
+     * OID: 1.3.36.8.3.1
      */
     static final ASN1ObjectIdentifier id_isismtt_at_dateOfCertGen = id_isismtt_at.branch("1");
 
     /**
      * Attribute to indicate that the certificate holder may sign in the name of
      * a third person. May also be used as extension in a certificate.
+     * <p>
+     * OID: 1.3.36.8.3.2
      */
     static final ASN1ObjectIdentifier id_isismtt_at_procuration = id_isismtt_at.branch("2");
 
     /**
      * Attribute to indicate admissions to certain professions. May be used as
      * attribute in attribute certificate or as extension in a certificate
+     * <p>
+     * OID: 1.3.36.8.3.3
      */
     static final ASN1ObjectIdentifier id_isismtt_at_admission = id_isismtt_at.branch("3");
 
@@ -47,33 +60,37 @@
      * MonetaryLimit since January 1, 2004. For the sake of backward
      * compatibility with certificates already in use, SigG conforming
      * components MUST support MonetaryLimit (as well as QcEuLimitValue).
+     * <p>
+     * OID: 1.3.36.8.3.4
      */
     static final ASN1ObjectIdentifier id_isismtt_at_monetaryLimit = id_isismtt_at.branch("4");
 
     /**
      * A declaration of majority. May be used as attribute in attribute
      * certificate or as extension in a certificate
+     * <p>
+     * OID: 1.3.36.8.3.5
      */
     static final ASN1ObjectIdentifier id_isismtt_at_declarationOfMajority = id_isismtt_at.branch("5");
 
     /**
-     * 
      * Serial number of the smart card containing the corresponding private key
-     * 
      * <pre>
-     *                 ICCSNSyntax ::= OCTET STRING (SIZE(8..20))
+     *    ICCSNSyntax ::= OCTET STRING (SIZE(8..20))
      * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.6
      */
     static final ASN1ObjectIdentifier id_isismtt_at_iCCSN = id_isismtt_at.branch("6");
 
     /**
-     * 
      * Reference for a file of a smartcard that stores the public key of this
-     * certificate and that is used as �security anchor�.
-     * 
+     * certificate and that is used as "security anchor".
      * <pre>
-     *      PKReferenceSyntax ::= OCTET STRING (SIZE(20))
+     *    PKReferenceSyntax ::= OCTET STRING (SIZE(20))
      * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.7
      */
     static final ASN1ObjectIdentifier id_isismtt_at_PKReference = id_isismtt_at.branch("7");
 
@@ -81,28 +98,28 @@
      * Some other restriction regarding the usage of this certificate. May be
      * used as attribute in attribute certificate or as extension in a
      * certificate.
-     * 
      * <pre>
-     *             RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+     *    RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
      * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.8
      * 
      * @see org.bouncycastle.asn1.isismtt.x509.Restriction
      */
     static final ASN1ObjectIdentifier id_isismtt_at_restriction = id_isismtt_at.branch("8");
 
     /**
-     * 
      * (Single)Request extension: Clients may include this extension in a
      * (single) Request to request the responder to send the certificate in the
      * response message along with the status information. Besides the LDAP
      * service, this extension provides another mechanism for the distribution
      * of certificates, which MAY optionally be provided by certificate
      * repositories.
-     * 
      * <pre>
-     *        RetrieveIfAllowed ::= BOOLEAN
-     *       
+     *    RetrieveIfAllowed ::= BOOLEAN
      * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.9
      */
     static final ASN1ObjectIdentifier id_isismtt_at_retrieveIfAllowed = id_isismtt_at.branch("9");
 
@@ -110,6 +127,8 @@
      * SingleOCSPResponse extension: The certificate requested by the client by
      * inserting the RetrieveIfAllowed extension in the request, will be
      * returned in this extension.
+     * <p>
+     * OID: 1.3.36.8.3.10
      * 
      * @see org.bouncycastle.asn1.isismtt.ocsp.RequestedCertificate
      */
@@ -117,6 +136,8 @@
 
     /**
      * Base ObjectIdentifier for naming authorities
+     * <p>
+     * OID: 1.3.36.8.3.11
      */
     static final ASN1ObjectIdentifier id_isismtt_at_namingAuthorities = id_isismtt_at.branch("11");
 
@@ -127,13 +148,17 @@
      * this extension in the responses.
      * 
      * <pre>
-     *      CertInDirSince ::= GeneralizedTime
+     *    CertInDirSince ::= GeneralizedTime
      * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.12
      */
     static final ASN1ObjectIdentifier id_isismtt_at_certInDirSince = id_isismtt_at.branch("12");
 
     /**
      * Hash of a certificate in OCSP.
+     * <p>
+     * OID: 1.3.36.8.3.13
      * 
      * @see org.bouncycastle.asn1.isismtt.ocsp.CertHash
      */
@@ -141,11 +166,13 @@
 
     /**
      * <pre>
-     *          NameAtBirth ::= DirectoryString(SIZE(1..64)
+     *    NameAtBirth ::= DirectoryString(SIZE(1..64)
      * </pre>
      * 
      * Used in
      * {@link org.bouncycastle.asn1.x509.SubjectDirectoryAttributes SubjectDirectoryAttributes}
+     * <p>
+     * OID: 1.3.36.8.3.14
      */
     static final ASN1ObjectIdentifier id_isismtt_at_nameAtBirth = id_isismtt_at.branch("14");
 
@@ -155,8 +182,10 @@
      * extension in a certificate.
      * 
      * <pre>
-     *               AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+     *    AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
      * </pre>
+     * <p>
+     * OID: 1.3.36.8.3.15
      * 
      * @see org.bouncycastle.asn1.isismtt.x509.AdditionalInformationSyntax
      */
@@ -171,10 +200,11 @@
      * PKC as base certificate) contains some attribute that restricts the
      * usability of the PKC too. Attribute certificates with restricting content
      * MUST always be included in the signed document.
-     * 
      * <pre>
-     *                   LiabilityLimitationFlagSyntax ::= BOOLEAN
+     *    LiabilityLimitationFlagSyntax ::= BOOLEAN
      * </pre>
+     * <p>
+     * OID: 0.2.262.1.10.12.0
      */
     static final ASN1ObjectIdentifier id_isismtt_at_liabilityLimitationFlag = new ASN1ObjectIdentifier("0.2.262.1.10.12.0");
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java
index 73e0c58..73575f1 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java
@@ -2,8 +2,30 @@
 
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
+/**
+ * Korea Information Security Agency (KISA)
+ * ({iso(1) member-body(2) kr(410) kisa(200004)})
+ * <p>
+ * See <a href="http://tools.ietf.org/html/rfc4010">RFC 4010</a>
+ * Use of the SEED Encryption Algorithm
+ * in Cryptographic Message Syntax (CMS),
+ * and <a href="http://tools.ietf.org/html/rfc4269">RFC 4269</a>
+ * The SEED Encryption Algorithm
+ */
 public interface KISAObjectIdentifiers
 {
-    public static final ASN1ObjectIdentifier id_seedCBC = new ASN1ObjectIdentifier("1.2.410.200004.1.4");
-    public static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier("1.2.410.200004.7.1.1.1");
+    /** RFC 4010, 4269: id-seedCBC; OID 1.2.410.200004.1.4 */
+    static final ASN1ObjectIdentifier id_seedCBC = new ASN1ObjectIdentifier("1.2.410.200004.1.4");
+
+    /** RFC 4269: id-seedMAC; OID 1.2.410.200004.1.7 */
+    static final ASN1ObjectIdentifier id_seedMAC = new ASN1ObjectIdentifier("1.2.410.200004.1.7");
+
+    /** RFC 4269: pbeWithSHA1AndSEED-CBC; OID 1.2.410.200004.1.15 */
+    static final ASN1ObjectIdentifier pbeWithSHA1AndSEED_CBC = new ASN1ObjectIdentifier("1.2.410.200004.1.15");
+
+    /** RFC 4010: id-npki-app-cmsSeed-wrap; OID 1.2.410.200004.7.1.1.1 */
+    static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier("1.2.410.200004.7.1.1.1");
+
+    /** RFC 4010: SeedEncryptionAlgorithmInCMS; OID 1.2.840.113549.1.9.16.0.24 */
+    static final ASN1ObjectIdentifier id_mod_cms_seed = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.0.24");
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
index debf268..6aff988 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
@@ -8,40 +8,52 @@
     // Netscape
     //       iso/itu(2) joint-assign(16) us(840) uscompany(1) netscape(113730) cert-extensions(1) }
     //
+    /** Netscape cert extensions OID base: 2.16.840.1.113730.1  */
     static final ASN1ObjectIdentifier    netscape                = new ASN1ObjectIdentifier("2.16.840.1.113730.1");
+    /** Netscape cert CertType OID: 2.16.840.1.113730.1.1  */
     static final ASN1ObjectIdentifier    netscapeCertType        = netscape.branch("1");
+    /** Netscape cert BaseURL OID: 2.16.840.1.113730.1.2  */
     static final ASN1ObjectIdentifier    netscapeBaseURL         = netscape.branch("2");
+    /** Netscape cert RevocationURL OID: 2.16.840.1.113730.1.3  */
     static final ASN1ObjectIdentifier    netscapeRevocationURL   = netscape.branch("3");
+    /** Netscape cert CARevocationURL OID: 2.16.840.1.113730.1.4  */
     static final ASN1ObjectIdentifier    netscapeCARevocationURL = netscape.branch("4");
+    /** Netscape cert RenewalURL OID: 2.16.840.1.113730.1.7  */
     static final ASN1ObjectIdentifier    netscapeRenewalURL      = netscape.branch("7");
+    /** Netscape cert CApolicyURL OID: 2.16.840.1.113730.1.8  */
     static final ASN1ObjectIdentifier    netscapeCApolicyURL     = netscape.branch("8");
+    /** Netscape cert SSLServerName OID: 2.16.840.1.113730.1.12  */
     static final ASN1ObjectIdentifier    netscapeSSLServerName   = netscape.branch("12");
+    /** Netscape cert CertComment OID: 2.16.840.1.113730.1.13  */
     static final ASN1ObjectIdentifier    netscapeCertComment     = netscape.branch("13");
     
     //
     // Verisign
     //       iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) }
     //
+    /** Verisign OID base: 2.16.840.1.113733.1 */
     static final ASN1ObjectIdentifier   verisign                = new ASN1ObjectIdentifier("2.16.840.1.113733.1");
 
-    //
-    // CZAG - country, zip, age, and gender
-    //
+    /** Verisign CZAG (Country,Zip,Age,Gender) Extension OID: 2.16.840.1.113733.1.6.3 */
     static final ASN1ObjectIdentifier    verisignCzagExtension   = verisign.branch("6.3");
-    // D&B D-U-N-S number
+    /** Verisign D&B D-U-N-S number Extension OID: 2.16.840.1.113733.1.6.15 */
     static final ASN1ObjectIdentifier    verisignDnbDunsNumber   = verisign.branch("6.15");
 
     //
     // Novell
     //       iso/itu(2) country(16) us(840) organization(1) novell(113719)
     //
+    /** Novell OID base: 2.16.840.1.113719 */
     static final ASN1ObjectIdentifier    novell                  = new ASN1ObjectIdentifier("2.16.840.1.113719");
+    /** Novell SecurityAttribs OID: 2.16.840.1.113719.1.9.4.1 */
     static final ASN1ObjectIdentifier    novellSecurityAttribs   = novell.branch("1.9.4.1");
 
     //
     // Entrust
     //       iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7)
     //
+    /** NortelNetworks Entrust OID base: 1.2.840.113533.7 */
     static final ASN1ObjectIdentifier    entrust                 = new ASN1ObjectIdentifier("1.2.840.113533.7");
+    /** NortelNetworks Entrust VersionExtension OID: 1.2.840.113533.7.65.0 */
     static final ASN1ObjectIdentifier    entrustVersionExtension = entrust.branch("65.0");
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
index afa93c4..e3613c6 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
@@ -2,59 +2,95 @@
 
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
+/**
+ *
+ * NIST:
+ *     iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3) 
+ */
 public interface NISTObjectIdentifiers
 {
     //
-    // NIST
-    //     iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3) 
-
-    //
     // nistalgorithms(4)
     //
+    /** 2.16.840.1.101.3.4 -- algorithms */
     static final ASN1ObjectIdentifier    nistAlgorithm           = new ASN1ObjectIdentifier("2.16.840.1.101.3.4");
 
+    /** 2.16.840.1.101.3.4.2 */
     static final ASN1ObjectIdentifier    hashAlgs                = nistAlgorithm.branch("2");
 
+    /** 2.16.840.1.101.3.4.2.1 */
     static final ASN1ObjectIdentifier    id_sha256               = hashAlgs.branch("1");
+    /** 2.16.840.1.101.3.4.2.2 */
     static final ASN1ObjectIdentifier    id_sha384               = hashAlgs.branch("2");
+    /** 2.16.840.1.101.3.4.2.3 */
     static final ASN1ObjectIdentifier    id_sha512               = hashAlgs.branch("3");
+    /** 2.16.840.1.101.3.4.2.4 */
     static final ASN1ObjectIdentifier    id_sha224               = hashAlgs.branch("4");
+    /** 2.16.840.1.101.3.4.2.5 */
     static final ASN1ObjectIdentifier    id_sha512_224           = hashAlgs.branch("5");
+    /** 2.16.840.1.101.3.4.2.6 */
     static final ASN1ObjectIdentifier    id_sha512_256           = hashAlgs.branch("6");
 
-    static final ASN1ObjectIdentifier    aes                     =  nistAlgorithm.branch("1");
+    /** 2.16.840.1.101.3.4.1 */
+    static final ASN1ObjectIdentifier    aes                     = nistAlgorithm.branch("1");
     
+    /** 2.16.840.1.101.3.4.1.1 */
     static final ASN1ObjectIdentifier    id_aes128_ECB           = aes.branch("1"); 
+    /** 2.16.840.1.101.3.4.1.2 */
     static final ASN1ObjectIdentifier    id_aes128_CBC           = aes.branch("2");
+    /** 2.16.840.1.101.3.4.1.3 */
     static final ASN1ObjectIdentifier    id_aes128_OFB           = aes.branch("3"); 
+    /** 2.16.840.1.101.3.4.1.4 */
     static final ASN1ObjectIdentifier    id_aes128_CFB           = aes.branch("4"); 
+    /** 2.16.840.1.101.3.4.1.5 */
     static final ASN1ObjectIdentifier    id_aes128_wrap          = aes.branch("5");
+    /** 2.16.840.1.101.3.4.1.6 */
     static final ASN1ObjectIdentifier    id_aes128_GCM           = aes.branch("6");
+    /** 2.16.840.1.101.3.4.1.7 */
     static final ASN1ObjectIdentifier    id_aes128_CCM           = aes.branch("7");
     
+    /** 2.16.840.1.101.3.4.1.21 */
     static final ASN1ObjectIdentifier    id_aes192_ECB           = aes.branch("21"); 
+    /** 2.16.840.1.101.3.4.1.22 */
     static final ASN1ObjectIdentifier    id_aes192_CBC           = aes.branch("22"); 
+    /** 2.16.840.1.101.3.4.1.23 */
     static final ASN1ObjectIdentifier    id_aes192_OFB           = aes.branch("23"); 
+    /** 2.16.840.1.101.3.4.1.24 */
     static final ASN1ObjectIdentifier    id_aes192_CFB           = aes.branch("24"); 
+    /** 2.16.840.1.101.3.4.1.25 */
     static final ASN1ObjectIdentifier    id_aes192_wrap          = aes.branch("25");
+    /** 2.16.840.1.101.3.4.1.26 */
     static final ASN1ObjectIdentifier    id_aes192_GCM           = aes.branch("26");
+    /** 2.16.840.1.101.3.4.1.27 */
     static final ASN1ObjectIdentifier    id_aes192_CCM           = aes.branch("27");
     
+    /** 2.16.840.1.101.3.4.1.41 */
     static final ASN1ObjectIdentifier    id_aes256_ECB           = aes.branch("41"); 
+    /** 2.16.840.1.101.3.4.1.42 */
     static final ASN1ObjectIdentifier    id_aes256_CBC           = aes.branch("42");
+    /** 2.16.840.1.101.3.4.1.43 */
     static final ASN1ObjectIdentifier    id_aes256_OFB           = aes.branch("43"); 
+    /** 2.16.840.1.101.3.4.1.44 */
     static final ASN1ObjectIdentifier    id_aes256_CFB           = aes.branch("44"); 
+    /** 2.16.840.1.101.3.4.1.45 */
     static final ASN1ObjectIdentifier    id_aes256_wrap          = aes.branch("45"); 
+    /** 2.16.840.1.101.3.4.1.46 */
     static final ASN1ObjectIdentifier    id_aes256_GCM           = aes.branch("46");
+    /** 2.16.840.1.101.3.4.1.47 */
     static final ASN1ObjectIdentifier    id_aes256_CCM           = aes.branch("47");
 
     //
     // signatures
     //
+    /** 2.16.840.1.101.3.4.3 */
     static final ASN1ObjectIdentifier    id_dsa_with_sha2        = nistAlgorithm.branch("3");
 
+    /** 2.16.840.1.101.3.4.3.1 */
     static final ASN1ObjectIdentifier    dsa_with_sha224         = id_dsa_with_sha2.branch("1");
+    /** 2.16.840.1.101.3.4.3.2 */
     static final ASN1ObjectIdentifier    dsa_with_sha256         = id_dsa_with_sha2.branch("2");
+    /** 2.16.840.1.101.3.4.3.3 */
     static final ASN1ObjectIdentifier    dsa_with_sha384         = id_dsa_with_sha2.branch("3");
+    /** 2.16.840.1.101.3.4.3.4 */
     static final ASN1ObjectIdentifier    dsa_with_sha512         = id_dsa_with_sha2.branch("4");
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java
index 2e4132a..fa32068 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java
@@ -3,15 +3,23 @@
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 /**
- * From RFC 3657
+ * From <a href="http://tools.ietf.org/html/rfc3657">RFC 3657</a>
+ * Use of the Camellia Encryption Algorithm
+ * in Cryptographic Message Syntax (CMS)
  */
 public interface NTTObjectIdentifiers
 {
-    public static final ASN1ObjectIdentifier id_camellia128_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.2");
-    public static final ASN1ObjectIdentifier id_camellia192_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.3");
-    public static final ASN1ObjectIdentifier id_camellia256_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.4");
+    /** id-camellia128-cbc; OID 1.2.392.200011.61.1.1.1.2 */
+    static final ASN1ObjectIdentifier id_camellia128_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.2");
+    /** id-camellia192-cbc; OID 1.2.392.200011.61.1.1.1.3 */
+    static final ASN1ObjectIdentifier id_camellia192_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.3");
+    /** id-camellia256-cbc; OID 1.2.392.200011.61.1.1.1.4 */
+    static final ASN1ObjectIdentifier id_camellia256_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.4");
 
-    public static final ASN1ObjectIdentifier id_camellia128_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.2");
-    public static final ASN1ObjectIdentifier id_camellia192_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.3");
-    public static final ASN1ObjectIdentifier id_camellia256_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.4");
+    /** id-camellia128-wrap; OID 1.2.392.200011.61.1.1.3.2 */
+    static final ASN1ObjectIdentifier id_camellia128_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.2");
+    /** id-camellia192-wrap; OID 1.2.392.200011.61.1.1.3.3 */
+    static final ASN1ObjectIdentifier id_camellia192_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.3");
+    /** id-camellia256-wrap; OID 1.2.392.200011.61.1.1.3.4 */
+    static final ASN1ObjectIdentifier id_camellia256_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.4");
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
index c8ce26b..c169c16 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
@@ -2,30 +2,49 @@
 
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
+/**
+ * OIW organization's OIDs:
+ * <p>
+ * id-SHA1 OBJECT IDENTIFIER ::=    
+ *   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }
+ */
 public interface OIWObjectIdentifiers
 {
-    // id-SHA1 OBJECT IDENTIFIER ::=    
-    //   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //
+    /** OID: 1.3.14.3.2.2 */
     static final ASN1ObjectIdentifier    md4WithRSA              = new ASN1ObjectIdentifier("1.3.14.3.2.2");
+    /** OID: 1.3.14.3.2.3 */
     static final ASN1ObjectIdentifier    md5WithRSA              = new ASN1ObjectIdentifier("1.3.14.3.2.3");
+    /** OID: 1.3.14.3.2.4 */
     static final ASN1ObjectIdentifier    md4WithRSAEncryption    = new ASN1ObjectIdentifier("1.3.14.3.2.4");
     
+    /** OID: 1.3.14.3.2.6 */
     static final ASN1ObjectIdentifier    desECB                  = new ASN1ObjectIdentifier("1.3.14.3.2.6");
+    /** OID: 1.3.14.3.2.7 */
     static final ASN1ObjectIdentifier    desCBC                  = new ASN1ObjectIdentifier("1.3.14.3.2.7");
+    /** OID: 1.3.14.3.2.8 */
     static final ASN1ObjectIdentifier    desOFB                  = new ASN1ObjectIdentifier("1.3.14.3.2.8");
+    /** OID: 1.3.14.3.2.9 */
     static final ASN1ObjectIdentifier    desCFB                  = new ASN1ObjectIdentifier("1.3.14.3.2.9");
 
+    /** OID: 1.3.14.3.2.17 */
     static final ASN1ObjectIdentifier    desEDE                  = new ASN1ObjectIdentifier("1.3.14.3.2.17");
     
+    /** OID: 1.3.14.3.2.26 */
     static final ASN1ObjectIdentifier    idSHA1                  = new ASN1ObjectIdentifier("1.3.14.3.2.26");
 
+    /** OID: 1.3.14.3.2.27 */
     static final ASN1ObjectIdentifier    dsaWithSHA1             = new ASN1ObjectIdentifier("1.3.14.3.2.27");
 
+    /** OID: 1.3.14.3.2.29 */
     static final ASN1ObjectIdentifier    sha1WithRSA             = new ASN1ObjectIdentifier("1.3.14.3.2.29");
     
-    // ElGamal Algorithm OBJECT IDENTIFIER ::=    
-    // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }
-    //
+    /**
+     * <pre>
+     * ElGamal Algorithm OBJECT IDENTIFIER ::=    
+     *   {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }
+     * </pre>
+     * OID: 1.3.14.7.2.1.1
+     */
     static final ASN1ObjectIdentifier    elGamalAlgorithm        = new ASN1ObjectIdentifier("1.3.14.7.2.1.1");
 
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
index 65c0fa8..92c4e8f 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
@@ -9,16 +9,39 @@
 import org.bouncycastle.asn1.ASN1OctetString;
 import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERNull;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
+/**
+ * <pre>
+ *     PBKDF2-params ::= SEQUENCE {
+ *               salt CHOICE {
+ *                      specified OCTET STRING,
+ *                      otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+ *               },
+ *              iterationCount INTEGER (1..MAX),
+ *              keyLength INTEGER (1..MAX) OPTIONAL,
+ *              prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
+ * </pre>
+ */
 public class PBKDF2Params
     extends ASN1Object
 {
+    private static final AlgorithmIdentifier algid_hmacWithSHA1 = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA1, DERNull.INSTANCE);
+
     private ASN1OctetString octStr;
     private ASN1Integer      iterationCount;
     private ASN1Integer      keyLength;
+    private AlgorithmIdentifier prf;
 
+    /**
+     * Create PBKDF2Params from the passed in object,
+     *
+     * @param obj either PBKDF2Params or an ASN2Sequence.
+     * @return a PBKDF2Params instance.
+     */
     public static PBKDF2Params getInstance(
         Object  obj)
     {
@@ -34,7 +57,13 @@
 
         return null;
     }
-    
+
+    /**
+     * Create a PBKDF2Params with the specified salt, iteration count, and algid-hmacWithSHA1 for the prf.
+     *
+     * @param salt  input salt.
+     * @param iterationCount input iteration count.
+     */
     public PBKDF2Params(
         byte[]  salt,
         int     iterationCount)
@@ -43,6 +72,13 @@
         this.iterationCount = new ASN1Integer(iterationCount);
     }
 
+    /**
+     * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and algid-hmacWithSHA1 for the prf.
+     *
+     * @param salt  input salt.
+     * @param iterationCount input iteration count.
+     * @param keyLength intended key length to be produced.
+     */
     public PBKDF2Params(
         byte[]  salt,
         int     iterationCount,
@@ -53,6 +89,42 @@
         this.keyLength = new ASN1Integer(keyLength);
     }
 
+    /**
+     * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and a defined prf.
+     *
+     * @param salt  input salt.
+     * @param iterationCount input iteration count.
+     * @param keyLength intended key length to be produced.
+     * @param prf the pseudo-random function to use.
+     */
+    public PBKDF2Params(
+        byte[]  salt,
+        int     iterationCount,
+        int     keyLength,
+        AlgorithmIdentifier prf)
+    {
+        this(salt, iterationCount);
+
+        this.keyLength = new ASN1Integer(keyLength);
+        this.prf = prf;
+    }
+
+    /**
+     * Create a PBKDF2Params with the specified salt, iteration count, and a defined prf.
+     *
+     * @param salt  input salt.
+     * @param iterationCount input iteration count.
+     * @param prf the pseudo-random function to use.
+     */
+    public PBKDF2Params(
+        byte[]  salt,
+        int     iterationCount,
+        AlgorithmIdentifier prf)
+    {
+        this(salt, iterationCount);
+        this.prf = prf;
+    }
+
     private PBKDF2Params(
         ASN1Sequence  seq)
     {
@@ -63,24 +135,57 @@
 
         if (e.hasMoreElements())
         {
-            keyLength = (ASN1Integer)e.nextElement();
-        }
-        else
-        {
-            keyLength = null;
+            Object o = e.nextElement();
+
+            if (o instanceof ASN1Integer)
+            {
+                keyLength = ASN1Integer.getInstance(o);
+                if (e.hasMoreElements())
+                {
+                    o = e.nextElement();
+                }
+                else
+                {
+                    o = null;
+                }
+            }
+            else
+            {
+                keyLength = null;
+            }
+
+            if (o != null)
+            {
+                prf = AlgorithmIdentifier.getInstance(o);
+            }
         }
     }
 
+    /**
+     * Return the salt to use.
+     *
+     * @return the input salt.
+     */
     public byte[] getSalt()
     {
         return octStr.getOctets();
     }
 
+    /**
+     * Return the iteration count to use.
+     *
+     * @return the input iteration count.
+     */
     public BigInteger getIterationCount()
     {
         return iterationCount.getValue();
     }
 
+    /**
+     * Return the intended length in octets of the derived key.
+     *
+     * @return length in octets for derived key, if specified.
+     */
     public BigInteger getKeyLength()
     {
         if (keyLength != null)
@@ -91,6 +196,36 @@
         return null;
     }
 
+    /**
+     * Return true if the PRF is the default (hmacWithSHA1)
+     *
+     * @return true if PRF is default, false otherwise.
+     */
+    public boolean isDefaultPrf()
+    {
+        return prf == null || prf.equals(algid_hmacWithSHA1);
+    }
+
+    /**
+     * Return the algId of the underlying pseudo random function to use.
+     *
+     * @return the prf algorithm identifier.
+     */
+    public AlgorithmIdentifier getPrf()
+    {
+        if (prf != null)
+        {
+            return prf;
+        }
+
+        return algid_hmacWithSHA1;
+    }
+
+    /**
+     * Return an ASN.1 structure suitable for encoding.
+     *
+     * @return the object as an ASN.1 encodable structure.
+     */
     public ASN1Primitive toASN1Primitive()
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
@@ -103,6 +238,11 @@
             v.add(keyLength);
         }
 
+        if (prf != null && !prf.equals(algid_hmacWithSHA1))
+        {
+            v.add(prf);
+        }
+
         return new DERSequence(v);
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
index 8ca8dc3..82f1f94 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
@@ -2,75 +2,104 @@
 
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
+/**
+ * pkcs-1 OBJECT IDENTIFIER ::=<p>
+ *   { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+ *
+ */
 public interface PKCSObjectIdentifiers
 {
-    //
-    // pkcs-1 OBJECT IDENTIFIER ::= {
-    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
-    //
+    /** PKCS#1: 1.2.840.113549.1.1 */
     static final ASN1ObjectIdentifier    pkcs_1                    = new ASN1ObjectIdentifier("1.2.840.113549.1.1");
+    /** PKCS#1: 1.2.840.113549.1.1.1 */
     static final ASN1ObjectIdentifier    rsaEncryption             = pkcs_1.branch("1");
     // BEGIN android-removed
+    // /** PKCS#1: 1.2.840.113549.1.1.2 */
     // static final ASN1ObjectIdentifier    md2WithRSAEncryption      = pkcs_1.branch("2");
+    // /** PKCS#1: 1.2.840.113549.1.1.3 */
     // static final ASN1ObjectIdentifier    md4WithRSAEncryption      = pkcs_1.branch("3");
     // END android-removed
+    /** PKCS#1: 1.2.840.113549.1.1.4 */
     static final ASN1ObjectIdentifier    md5WithRSAEncryption      = pkcs_1.branch("4");
+    /** PKCS#1: 1.2.840.113549.1.1.5 */
     static final ASN1ObjectIdentifier    sha1WithRSAEncryption     = pkcs_1.branch("5");
+    /** PKCS#1: 1.2.840.113549.1.1.6 */
     static final ASN1ObjectIdentifier    srsaOAEPEncryptionSET     = pkcs_1.branch("6");
+    /** PKCS#1: 1.2.840.113549.1.1.7 */
     static final ASN1ObjectIdentifier    id_RSAES_OAEP             = pkcs_1.branch("7");
+    /** PKCS#1: 1.2.840.113549.1.1.8 */
     static final ASN1ObjectIdentifier    id_mgf1                   = pkcs_1.branch("8");
+    /** PKCS#1: 1.2.840.113549.1.1.9 */
     static final ASN1ObjectIdentifier    id_pSpecified             = pkcs_1.branch("9");
+    /** PKCS#1: 1.2.840.113549.1.1.10 */
     static final ASN1ObjectIdentifier    id_RSASSA_PSS             = pkcs_1.branch("10");
+    /** PKCS#1: 1.2.840.113549.1.1.11 */
     static final ASN1ObjectIdentifier    sha256WithRSAEncryption   = pkcs_1.branch("11");
+    /** PKCS#1: 1.2.840.113549.1.1.12 */
     static final ASN1ObjectIdentifier    sha384WithRSAEncryption   = pkcs_1.branch("12");
+    /** PKCS#1: 1.2.840.113549.1.1.13 */
     static final ASN1ObjectIdentifier    sha512WithRSAEncryption   = pkcs_1.branch("13");
-    // BEGIN android-removed
-    // static final ASN1ObjectIdentifier    sha224WithRSAEncryption   = pkcs_1.branch("14");
-    // END android-removed
+    /** PKCS#1: 1.2.840.113549.1.1.14 */
+    static final ASN1ObjectIdentifier    sha224WithRSAEncryption   = pkcs_1.branch("14");
 
     //
     // pkcs-3 OBJECT IDENTIFIER ::= {
     //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 }
     //
+    /** PKCS#3: 1.2.840.113549.1.3 */
     static final ASN1ObjectIdentifier    pkcs_3                  = new ASN1ObjectIdentifier("1.2.840.113549.1.3");
+    /** PKCS#3: 1.2.840.113549.1.3.1 */
     static final ASN1ObjectIdentifier    dhKeyAgreement          = pkcs_3.branch("1");
 
     //
     // pkcs-5 OBJECT IDENTIFIER ::= {
     //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 }
     //
+    /** PKCS#5: 1.2.840.113549.1.5 */
     static final ASN1ObjectIdentifier    pkcs_5                  = new ASN1ObjectIdentifier("1.2.840.113549.1.5");
 
+    /** PKCS#5: 1.2.840.113549.1.5.1 */
     static final ASN1ObjectIdentifier    pbeWithMD2AndDES_CBC    = pkcs_5.branch("1");
+    /** PKCS#5: 1.2.840.113549.1.5.4 */
     static final ASN1ObjectIdentifier    pbeWithMD2AndRC2_CBC    = pkcs_5.branch("4");
+    /** PKCS#5: 1.2.840.113549.1.5.3 */
     static final ASN1ObjectIdentifier    pbeWithMD5AndDES_CBC    = pkcs_5.branch("3");
+    /** PKCS#5: 1.2.840.113549.1.5.6 */
     static final ASN1ObjectIdentifier    pbeWithMD5AndRC2_CBC    = pkcs_5.branch("6");
+    /** PKCS#5: 1.2.840.113549.1.5.10 */
     static final ASN1ObjectIdentifier    pbeWithSHA1AndDES_CBC   = pkcs_5.branch("10");
+    /** PKCS#5: 1.2.840.113549.1.5.11 */
     static final ASN1ObjectIdentifier    pbeWithSHA1AndRC2_CBC   = pkcs_5.branch("11");
-
+    /** PKCS#5: 1.2.840.113549.1.5.13 */
     static final ASN1ObjectIdentifier    id_PBES2                = pkcs_5.branch("13");
-
+    /** PKCS#5: 1.2.840.113549.1.5.12 */
     static final ASN1ObjectIdentifier    id_PBKDF2               = pkcs_5.branch("12");
 
     //
     // encryptionAlgorithm OBJECT IDENTIFIER ::= {
     //       iso(1) member-body(2) us(840) rsadsi(113549) 3 }
     //
+    /**  1.2.840.113549.3 */
     static final ASN1ObjectIdentifier    encryptionAlgorithm     = new ASN1ObjectIdentifier("1.2.840.113549.3");
 
+    /**  1.2.840.113549.3.7 */
     static final ASN1ObjectIdentifier    des_EDE3_CBC            = encryptionAlgorithm.branch("7");
+    /**  1.2.840.113549.3.2 */
     static final ASN1ObjectIdentifier    RC2_CBC                 = encryptionAlgorithm.branch("2");
+    /**  1.2.840.113549.3.4 */
     static final ASN1ObjectIdentifier    rc4                     = encryptionAlgorithm.branch("4");
 
     //
     // object identifiers for digests
     //
+    /**  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
+    // /**  1.2.840.113549.2.2 */
     // static final ASN1ObjectIdentifier    md2                    = digestAlgorithm.branch("2");
     // END android-removed
 
@@ -79,190 +108,289 @@
     //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4}
     //
     // BEGIN android-removed
-    // static final ASN1ObjectIdentifier    md4 = digestAlgorithm.branch("4");
+    // /**  1.2.840.113549.2.4 */
+    // 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 ASN1ObjectIdentifier    md5                     = digestAlgorithm.branch("5");
+    /**  1.2.840.113549.2.5 */
+    static final ASN1ObjectIdentifier    md5                    = digestAlgorithm.branch("5");
 
-    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");
+    /**  1.2.840.113549.2.7 */
+    static final ASN1ObjectIdentifier    id_hmacWithSHA1        = digestAlgorithm.branch("7");
+    /**  1.2.840.113549.2.8 */
+    static final ASN1ObjectIdentifier    id_hmacWithSHA224      = digestAlgorithm.branch("8");
+    /**  1.2.840.113549.2.9 */
+    static final ASN1ObjectIdentifier    id_hmacWithSHA256      = digestAlgorithm.branch("9");
+    /**  1.2.840.113549.2.10 */
+    static final ASN1ObjectIdentifier    id_hmacWithSHA384      = digestAlgorithm.branch("10");
+    /**  1.2.840.113549.2.11 */
+    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 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#7: 1.2.840.113549.1.7 */
+    static final ASN1ObjectIdentifier    pkcs_7                  = new ASN1ObjectIdentifier("1.2.840.113549.1.7");
+    /** PKCS#7: 1.2.840.113549.1.7.1 */
+    static final ASN1ObjectIdentifier    data                    = new ASN1ObjectIdentifier("1.2.840.113549.1.7.1");
+    /** PKCS#7: 1.2.840.113549.1.7.2 */
+    static final ASN1ObjectIdentifier    signedData              = new ASN1ObjectIdentifier("1.2.840.113549.1.7.2");
+    /** PKCS#7: 1.2.840.113549.1.7.3 */
+    static final ASN1ObjectIdentifier    envelopedData           = new ASN1ObjectIdentifier("1.2.840.113549.1.7.3");
+    /** PKCS#7: 1.2.840.113549.1.7.4 */
+    static final ASN1ObjectIdentifier    signedAndEnvelopedData  = new ASN1ObjectIdentifier("1.2.840.113549.1.7.4");
+    /** PKCS#7: 1.2.840.113549.1.7.5 */
+    static final ASN1ObjectIdentifier    digestedData            = new ASN1ObjectIdentifier("1.2.840.113549.1.7.5");
+    /** PKCS#7: 1.2.840.113549.1.7.76 */
+    static final ASN1ObjectIdentifier    encryptedData           = new ASN1ObjectIdentifier("1.2.840.113549.1.7.6");
 
     //
     // pkcs-9 OBJECT IDENTIFIER ::= {
     //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
     //
+    /** PKCS#9: 1.2.840.113549.1.9 */
     static final ASN1ObjectIdentifier    pkcs_9                  = new ASN1ObjectIdentifier("1.2.840.113549.1.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");
+    /** PKCS#9: 1.2.840.113549.1.9.1 */
+    static final ASN1ObjectIdentifier    pkcs_9_at_emailAddress        = pkcs_9.branch("1");
+    /** PKCS#9: 1.2.840.113549.1.9.2 */
+    static final ASN1ObjectIdentifier    pkcs_9_at_unstructuredName    = pkcs_9.branch("2");
+    /** PKCS#9: 1.2.840.113549.1.9.3 */
+    static final ASN1ObjectIdentifier    pkcs_9_at_contentType         = pkcs_9.branch("3");
+    /** PKCS#9: 1.2.840.113549.1.9.4 */
+    static final ASN1ObjectIdentifier    pkcs_9_at_messageDigest       = pkcs_9.branch("4");
+    /** PKCS#9: 1.2.840.113549.1.9.5 */
+    static final ASN1ObjectIdentifier    pkcs_9_at_signingTime         = pkcs_9.branch("5");
+    /** PKCS#9: 1.2.840.113549.1.9.6 */
+    static final ASN1ObjectIdentifier    pkcs_9_at_counterSignature    = pkcs_9.branch("6");
+    /** PKCS#9: 1.2.840.113549.1.9.7 */
+    static final ASN1ObjectIdentifier    pkcs_9_at_challengePassword   = pkcs_9.branch("7");
+    /** PKCS#9: 1.2.840.113549.1.9.8 */
     static final ASN1ObjectIdentifier    pkcs_9_at_unstructuredAddress = pkcs_9.branch("8");
+    /** PKCS#9: 1.2.840.113549.1.9.9 */
     static final ASN1ObjectIdentifier    pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9");
 
+    /** PKCS#9: 1.2.840.113549.1.9.13 */
     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");
+    /** PKCS#9: 1.2.840.113549.1.9.14 */
+    static final ASN1ObjectIdentifier    pkcs_9_at_extensionRequest   = pkcs_9.branch("14");
+    /** PKCS#9: 1.2.840.113549.1.9.15 */
+    static final ASN1ObjectIdentifier    pkcs_9_at_smimeCapabilities  = pkcs_9.branch("15");
+    /** PKCS#9: 1.2.840.113549.1.9.16 */
+    static final ASN1ObjectIdentifier    id_smime                     = pkcs_9.branch("16");
 
+    /** PKCS#9: 1.2.840.113549.1.9.20 */
     static final ASN1ObjectIdentifier    pkcs_9_at_friendlyName  = pkcs_9.branch("20");
+    /** PKCS#9: 1.2.840.113549.1.9.21 */
     static final ASN1ObjectIdentifier    pkcs_9_at_localKeyId    = pkcs_9.branch("21");
 
-    /** @deprecated use x509Certificate instead */
+    /** PKCS#9: 1.2.840.113549.1.9.22.1
+     * @deprecated use x509Certificate instead */
     static final ASN1ObjectIdentifier    x509certType            = pkcs_9.branch("22.1");
 
+    /** PKCS#9: 1.2.840.113549.1.9.22 */
     static final ASN1ObjectIdentifier    certTypes               = pkcs_9.branch("22");
+    /** PKCS#9: 1.2.840.113549.1.9.22.1 */
     static final ASN1ObjectIdentifier    x509Certificate         = certTypes.branch("1");
+    /** PKCS#9: 1.2.840.113549.1.9.22.2 */
     static final ASN1ObjectIdentifier    sdsiCertificate         = certTypes.branch("2");
 
+    /** PKCS#9: 1.2.840.113549.1.9.23 */
     static final ASN1ObjectIdentifier    crlTypes                = pkcs_9.branch("23");
+    /** PKCS#9: 1.2.840.113549.1.9.23.1 */
     static final ASN1ObjectIdentifier    x509Crl                 = crlTypes.branch("1");
 
-    static final ASN1ObjectIdentifier    id_alg_PWRI_KEK    = pkcs_9.branch("16.3.9");
-
     //
     // SMIME capability sub oids.
     //
+    /** PKCS#9: 1.2.840.113549.1.9.15.1 -- smime capability */
     static final ASN1ObjectIdentifier    preferSignedData        = pkcs_9.branch("15.1");
+    /** PKCS#9: 1.2.840.113549.1.9.15.2 -- smime capability  */
     static final ASN1ObjectIdentifier    canNotDecryptAny        = pkcs_9.branch("15.2");
+    /** PKCS#9: 1.2.840.113549.1.9.15.3 -- smime capability  */
     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)}
     //
+    /** PKCS#9: 1.2.840.113549.1.9.16.1 -- smime ct */
     static final ASN1ObjectIdentifier    id_ct = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1");
 
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.2 -- smime ct authData */
     static final ASN1ObjectIdentifier    id_ct_authData          = id_ct.branch("2");
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.4 -- smime ct TSTInfo*/
     static final ASN1ObjectIdentifier    id_ct_TSTInfo           = id_ct.branch("4");
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.9 -- smime ct compressedData */
     static final ASN1ObjectIdentifier    id_ct_compressedData    = id_ct.branch("9");
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.23 -- smime ct authEnvelopedData */
     static final ASN1ObjectIdentifier    id_ct_authEnvelopedData = id_ct.branch("23");
+    /** PKCS#9: 1.2.840.113549.1.9.16.1.31 -- smime ct timestampedData*/
     static final ASN1ObjectIdentifier    id_ct_timestampedData   = id_ct.branch("31");
 
+
+    /** S/MIME: Algorithm Identifiers ; 1.2.840.113549.1.9.16.3 */
+    static final ASN1ObjectIdentifier id_alg                  = id_smime.branch("3");
+    /** PKCS#9: 1.2.840.113549.1.9.16.3.9 */
+    static final ASN1ObjectIdentifier id_alg_PWRI_KEK         = id_alg.branch("9");
+
     //
     // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
     // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)}
     //
+    /** PKCS#9: 1.2.840.113549.1.9.16.6 -- smime cti */
     static final ASN1ObjectIdentifier    id_cti = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.6");
     
-    static final ASN1ObjectIdentifier    id_cti_ets_proofOfOrigin  = id_cti.branch("1");
-    static final ASN1ObjectIdentifier    id_cti_ets_proofOfReceipt = id_cti.branch("2");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.1 -- smime cti proofOfOrigin */
+    static final ASN1ObjectIdentifier    id_cti_ets_proofOfOrigin   = id_cti.branch("1");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2 -- smime cti proofOfReceipt*/
+    static final ASN1ObjectIdentifier    id_cti_ets_proofOfReceipt  = id_cti.branch("2");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.3 -- smime cti proofOfDelivery */
     static final ASN1ObjectIdentifier    id_cti_ets_proofOfDelivery = id_cti.branch("3");
-    static final ASN1ObjectIdentifier    id_cti_ets_proofOfSender = id_cti.branch("4");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.4 -- smime cti proofOfSender */
+    static final ASN1ObjectIdentifier    id_cti_ets_proofOfSender   = id_cti.branch("4");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.5 -- smime cti proofOfApproval */
     static final ASN1ObjectIdentifier    id_cti_ets_proofOfApproval = id_cti.branch("5");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.6 -- smime cti proofOfCreation */
     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)}
     //
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2 - smime attributes */
     static final ASN1ObjectIdentifier    id_aa = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.2");
 
 
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.1 -- smime attribute receiptRequest */
     static final ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch("1");
     
-    static final ASN1ObjectIdentifier id_aa_contentHint = id_aa.branch("4"); // See RFC 2634
-    static final ASN1ObjectIdentifier id_aa_msgSigDigest = id_aa.branch("5");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.4 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */
+    static final ASN1ObjectIdentifier id_aa_contentHint      = id_aa.branch("4"); // See RFC 2634
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.5 */
+    static final ASN1ObjectIdentifier id_aa_msgSigDigest     = id_aa.branch("5");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.10 */
     static final ASN1ObjectIdentifier id_aa_contentReference = id_aa.branch("10");
     /*
      * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11}
      * 
      */
-    static final ASN1ObjectIdentifier id_aa_encrypKeyPref = id_aa.branch("11");
-    static final ASN1ObjectIdentifier id_aa_signingCertificate = id_aa.branch("12");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.11 */
+    static final ASN1ObjectIdentifier id_aa_encrypKeyPref        = id_aa.branch("11");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.12 */
+    static final ASN1ObjectIdentifier id_aa_signingCertificate   = id_aa.branch("12");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.47 */
     static final ASN1ObjectIdentifier id_aa_signingCertificateV2 = id_aa.branch("47");
 
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.7 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */
     static final ASN1ObjectIdentifier id_aa_contentIdentifier = id_aa.branch("7"); // See RFC 2634
 
     /*
      * RFC 3126
      */
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.14 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_signatureTimeStampToken = id_aa.branch("14");
     
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.15 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_sigPolicyId = id_aa.branch("15");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.16 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_commitmentType = id_aa.branch("16");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.17 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_signerLocation = id_aa.branch("17");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.18 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_signerAttr = id_aa.branch("18");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.19 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_otherSigCert = id_aa.branch("19");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.20 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_contentTimestamp = id_aa.branch("20");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.21 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_certificateRefs = id_aa.branch("21");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.22 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_revocationRefs = id_aa.branch("22");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.23 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_certValues = id_aa.branch("23");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.24 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_revocationValues = id_aa.branch("24");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.25 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_escTimeStamp = id_aa.branch("25");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.26 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_certCRLTimestamp = id_aa.branch("26");
+    /** PKCS#9: 1.2.840.113549.1.9.16.6.2.27 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */
     static final ASN1ObjectIdentifier id_aa_ets_archiveTimestamp = id_aa.branch("27");
 
     /** @deprecated use id_aa_ets_sigPolicyId instead */
-    static final ASN1ObjectIdentifier 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 ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType;
     /** @deprecated use id_aa_ets_signerLocation instead */
     static final ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation;
     /** @deprecated use id_aa_ets_otherSigCert instead */
-    static final ASN1ObjectIdentifier 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)
-    // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)}
-    //
+    /**
+     * id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+     * rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)}; <p>
+     * 1.2.840.113549.1.9.16.5
+     */
     final String id_spq = "1.2.840.113549.1.9.16.5";
 
-    static final ASN1ObjectIdentifier id_spq_ets_uri = new ASN1ObjectIdentifier(id_spq + ".1");
+    /** SMIME SPQ URI:     1.2.840.113549.1.9.16.5.1 */
+    static final ASN1ObjectIdentifier id_spq_ets_uri     = new ASN1ObjectIdentifier(id_spq + ".1");
+    /** SMIME SPQ UNOTICE: 1.2.840.113549.1.9.16.5.2 */
     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 }
     //
+    /** PKCS#12: 1.2.840.113549.1.12 */
     static final ASN1ObjectIdentifier   pkcs_12                  = new ASN1ObjectIdentifier("1.2.840.113549.1.12");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1 */
     static final ASN1ObjectIdentifier   bagtypes                 = pkcs_12.branch("10.1");
 
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.1 */
     static final ASN1ObjectIdentifier    keyBag                  = bagtypes.branch("1");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.2 */
     static final ASN1ObjectIdentifier    pkcs8ShroudedKeyBag     = bagtypes.branch("2");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.3 */
     static final ASN1ObjectIdentifier    certBag                 = bagtypes.branch("3");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.4 */
     static final ASN1ObjectIdentifier    crlBag                  = bagtypes.branch("4");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.5 */
     static final ASN1ObjectIdentifier    secretBag               = bagtypes.branch("5");
+    /** PKCS#12: 1.2.840.113549.1.12.10.1.6 */
     static final ASN1ObjectIdentifier    safeContentsBag         = bagtypes.branch("6");
 
-    static final ASN1ObjectIdentifier    pkcs_12PbeIds  = pkcs_12.branch("1");
+    /** PKCS#12: 1.2.840.113549.1.12.1 */
+    static final ASN1ObjectIdentifier    pkcs_12PbeIds           = pkcs_12.branch("1");
 
-    static final ASN1ObjectIdentifier    pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch("1");
-    static final ASN1ObjectIdentifier    pbeWithSHAAnd40BitRC4  = pkcs_12PbeIds.branch("2");
+    /** PKCS#12: 1.2.840.113549.1.12.1.1 */
+    static final ASN1ObjectIdentifier    pbeWithSHAAnd128BitRC4          = pkcs_12PbeIds.branch("1");
+    /** PKCS#12: 1.2.840.113549.1.12.1.2 */
+    static final ASN1ObjectIdentifier    pbeWithSHAAnd40BitRC4           = pkcs_12PbeIds.branch("2");
+    /** PKCS#12: 1.2.840.113549.1.12.1.3 */
     static final ASN1ObjectIdentifier    pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch("3");
+    /** PKCS#12: 1.2.840.113549.1.12.1.4 */
     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");
+    /** PKCS#12: 1.2.840.113549.1.12.1.5 */
+    static final ASN1ObjectIdentifier    pbeWithSHAAnd128BitRC2_CBC      = pkcs_12PbeIds.branch("5");
+    /** PKCS#12: 1.2.840.113549.1.12.1.6 */
+    static final ASN1ObjectIdentifier    pbeWithSHAAnd40BitRC2_CBC       = pkcs_12PbeIds.branch("6");
 
     /**
+     * PKCS#12: 1.2.840.113549.1.12.1.6
      * @deprecated use pbeWithSHAAnd40BitRC2_CBC
      */
     static final ASN1ObjectIdentifier    pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6");
 
+    /** PKCS#9: 1.2.840.113549.1.9.16.3.6 */
     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");
+    /** PKCS#9: 1.2.840.113549.1.9.16.3.7 */
+    static final ASN1ObjectIdentifier    id_alg_CMSRC2wrap  = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7");
 }
 
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
index 515b515..e707fd1 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
@@ -57,7 +57,11 @@
         this.maskGenAlgorithm = maskGenAlgorithm;
         this.pSourceAlgorithm = pSourceAlgorithm;
     }
-    
+
+    /**
+     * @deprecated use getInstance()
+     * @param seq
+     */
     public RSAESOAEPparams(
         ASN1Sequence seq)
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java
index 4bf6b2b..df2238a 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java
@@ -62,7 +62,7 @@
 
     public ECPrivateKey(
         BigInteger key,
-        ASN1Object parameters)
+        ASN1Encodable parameters)
     {
         this(key, null, parameters);
     }
@@ -70,7 +70,7 @@
     public ECPrivateKey(
         BigInteger key,
         DERBitString publicKey,
-        ASN1Object parameters)
+        ASN1Encodable parameters)
     {
         byte[] bytes = BigIntegers.asUnsignedByteArray(key);
 
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
index 44c811b..50a7a63 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
@@ -15,6 +15,21 @@
 
 public class SECNamedCurves
 {
+    private static ECCurve configureCurve(ECCurve curve)
+    {
+//        int coord = ECCurve.COORD_JACOBIAN_MODIFIED;
+//
+//        if (curve.getCoordinateSystem() != coord && curve.supportsCoordinateSystem(coord))
+//        {
+//            return curve.configure()
+//                .setCoordinateSystem(coord)
+////                .setMultiplier(new WNafL2RMultiplier())
+//                .create();
+//        }
+
+        return curve;
+    }
+
     private static BigInteger fromHex(
         String hex)
     {
@@ -36,7 +51,7 @@
             BigInteger n = fromHex("DB7C2ABF62E35E7628DFAC6561C5");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("02"
             //+ "09487239995A5EE76B55F9C2F098"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -62,7 +77,7 @@
             BigInteger n = fromHex("36DF0AAFD8B8D7597CA10520D04B");
             BigInteger h = BigInteger.valueOf(4);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "4BA30AB5E892B4E1649DD0928643"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -88,7 +103,7 @@
             BigInteger n = fromHex("FFFFFFFE0000000075A30D1B9038A115");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "161FF7528B899B2D0C28607CA52C5B86"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -114,7 +129,7 @@
             BigInteger n = fromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3");
             BigInteger h = BigInteger.valueOf(4);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("02"
             //+ "7B6AA5D85E572983E6FB32A7CDEBC140"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -140,7 +155,7 @@
             BigInteger n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
 //            ECPoint G = curve.decodePoint(Hex.decode("02"
 //                + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -166,7 +181,7 @@
             BigInteger n = fromHex("0100000000000000000001F4C8F927AED3CA752257");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("02"
                 //+ "4A96B5688EF573284664698968C38BB913CBFC82"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -192,7 +207,7 @@
             BigInteger n = fromHex("0100000000000000000000351EE786A818F3A1A16B");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("02"
             //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -218,7 +233,7 @@
             BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -244,7 +259,7 @@
             BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -270,7 +285,7 @@
             BigInteger n = fromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -296,7 +311,7 @@
             BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("02"
             //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -322,7 +337,7 @@
             BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("02"
             //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -348,7 +363,7 @@
             BigInteger n = fromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -374,7 +389,7 @@
             BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -400,7 +415,8 @@
             BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409");
             BigInteger h = BigInteger.valueOf(1);
 
-            ECCurve curve = new ECCurve.Fp(p, a, b);
+            ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b));
+
             //ECPoint G = curve.decodePoint(Hex.decode("02"
             //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -410,7 +426,7 @@
             return new X9ECParameters(curve, G, n, h, S);
         }
     };
-    
+
     /*
      * sect113r1
      */
@@ -427,7 +443,7 @@
             BigInteger n = fromHex("0100000000000000D9CCEC8A39E56F");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "009D73616F35F4AB1407D73562C10F"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -454,7 +470,7 @@
             BigInteger n = fromHex("010000000000000108789B2496AF93");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "01A57A6A7B26CA5EF52FCDB8164797"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -483,7 +499,7 @@
             BigInteger n = fromHex("0400000000000000023123953A9464B54D");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "0081BAF91FDF9833C40F9C181343638399"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -512,7 +528,7 @@
             BigInteger n = fromHex("0400000000000000016954A233049BA98F");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "0356DCD8F2F95031AD652D23951BB366A8"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -541,7 +557,7 @@
             BigInteger n = fromHex("04000000000000000000020108A2E0CC0D99F8A5EF");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -570,7 +586,7 @@
             BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "0369979697AB43897789566789567F787A7876A654"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -599,7 +615,7 @@
             BigInteger n = fromHex("040000000000000000000292FE77E70C12A4234C33");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -626,7 +642,7 @@
             BigInteger n = fromHex("01000000000000000000000000C7F34A778F443ACC920EBA49");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -653,7 +669,7 @@
             BigInteger n = fromHex("010000000000000000000000015AAB561B005413CCD4EE99D5");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -680,7 +696,7 @@
             BigInteger n = fromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF");
             BigInteger h = BigInteger.valueOf(4);
 
-            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("02"
             //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -707,7 +723,7 @@
             BigInteger n = fromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -734,7 +750,7 @@
             BigInteger n = fromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5");
             BigInteger h = BigInteger.valueOf(4);
 
-            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -763,7 +779,7 @@
             BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61");
             BigInteger h = BigInteger.valueOf(4);
 
-            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("02"
             //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -792,7 +808,7 @@
             BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -819,7 +835,7 @@
             BigInteger n = fromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF");
             BigInteger h = BigInteger.valueOf(4);
 
-            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -846,7 +862,7 @@
             BigInteger n = fromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -875,7 +891,7 @@
             BigInteger n = fromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001");
             BigInteger h = BigInteger.valueOf(4);
 
-            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("02"
             //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
@@ -904,7 +920,7 @@
             BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47");
             BigInteger h = BigInteger.valueOf(2);
 
-            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);
+            ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h));
             //ECPoint G = curve.decodePoint(Hex.decode("03"
             //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"));
             ECPoint G = curve.decodePoint(Hex.decode("04"
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
index 8b19cd6..fb60aca 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
@@ -3,48 +3,85 @@
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 
+/**
+ * Certicom object identifiers
+ * <pre>
+ *  ellipticCurve OBJECT IDENTIFIER ::= {
+ *        iso(1) identified-organization(3) certicom(132) curve(0)
+ *  }
+ * </pre>
+ */
 public interface SECObjectIdentifiers
 {
-    /**
-     *  ellipticCurve OBJECT IDENTIFIER ::= {
-     *        iso(1) identified-organization(3) certicom(132) curve(0)
-     *  }
-     */
+    /** Base OID: 1.3.132.0 */
     static final ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier("1.3.132.0");
 
+    /**  sect163k1 OID: 1.3.132.0.1 */
     static final ASN1ObjectIdentifier sect163k1 = ellipticCurve.branch("1");
+    /**  sect163r1 OID: 1.3.132.0.2 */
     static final ASN1ObjectIdentifier sect163r1 = ellipticCurve.branch("2");
+    /**  sect239k1 OID: 1.3.132.0.3 */
     static final ASN1ObjectIdentifier sect239k1 = ellipticCurve.branch("3");
+    /**  sect113r1 OID: 1.3.132.0.4 */
     static final ASN1ObjectIdentifier sect113r1 = ellipticCurve.branch("4");
+    /**  sect113r2 OID: 1.3.132.0.5 */
     static final ASN1ObjectIdentifier sect113r2 = ellipticCurve.branch("5");
+    /**  secp112r1 OID: 1.3.132.0.6 */
     static final ASN1ObjectIdentifier secp112r1 = ellipticCurve.branch("6");
+    /**  secp112r2 OID: 1.3.132.0.7 */
     static final ASN1ObjectIdentifier secp112r2 = ellipticCurve.branch("7");
+    /**  secp160r1 OID: 1.3.132.0.8 */
     static final ASN1ObjectIdentifier secp160r1 = ellipticCurve.branch("8");
+    /**  secp160k1 OID: 1.3.132.0.9 */
     static final ASN1ObjectIdentifier secp160k1 = ellipticCurve.branch("9");
+    /**  secp256k1 OID: 1.3.132.0.10 */
     static final ASN1ObjectIdentifier secp256k1 = ellipticCurve.branch("10");
+    /**  sect163r2 OID: 1.3.132.0.15 */
     static final ASN1ObjectIdentifier sect163r2 = ellipticCurve.branch("15");
+    /**  sect283k1 OID: 1.3.132.0.16 */
     static final ASN1ObjectIdentifier sect283k1 = ellipticCurve.branch("16");
+    /**  sect283r1 OID: 1.3.132.0.17 */
     static final ASN1ObjectIdentifier sect283r1 = ellipticCurve.branch("17");
+    /**  sect131r1 OID: 1.3.132.0.22 */
     static final ASN1ObjectIdentifier sect131r1 = ellipticCurve.branch("22");
+    /**  sect131r2 OID: 1.3.132.0.23 */
     static final ASN1ObjectIdentifier sect131r2 = ellipticCurve.branch("23");
+    /**  sect193r1 OID: 1.3.132.0.24 */
     static final ASN1ObjectIdentifier sect193r1 = ellipticCurve.branch("24");
+    /**  sect193r2 OID: 1.3.132.0.25 */
     static final ASN1ObjectIdentifier sect193r2 = ellipticCurve.branch("25");
+    /**  sect233k1 OID: 1.3.132.0.26 */
     static final ASN1ObjectIdentifier sect233k1 = ellipticCurve.branch("26");
+    /**  sect233r1 OID: 1.3.132.0.27 */
     static final ASN1ObjectIdentifier sect233r1 = ellipticCurve.branch("27");
+    /**  secp128r1 OID: 1.3.132.0.28 */
     static final ASN1ObjectIdentifier secp128r1 = ellipticCurve.branch("28");
+    /**  secp128r2 OID: 1.3.132.0.29 */
     static final ASN1ObjectIdentifier secp128r2 = ellipticCurve.branch("29");
+    /**  secp160r2 OID: 1.3.132.0.30 */
     static final ASN1ObjectIdentifier secp160r2 = ellipticCurve.branch("30");
+    /**  secp192k1 OID: 1.3.132.0.31 */
     static final ASN1ObjectIdentifier secp192k1 = ellipticCurve.branch("31");
+    /**  secp224k1 OID: 1.3.132.0.32 */
     static final ASN1ObjectIdentifier secp224k1 = ellipticCurve.branch("32");
+    /**  secp224r1 OID: 1.3.132.0.33 */
     static final ASN1ObjectIdentifier secp224r1 = ellipticCurve.branch("33");
+    /**  secp384r1 OID: 1.3.132.0.34 */
     static final ASN1ObjectIdentifier secp384r1 = ellipticCurve.branch("34");
+    /**  secp521r1 OID: 1.3.132.0.35 */
     static final ASN1ObjectIdentifier secp521r1 = ellipticCurve.branch("35");
+    /**  sect409k1 OID: 1.3.132.0.36 */
     static final ASN1ObjectIdentifier sect409k1 = ellipticCurve.branch("36");
+    /**  sect409r1 OID: 1.3.132.0.37 */
     static final ASN1ObjectIdentifier sect409r1 = ellipticCurve.branch("37");
+    /**  sect571k1 OID: 1.3.132.0.38 */
     static final ASN1ObjectIdentifier sect571k1 = ellipticCurve.branch("38");
+    /**  sect571r1 OID: 1.3.132.0.39 */
     static final ASN1ObjectIdentifier sect571r1 = ellipticCurve.branch("39");
 
+    /**  secp192r1 OID: 1.3.132.0.prime192v1 */
     static final ASN1ObjectIdentifier secp192r1 = X9ObjectIdentifiers.prime192v1;
+    /**  secp256r1 OID: 1.3.132.0.prime256v1 */
     static final ASN1ObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1;
 
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
index df9a0ff..895f5e8 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
@@ -2,41 +2,74 @@
 
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
+/**
+ * TeleTrusT:
+ *   { iso(1) identifier-organization(3) teleTrust(36) algorithm(3)
+ *
+ */
 public interface TeleTrusTObjectIdentifiers
 {
+    /** 1.3.36.3 */
     static final ASN1ObjectIdentifier teleTrusTAlgorithm = new ASN1ObjectIdentifier("1.3.36.3");
 
+    /** 1.3.36.3.2.1 */
     static final ASN1ObjectIdentifier    ripemd160           = teleTrusTAlgorithm.branch("2.1");
+    /** 1.3.36.3.2.2 */
     static final ASN1ObjectIdentifier    ripemd128           = teleTrusTAlgorithm.branch("2.2");
+    /** 1.3.36.3.2.3 */
     static final ASN1ObjectIdentifier    ripemd256           = teleTrusTAlgorithm.branch("2.3");
 
+    /** 1.3.36.3.3.1 */
     static final ASN1ObjectIdentifier teleTrusTRSAsignatureAlgorithm = teleTrusTAlgorithm.branch("3.1");
 
-    static final ASN1ObjectIdentifier    rsaSignatureWithripemd160           = teleTrusTRSAsignatureAlgorithm.branch("2");
-    static final ASN1ObjectIdentifier    rsaSignatureWithripemd128           = teleTrusTRSAsignatureAlgorithm.branch("3");
-    static final ASN1ObjectIdentifier    rsaSignatureWithripemd256           = teleTrusTRSAsignatureAlgorithm.branch("4");
+    /** 1.3.36.3.3.1.2 */
+    static final ASN1ObjectIdentifier rsaSignatureWithripemd160      = teleTrusTRSAsignatureAlgorithm.branch("2");
+    /** 1.3.36.3.3.1.3 */
+    static final ASN1ObjectIdentifier rsaSignatureWithripemd128      = teleTrusTRSAsignatureAlgorithm.branch("3");
+    /** 1.3.36.3.3.1.4 */
+    static final ASN1ObjectIdentifier rsaSignatureWithripemd256      = teleTrusTRSAsignatureAlgorithm.branch("4");
 
-    static final ASN1ObjectIdentifier    ecSign = teleTrusTAlgorithm.branch("3.2");
+    /** 1.3.36.3.3.2 */
+    static final ASN1ObjectIdentifier    ecSign               = teleTrusTAlgorithm.branch("3.2");
 
-    static final ASN1ObjectIdentifier    ecSignWithSha1  = ecSign.branch("1");
+    /** 1.3.36.3.3.2,1 */
+    static final ASN1ObjectIdentifier    ecSignWithSha1       = ecSign.branch("1");
+    /** 1.3.36.3.3.2.2 */
     static final ASN1ObjectIdentifier    ecSignWithRipemd160  = ecSign.branch("2");
 
+    /** 1.3.36.3.3.2.8 */
     static final ASN1ObjectIdentifier ecc_brainpool = teleTrusTAlgorithm.branch("3.2.8");
+    /** 1.3.36.3.3.2.8.1 */
     static final ASN1ObjectIdentifier ellipticCurve = ecc_brainpool.branch("1");
+    /** 1.3.36.3.3.2.8.1 */
     static final ASN1ObjectIdentifier versionOne = ellipticCurve.branch("1");
 
+    /** 1.3.36.3.3.2.8.1.1 */
     static final ASN1ObjectIdentifier brainpoolP160r1 = versionOne.branch("1");
+    /** 1.3.36.3.3.2.8.1.2 */
     static final ASN1ObjectIdentifier brainpoolP160t1 = versionOne.branch("2");
+    /** 1.3.36.3.3.2.8.1.3 */
     static final ASN1ObjectIdentifier brainpoolP192r1 = versionOne.branch("3");
+    /** 1.3.36.3.3.2.8.1.4 */
     static final ASN1ObjectIdentifier brainpoolP192t1 = versionOne.branch("4");
+    /** 1.3.36.3.3.2.8.1.5 */
     static final ASN1ObjectIdentifier brainpoolP224r1 = versionOne.branch("5");
+    /** 1.3.36.3.3.2.8.1.6 */
     static final ASN1ObjectIdentifier brainpoolP224t1 = versionOne.branch("6");
+    /** 1.3.36.3.3.2.8.1.7 */
     static final ASN1ObjectIdentifier brainpoolP256r1 = versionOne.branch("7");
+    /** 1.3.36.3.3.2.8.1.8 */
     static final ASN1ObjectIdentifier brainpoolP256t1 = versionOne.branch("8");
+    /** 1.3.36.3.3.2.8.1.9 */
     static final ASN1ObjectIdentifier brainpoolP320r1 = versionOne.branch("9");
+    /** 1.3.36.3.3.2.8.1.10 */
     static final ASN1ObjectIdentifier brainpoolP320t1 = versionOne.branch("10");
+    /** 1.3.36.3.3.2.8.1.11 */
     static final ASN1ObjectIdentifier brainpoolP384r1 = versionOne.branch("11");
+    /** 1.3.36.3.3.2.8.1.12 */
     static final ASN1ObjectIdentifier brainpoolP384t1 = versionOne.branch("12");
+    /** 1.3.36.3.3.2.8.1.13 */
     static final ASN1ObjectIdentifier brainpoolP512r1 = versionOne.branch("13");
+    /** 1.3.36.3.3.2.8.1.14 */
     static final ASN1ObjectIdentifier brainpoolP512t1 = versionOne.branch("14");
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
index 714a32c..6842182 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
@@ -1,6 +1,7 @@
 package org.bouncycastle.asn1.x500.style;
 
 import java.io.IOException;
+import java.util.Enumeration;
 import java.util.Hashtable;
 
 import org.bouncycastle.asn1.ASN1Encodable;
@@ -19,8 +20,6 @@
 public class BCStyle
     implements X500NameStyle
 {
-    public static final X500NameStyle INSTANCE = new BCStyle();
-
     /**
      * country code - StringType(SIZE(2))
      */
@@ -273,9 +272,18 @@
         DefaultLookUp.put("name", NAME);
     }
 
+    /**
+     * Singleton instance.
+     */
+    public static final X500NameStyle INSTANCE = new BCStyle();
+
+    protected final Hashtable defaultLookUp;
+    protected final Hashtable defaultSymbols;
+
     protected BCStyle()
     {
-
+        defaultSymbols = copyHashTable(DefaultSymbols);
+        defaultLookUp = copyHashTable(DefaultLookUp);
     }
     
     public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)
@@ -322,12 +330,12 @@
 
     public String[] oidToAttrNames(ASN1ObjectIdentifier oid)
     {
-        return IETFUtils.findAttrNamesForOID(oid, DefaultLookUp);
+        return IETFUtils.findAttrNamesForOID(oid, defaultLookUp);
     }
 
     public ASN1ObjectIdentifier attrNameToOID(String attrName)
     {
-        return IETFUtils.decodeAttrName(attrName, DefaultLookUp);
+        return IETFUtils.decodeAttrName(attrName, defaultLookUp);
     }
 
     public boolean areEqual(X500Name name1, X500Name name2)
@@ -451,9 +459,23 @@
                 buf.append(',');
             }
 
-            IETFUtils.appendRDN(buf, rdns[i], DefaultSymbols);
+            IETFUtils.appendRDN(buf, rdns[i], defaultSymbols);
         }
 
         return buf.toString();
     }
+
+    private static Hashtable copyHashTable(Hashtable paramsMap)
+    {
+        Hashtable newTable = new Hashtable();
+
+        Enumeration keys = paramsMap.keys();
+        while (keys.hasMoreElements())
+        {
+            Object key = keys.nextElement();
+            newTable.put(key, paramsMap.get(key));
+        }
+
+        return newTable;
+    }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
index c73107e..b4f1794 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
@@ -405,7 +405,7 @@
         int start = 0;
         if (vBuf.length() > 0)
         {
-            while (vBuf.charAt(start) == ' ')
+            while (vBuf.length() > start && vBuf.charAt(start) == ' ')
             {
                 vBuf.insert(start, "\\");
                 start += 2;
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
index 8486989..8c92257 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
@@ -1,6 +1,7 @@
 package org.bouncycastle.asn1.x500.style;
 
 import java.io.IOException;
+import java.util.Enumeration;
 import java.util.Hashtable;
 
 import org.bouncycastle.asn1.ASN1Encodable;
@@ -16,8 +17,6 @@
 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");
@@ -166,9 +165,18 @@
         // TODO: need to add correct matching for equality comparisons.
     }
 
+    /**
+     * Singleton instance.
+     */
+    public static final X500NameStyle INSTANCE = new RFC4519Style();
+
+    protected final Hashtable defaultLookUp;
+    protected final Hashtable defaultSymbols;
+
     protected RFC4519Style()
     {
-
+        defaultSymbols = copyHashTable(DefaultSymbols);
+        defaultLookUp = copyHashTable(DefaultLookUp);
     }
 
     public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)
@@ -211,12 +219,12 @@
 
     public String[] oidToAttrNames(ASN1ObjectIdentifier oid)
     {
-        return IETFUtils.findAttrNamesForOID(oid, DefaultLookUp);
+        return IETFUtils.findAttrNamesForOID(oid, defaultLookUp);
     }
 
     public ASN1ObjectIdentifier attrNameToOID(String attrName)
     {
-        return IETFUtils.decodeAttrName(attrName, DefaultLookUp);
+        return IETFUtils.decodeAttrName(attrName, defaultLookUp);
     }
 
     public boolean areEqual(X500Name name1, X500Name name2)
@@ -350,9 +358,23 @@
                 buf.append(',');
             }
 
-            IETFUtils.appendRDN(buf, rdns[i], DefaultSymbols);
+            IETFUtils.appendRDN(buf, rdns[i], defaultSymbols);
         }
 
         return buf.toString();
     }
+
+    private static Hashtable copyHashTable(Hashtable paramsMap)
+    {
+        Hashtable newTable = new Hashtable();
+
+        Enumeration keys = paramsMap.keys();
+        while (keys.hasMoreElements())
+        {
+            Object key = keys.nextElement();
+            newTable.put(key, paramsMap.get(key));
+        }
+
+        return newTable;
+    }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
index 92aa0f7..73fe7b4 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
@@ -41,7 +41,10 @@
         this.signatureAlgorithm = signatureAlgorithm;
         this.signatureValue = signatureValue;
     }
-    
+
+    /**
+     * @deprecated use getInstance() method.
+     */
     public AttributeCertificate(
         ASN1Sequence    seq)
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
index 7b9d450..ae539f4 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
@@ -13,7 +13,7 @@
 public class AttributeCertificateInfo
     extends ASN1Object
 {
-    private ASN1Integer              version;
+    private ASN1Integer             version;
     private Holder                  holder;
     private AttCertIssuer           issuer;
     private AlgorithmIdentifier     signature;
@@ -48,22 +48,33 @@
     private AttributeCertificateInfo(
         ASN1Sequence   seq)
     {
-        if (seq.size() < 7 || seq.size() > 9)
+        if (seq.size() < 6 || seq.size() > 9)
         {
             throw new IllegalArgumentException("Bad sequence size: " + seq.size());
         }
 
-        this.version = ASN1Integer.getInstance(seq.getObjectAt(0));
-        this.holder = Holder.getInstance(seq.getObjectAt(1));
-        this.issuer = AttCertIssuer.getInstance(seq.getObjectAt(2));
-        this.signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(3));
-        this.serialNumber = ASN1Integer.getInstance(seq.getObjectAt(4));
-        this.attrCertValidityPeriod = AttCertValidityPeriod.getInstance(seq.getObjectAt(5));
-        this.attributes = ASN1Sequence.getInstance(seq.getObjectAt(6));
-        
-        for (int i = 7; i < seq.size(); i++)
+        int start;
+        if (seq.getObjectAt(0) instanceof ASN1Integer)   // in version 1 certs version is DEFAULT  v1(0)
         {
-            ASN1Encodable    obj = (ASN1Encodable)seq.getObjectAt(i);
+            this.version = ASN1Integer.getInstance(seq.getObjectAt(0));
+            start = 1;
+        }
+        else
+        {
+            this.version = new ASN1Integer(0);
+            start = 0;
+        }
+
+        this.holder = Holder.getInstance(seq.getObjectAt(start));
+        this.issuer = AttCertIssuer.getInstance(seq.getObjectAt(start + 1));
+        this.signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(start + 2));
+        this.serialNumber = ASN1Integer.getInstance(seq.getObjectAt(start + 3));
+        this.attrCertValidityPeriod = AttCertValidityPeriod.getInstance(seq.getObjectAt(start + 4));
+        this.attributes = ASN1Sequence.getInstance(seq.getObjectAt(start + 5));
+        
+        for (int i = start + 6; i < seq.size(); i++)
+        {
+            ASN1Encodable    obj = seq.getObjectAt(i);
 
             if (obj instanceof DERBitString)
             {
@@ -143,7 +154,10 @@
     {
         ASN1EncodableVector  v = new ASN1EncodableVector();
 
-        v.add(version);
+        if (version.getValue().intValue() != 0)
+        {
+            v.add(version);
+        }
         v.add(holder);
         v.add(issuer);
         v.add(signature);
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
index 91a37ad..61d7d4a 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
@@ -31,6 +31,8 @@
     TBSCertList            tbsCertList;
     AlgorithmIdentifier    sigAlgId;
     DERBitString           sig;
+    boolean                isHashCodeSet = false;
+    int                    hashCodeValue;
 
     public static CertificateList getInstance(
         ASN1TaggedObject obj,
@@ -54,6 +56,10 @@
         return null;
     }
 
+    /**
+     * @deprecated use getInstance() method.
+     * @param seq
+     */
     public CertificateList(
         ASN1Sequence seq)
     {
@@ -124,4 +130,15 @@
 
         return new DERSequence(v);
     }
+
+    public int hashCode()
+    {
+        if (!isHashCodeSet)
+        {
+            hashCodeValue = super.hashCode();
+            isHashCodeSet = true;
+        }
+
+        return hashCodeValue;
+    }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
index dcc1b1f..84d21ca 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
@@ -25,6 +25,13 @@
     Hashtable     usageTable = new Hashtable();
     ASN1Sequence  seq;
 
+    /**
+     * Return an ExtendedKeyUsage from the passed in tagged object.
+     *
+     * @param obj the tagged object containing the ExtendedKeyUsage
+     * @param explicit true if the tagged object should be interpreted as explicitly tagged, false if implicit.
+     * @return the ExtendedKeyUsage contained.
+     */
     public static ExtendedKeyUsage getInstance(
         ASN1TaggedObject obj,
         boolean          explicit)
@@ -32,6 +39,12 @@
         return getInstance(ASN1Sequence.getInstance(obj, explicit));
     }
 
+    /**
+     * Return an ExtendedKeyUsage from the passed in object.
+     *
+     * @param obj an ExtendedKeyUsage, some form or encoding of one, or null.
+     * @return  an ExtendedKeyUsage object, or null if null is passed in.
+     */
     public static ExtendedKeyUsage getInstance(
         Object obj)
     {
@@ -47,11 +60,22 @@
         return null;
     }
 
+    /**
+     * Retrieve an ExtendedKeyUsage for a passed in Extensions object, if present.
+     *
+     * @param extensions the extensions object to be examined.
+     * @return  the ExtendedKeyUsage, null if the extension is not present.
+     */
     public static ExtendedKeyUsage fromExtensions(Extensions extensions)
     {
         return ExtendedKeyUsage.getInstance(extensions.getExtensionParsedValue(Extension.extendedKeyUsage));
     }
 
+    /**
+     * Base constructor, from a single KeyPurposeId.
+     *
+     * @param usage the keyPurposeId to be included.
+     */
     public ExtendedKeyUsage(
         KeyPurposeId  usage)
     {
@@ -78,6 +102,11 @@
         }
     }
 
+    /**
+     * Base constructor, from multiple KeyPurposeIds.
+     *
+     * @param usages an array of KeyPurposeIds.
+     */
     public ExtendedKeyUsage(
         KeyPurposeId[]  usages)
     {
@@ -103,7 +132,7 @@
 
         while (e.hasMoreElements())
         {
-            ASN1Primitive  o = (ASN1Primitive)e.nextElement();
+            KeyPurposeId  o = KeyPurposeId.getInstance(e.nextElement());
 
             v.add(o);
             this.usageTable.put(o, o);
@@ -112,6 +141,12 @@
         this.seq = new DERSequence(v);
     }
 
+    /**
+     * Return true if this ExtendedKeyUsage object contains the passed in keyPurposeId.
+     *
+     * @param keyPurposeId  the KeyPurposeId of interest.
+     * @return true if the keyPurposeId is present, false otherwise.
+     */
     public boolean hasKeyPurposeId(
         KeyPurposeId keyPurposeId)
     {
@@ -120,7 +155,7 @@
     
     /**
      * Returns all extended key usages.
-     * The returned vector contains DERObjectIdentifiers.
+     *
      * @return An array with all key purposes.
      */
     public KeyPurposeId[] getUsages()
@@ -135,11 +170,21 @@
         return temp;
     }
 
+    /**
+     * Return the number of KeyPurposeIds present in this ExtendedKeyUsage.
+     *
+     * @return the number of KeyPurposeIds
+     */
     public int size()
     {
         return usageTable.size();
     }
-    
+
+    /**
+     * Return the ASN.1 primitive form of this object.
+     *
+     * @return an ASN1Sequence.
+     */
     public ASN1Primitive toASN1Primitive()
     {
         return seq;
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java
index 6ae6e35..e854681 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java
@@ -31,9 +31,9 @@
  * 
  * <pre>
  *         subject CHOICE {
- *          baseCertificateID [0] IssuerSerial,
+ *          baseCertificateID [0] EXPLICIT IssuerSerial,
  *          -- associated with a Public Key Certificate
- *          subjectName [1] GeneralNames },
+ *          subjectName [1] EXPLICIT GeneralNames },
  *          -- associated with a name
  * </pre>
  */
@@ -79,10 +79,10 @@
         switch (tagObj.getTagNo())
         {
         case 0:
-            baseCertificateID = IssuerSerial.getInstance(tagObj, false);
+            baseCertificateID = IssuerSerial.getInstance(tagObj, true);
             break;
         case 1:
-            entityName = GeneralNames.getInstance(tagObj, false);
+            entityName = GeneralNames.getInstance(tagObj, true);
             break;
         default:
             throw new IllegalArgumentException("unknown tag in Holder");
@@ -234,11 +234,11 @@
         {
             if (entityName != null)
             {
-                return new DERTaggedObject(false, 1, entityName);
+                return new DERTaggedObject(true, 1, entityName);
             }
             else
             {
-                return new DERTaggedObject(false, 0, baseCertificateID);
+                return new DERTaggedObject(true, 0, baseCertificateID);
             }
         }
     }
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java
index 8d3036b..fefc939 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java
@@ -10,6 +10,7 @@
 import org.bouncycastle.asn1.ASN1TaggedObject;
 import org.bouncycastle.asn1.DERBitString;
 import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x500.X500Name;
 
 public class IssuerSerial
     extends ASN1Object
@@ -59,6 +60,13 @@
     }
 
     public IssuerSerial(
+        X500Name   issuer,
+        BigInteger serial)
+    {
+        this(new GeneralNames(new GeneralName(issuer)), new ASN1Integer(serial));
+    }
+
+    public IssuerSerial(
         GeneralNames    issuer,
         BigInteger serial)
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java
index 2943c0b..d4456b7 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java
@@ -74,6 +74,17 @@
         this.bitString = bitString;
     }
 
+    /**
+     * Return true if a given usage bit is set, false otherwise.
+     *
+     * @param usages combination of usage flags.
+     * @return true if all bits are set, false otherwise.
+     */
+    public boolean hasUsages(int usages)
+    {
+        return (bitString.intValue() & usages) == usages;
+    }
+
     public byte[] getBytes()
     {
         return bitString.getBytes();
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyConstraints.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyConstraints.java
new file mode 100644
index 0000000..aeb53f0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyConstraints.java
@@ -0,0 +1,106 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * PKIX RFC 5280
+ * <pre>
+ * id-ce-policyConstraints OBJECT IDENTIFIER ::=  { id-ce 36 }
+ *
+ * PolicyConstraints ::= SEQUENCE {
+ *      requireExplicitPolicy           [0] SkipCerts OPTIONAL,
+ *      inhibitPolicyMapping            [1] SkipCerts OPTIONAL }
+ *
+ * SkipCerts ::= INTEGER (0..MAX)
+ * </pre>
+ */
+public class PolicyConstraints
+    extends ASN1Object
+{
+    private BigInteger requireExplicitPolicyMapping;
+    private BigInteger inhibitPolicyMapping;
+
+    public PolicyConstraints(BigInteger requireExplicitPolicyMapping, BigInteger inhibitPolicyMapping)
+    {
+        this.requireExplicitPolicyMapping = requireExplicitPolicyMapping;
+        this.inhibitPolicyMapping = inhibitPolicyMapping;
+    }
+
+    private PolicyConstraints(ASN1Sequence seq)
+    {
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject to = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+
+            if (to.getTagNo() == 0)
+            {
+                requireExplicitPolicyMapping = ASN1Integer.getInstance(to, false).getValue();
+            }
+            else if (to.getTagNo() == 1)
+            {
+                inhibitPolicyMapping = ASN1Integer.getInstance(to, false).getValue();
+            }
+            else
+            {
+                throw new IllegalArgumentException("Unknown tag encountered.");
+            }
+        }
+    }
+
+    public static PolicyConstraints getInstance(
+        Object  obj)
+    {
+        if (obj instanceof PolicyConstraints)
+        {
+            return (PolicyConstraints)obj;
+        }
+
+        if (obj != null)
+        {
+            return new PolicyConstraints(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
+    }
+
+    public static PolicyConstraints fromExtensions(Extensions extensions)
+    {
+        return PolicyConstraints.getInstance(extensions.getExtensionParsedValue(Extension.policyConstraints));
+    }
+
+    public BigInteger getRequireExplicitPolicyMapping()
+    {
+        return requireExplicitPolicyMapping;
+    }
+
+    public BigInteger getInhibitPolicyMapping()
+    {
+        return inhibitPolicyMapping;
+    }
+
+    public ASN1Primitive toASN1Primitive()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        if (requireExplicitPolicyMapping != null)
+        {
+            v.add(new DERTaggedObject(0, new ASN1Integer(requireExplicitPolicyMapping)));
+        }
+
+        if (inhibitPolicyMapping != null)
+        {
+            v.add(new DERTaggedObject(1, new ASN1Integer(inhibitPolicyMapping)));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
index f020bcb..f29284d 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
@@ -10,6 +10,7 @@
 
 /**
  * an object for the elements in the X.509 V3 extension block.
+ * @deprecated use Extension
  */
 public class X509Extension
 {
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
index 9aed4e1..0c372f7 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
@@ -1242,49 +1242,47 @@
 
         buf.append('=');
 
-        int     index = buf.length();
-        int     start = index;
-
+        int start = buf.length();
         buf.append(value);
-
-        int     end = buf.length();
+        int end = buf.length();
 
         if (value.length() >= 2 && value.charAt(0) == '\\' && value.charAt(1) == '#')
         {
-            index += 2;   
-        }
-
-        while (index != end)
-        {
-            if ((buf.charAt(index) == ',')
-               || (buf.charAt(index) == '"')
-               || (buf.charAt(index) == '\\')
-               || (buf.charAt(index) == '+')
-               || (buf.charAt(index) == '=')
-               || (buf.charAt(index) == '<')
-               || (buf.charAt(index) == '>')
-               || (buf.charAt(index) == ';'))
-            {
-                buf.insert(index, "\\");
-                index++;
-                end++;
-            }
-
-            index++;
-        }
-
-        while (buf.charAt(start) == ' ')
-        {
-            buf.insert(start, "\\");
             start += 2;
         }
 
-        int endBuf = buf.length() - 1;
-
-        while (endBuf >= 0 && buf.charAt(endBuf) == ' ')
+        while (start < end && buf.charAt(start) == ' ')
         {
-            buf.insert(endBuf, '\\');
-            endBuf--;
+            buf.insert(start, "\\");
+            start += 2;
+            ++end;
+        }
+
+        while (--end > start && buf.charAt(end) == ' ')
+        {
+            buf.insert(end, '\\');
+        }
+
+        while (start <= end)
+        {
+            switch (buf.charAt(start))
+            {
+            case ',':
+            case '"':
+            case '\\':
+            case '+':
+            case '=':
+            case '<':
+            case '>':
+            case ';':
+                buf.insert(start, "\\");
+                start += 2;
+                ++end;
+                break;
+            default:
+                ++start;
+                break;
+            }
         }
     }
 
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
index ed4dd32..e1c7a54 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
@@ -4,64 +4,78 @@
 
 public interface X509ObjectIdentifiers
 {
-    //
-    // base id
-    //
-    static final String                 id                      = "2.5.4";
+    
+    /** Subject RDN components: commonName = 2.5.4.3 */
+    static final ASN1ObjectIdentifier    commonName              = new ASN1ObjectIdentifier("2.5.4.3");
+    /** Subject RDN components: countryName = 2.5.4.6 */
+    static final ASN1ObjectIdentifier    countryName             = new ASN1ObjectIdentifier("2.5.4.6");
+    /** Subject RDN components: localityName = 2.5.4.7 */
+    static final ASN1ObjectIdentifier    localityName            = new ASN1ObjectIdentifier("2.5.4.7");
+    /** Subject RDN components: stateOrProvinceName = 2.5.4.8 */
+    static final ASN1ObjectIdentifier    stateOrProvinceName     = new ASN1ObjectIdentifier("2.5.4.8");
+    /** Subject RDN components: organization = 2.5.4.10 */
+    static final ASN1ObjectIdentifier    organization            = new ASN1ObjectIdentifier("2.5.4.10");
+    /** Subject RDN components: organizationalUnitName = 2.5.4.11 */
+    static final ASN1ObjectIdentifier    organizationalUnitName  = new ASN1ObjectIdentifier("2.5.4.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");
-
+    /** Subject RDN components: telephone_number = 2.5.4.20 */
     static final ASN1ObjectIdentifier    id_at_telephoneNumber   = new ASN1ObjectIdentifier("2.5.4.20");
-    static final ASN1ObjectIdentifier    id_at_name              = new ASN1ObjectIdentifier(id + ".41");
+    /** Subject RDN components: name = 2.5.4.41 */
+    static final ASN1ObjectIdentifier    id_at_name              = new ASN1ObjectIdentifier("2.5.4.41");
 
-    // id-SHA1 OBJECT IDENTIFIER ::=    
-    //   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //
+    /**
+     * id-SHA1 OBJECT IDENTIFIER ::=    
+     *   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }
+     * <p>
+     * OID: 1.3.14.3.2.27
+     */
     static final ASN1ObjectIdentifier    id_SHA1                 = new ASN1ObjectIdentifier("1.3.14.3.2.26");
 
-    //
-    // ripemd160 OBJECT IDENTIFIER ::=
-    //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)}
-    //
+    /**
+     * ripemd160 OBJECT IDENTIFIER ::=
+     *      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)}
+     * <p>
+     * OID: 1.3.36.3.2.1
+     */
     static final ASN1ObjectIdentifier    ripemd160               = new ASN1ObjectIdentifier("1.3.36.3.2.1");
 
-    //
-    // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=
-    //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }
-    //
+    /**
+     * ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=
+     *      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }
+     * <p>
+     * OID: 1.3.36.3.3.1.2
+     */
     static final ASN1ObjectIdentifier    ripemd160WithRSAEncryption = new ASN1ObjectIdentifier("1.3.36.3.3.1.2");
 
 
+    /** OID: 2.5.8.1.1  */
     static final ASN1ObjectIdentifier    id_ea_rsa = new ASN1ObjectIdentifier("2.5.8.1.1");
     
-    // id-pkix
-    static final ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7");
+    /** id-pkix OID: 1.3.6.1.5.5.7
+     */
+    static final ASN1ObjectIdentifier  id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7");
 
-    //
-    // private internet extensions
-    //
-    static final ASN1ObjectIdentifier  id_pe = new ASN1ObjectIdentifier(id_pkix + ".1");
+    /**
+     * private internet extensions; OID = 1.3.6.1.5.5.7.1
+     */
+    static final ASN1ObjectIdentifier  id_pe   = id_pkix.branch("1");
 
-    //
-    // ISO ARC for standard certificate and CRL extensions
-    //
+    /**
+     * ISO ARC for standard certificate and CRL extensions
+     * <p>
+     * OID: 2.5.29
+     */
     static final ASN1ObjectIdentifier id_ce = new ASN1ObjectIdentifier("2.5.29");
 
-    //
-    // authority information access
-    //
-    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");
+    /** id-pkix OID:         1.3.6.1.5.5.7.48  */
+    static final ASN1ObjectIdentifier  id_ad           = id_pkix.branch("48");
+    /** id-ad-caIssuers OID: 1.3.6.1.5.5.7.48.2  */
+    static final ASN1ObjectIdentifier  id_ad_caIssuers = id_ad.branch("2");
+    /** id-ad-ocsp OID:      1.3.6.1.5.5.7.48.1  */
+    static final ASN1ObjectIdentifier  id_ad_ocsp      = id_ad.branch("1");
 
-    //
-    //    OID for ocsp and crl uri in AuthorityInformationAccess extension
-    //
+    /** OID for ocsp uri in AuthorityInformationAccess extension */
     static final ASN1ObjectIdentifier ocspAccessMethod = id_ad_ocsp;
-    static final ASN1ObjectIdentifier crlAccessMethod = id_ad_caIssuers;
+    /** OID for crl uri in AuthorityInformationAccess extension */
+    static final ASN1ObjectIdentifier crlAccessMethod  = id_ad_caIssuers;
 }
-
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java
new file mode 100644
index 0000000..fef664f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java
@@ -0,0 +1,107 @@
+package org.bouncycastle.asn1.x9;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+// END android-removed
+
+/**
+ * A general class that reads all X9.62 style EC curve tables.
+ */
+public class ECNamedCurveTable
+{
+    /**
+     * return a X9ECParameters object representing the passed in named
+     * curve. The routine returns null if the curve is not present.
+     *
+     * @param name the name of the curve requested
+     * @return an X9ECParameters object or null if the curve is not available.
+     */
+    public static X9ECParameters getByName(
+        String name)
+    {
+        X9ECParameters ecP = X962NamedCurves.getByName(name);
+
+        if (ecP == null)
+        {
+            ecP = SECNamedCurves.getByName(name);
+        }
+
+        // BEGIN android-removed
+        // if (ecP == null)
+        // {
+        //     ecP = TeleTrusTNamedCurves.getByName(name);
+        // }
+        // END android-removed
+
+        if (ecP == null)
+        {
+            ecP = NISTNamedCurves.getByName(name);
+        }
+
+        return ecP;
+    }
+
+    /**
+     * return a X9ECParameters object representing the passed in named
+     * curve.
+     *
+     * @param oid the object id of the curve requested
+     * @return an X9ECParameters object or null if the curve is not available.
+     */
+    public static X9ECParameters getByOID(
+        ASN1ObjectIdentifier oid)
+    {
+        X9ECParameters ecP = X962NamedCurves.getByOID(oid);
+
+        if (ecP == null)
+        {
+            ecP = SECNamedCurves.getByOID(oid);
+        }
+
+        // BEGIN android-removed
+        // if (ecP == null)
+        // {
+        //     ecP = TeleTrusTNamedCurves.getByOID(oid);
+        // }
+        // END android-removed
+
+        // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup
+
+        return ecP;
+    }
+
+    /**
+     * return an enumeration of the names of the available curves.
+     *
+     * @return an enumeration of the names of the available curves.
+     */
+    public static Enumeration getNames()
+    {
+        Vector v = new Vector();
+
+        addEnumeration(v, X962NamedCurves.getNames());
+        addEnumeration(v, SECNamedCurves.getNames());
+        addEnumeration(v, NISTNamedCurves.getNames());
+        // BEGIN android-removed
+        // 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/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
index e059089..60f9008 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
@@ -39,11 +39,21 @@
         }
 
         X9Curve     x9c = new X9Curve(
-                        new X9FieldID((ASN1Sequence)seq.getObjectAt(1)),
-                        (ASN1Sequence)seq.getObjectAt(2));
+                        X9FieldID.getInstance(seq.getObjectAt(1)),
+                        ASN1Sequence.getInstance(seq.getObjectAt(2)));
 
         this.curve = x9c.getCurve();
-        this.g = new X9ECPoint(curve, (ASN1OctetString)seq.getObjectAt(3)).getPoint();
+        Object p = seq.getObjectAt(3);
+
+        if (p instanceof X9ECPoint)
+        {
+            this.g = ((X9ECPoint)p).getPoint();
+        }
+        else
+        {
+            this.g = new X9ECPoint(curve, (ASN1OctetString)p).getPoint();
+        }
+
         this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue();
         this.seed = x9c.getSeed();
 
@@ -93,7 +103,7 @@
         byte[]      seed)
     {
         this.curve = curve;
-        this.g = g;
+        this.g = g.normalize();
         this.n = n;
         this.h = h;
         this.seed = seed;
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
index a4acb6e..cbb9116 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
@@ -18,7 +18,7 @@
     public X9ECPoint(
         ECPoint p)
     {
-        this.p = p;
+        this.p = p.normalize();
     }
 
     public X9ECPoint(
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
index 30598e2..a210352 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
@@ -71,11 +71,26 @@
         this.parameters = new DERSequence(fieldIdParams);
     }
 
-    public X9FieldID(
+    private X9FieldID(
         ASN1Sequence  seq)
     {
-        this.id = (ASN1ObjectIdentifier)seq.getObjectAt(0);
-        this.parameters = (ASN1Primitive)seq.getObjectAt(1);
+        this.id = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+        this.parameters = seq.getObjectAt(1).toASN1Primitive();
+    }
+
+    public static X9FieldID getInstance(Object obj)
+    {
+        if (obj instanceof X9FieldID)
+        {
+            return (X9FieldID)obj;
+        }
+
+        if (obj != null)
+        {
+            return new X9FieldID(ASN1Sequence.getInstance(obj));
+        }
+
+        return null;
     }
 
     public ASN1ObjectIdentifier getIdentifier()
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
index f005cfa..eabf90e 100644
--- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
@@ -2,109 +2,172 @@
 
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
+/**
+ *
+ * X9.62
+ * <pre>
+ * ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ *                                    us(840) ansi-x962(10045) }
+ * </pre>
+ */
 public interface X9ObjectIdentifiers
 {
-    //
-    // X9.62
-    //
-    // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
-    //            us(840) ansi-x962(10045) }
-    //
+    /** Base OID: 1.2.840.10045 */
     static final ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045");
+
+    /** OID: 1.2.840.10045.1 */
     static final ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1");
 
+    /** OID: 1.2.840.10045.1.1 */
     static final ASN1ObjectIdentifier prime_field = id_fieldType.branch("1");
 
+    /** OID: 1.2.840.10045.1.2 */
     static final ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2");
 
+    /** OID: 1.2.840.10045.1.2.3.1 */
     static final ASN1ObjectIdentifier gnBasis = characteristic_two_field.branch("3.1");
 
+    /** OID: 1.2.840.10045.1.2.3.2 */
     static final ASN1ObjectIdentifier tpBasis = characteristic_two_field.branch("3.2");
 
+    /** OID: 1.2.840.10045.1.2.3.3 */
     static final ASN1ObjectIdentifier ppBasis = characteristic_two_field.branch("3.3");
 
+    /** OID: 1.2.840.10045.4 */
     static final ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4");
 
-    static final ASN1ObjectIdentifier ecdsa_with_SHA1 = new ASN1ObjectIdentifier(id_ecSigType + ".1");
+    /** OID: 1.2.840.10045.4.1 */
+    static final ASN1ObjectIdentifier ecdsa_with_SHA1 = id_ecSigType.branch("1");
 
+    /** OID: 1.2.840.10045.2 */
     static final ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2");
 
+    /** OID: 1.2.840.10045.2.1 */
     static final ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1");
 
+    /** OID: 1.2.840.10045.4.3 */
     static final ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3");
 
+    /** OID: 1.2.840.10045.4.3.1 */
     static final ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1");
 
+    /** OID: 1.2.840.10045.4.3.2 */
     static final ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2");
 
+    /** OID: 1.2.840.10045.4.3.3 */
     static final ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3");
 
+    /** OID: 1.2.840.10045.4.3.4 */
     static final ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4");
 
-    //
-    // named curves
-    //
+    /**
+     * Named curves base
+     * <p>
+     * OID: 1.2.840.10045.1
+     */
     static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3");
 
-    //
-    // Two Curves
-    //
+    /**
+     * Two Curves
+     * <p>
+     * OID: 1.2.840.10045.1.0
+     */
     static final ASN1ObjectIdentifier  cTwoCurve = ellipticCurve.branch("0");
 
+    /** Two Curve c2pnb163v1, OID: 1.2.840.10045.1.0.1 */
     static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1");
+    /** Two Curve c2pnb163v2, OID: 1.2.840.10045.1.0.2 */
     static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2");
+    /** Two Curve c2pnb163v3, OID: 1.2.840.10045.1.0.3 */
     static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3");
+    /** Two Curve c2pnb176w1, OID: 1.2.840.10045.1.0.4 */
     static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4");
+    /** Two Curve c2tnb191v1, OID: 1.2.840.10045.1.0.5 */
     static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5");
+    /** Two Curve c2tnb191v2, OID: 1.2.840.10045.1.0.6 */
     static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6");
+    /** Two Curve c2tnb191v3, OID: 1.2.840.10045.1.0.7 */
     static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7");
+    /** Two Curve c2onb191v4, OID: 1.2.840.10045.1.0.8 */
     static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8");
+    /** Two Curve c2onb191v5, OID: 1.2.840.10045.1.0.9 */
     static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9");
+    /** Two Curve c2pnb208w1, OID: 1.2.840.10045.1.0.10 */
     static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10");
+    /** Two Curve c2tnb239v1, OID: 1.2.840.10045.1.0.11 */
     static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11");
+    /** Two Curve c2tnb239v2, OID: 1.2.840.10045.1.0.12 */
     static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12");
+    /** Two Curve c2tnb239v3, OID: 1.2.840.10045.1.0.13 */
     static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13");
+    /** Two Curve c2onb239v4, OID: 1.2.840.10045.1.0.14 */
     static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14");
+    /** Two Curve c2onb239v5, OID: 1.2.840.10045.1.0.15 */
     static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15");
+    /** Two Curve c2pnb272w1, OID: 1.2.840.10045.1.0.16 */
     static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16");
+    /** Two Curve c2pnb304w1, OID: 1.2.840.10045.1.0.17 */
     static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17");
+    /** Two Curve c2tnb359v1, OID: 1.2.840.10045.1.0.18 */
     static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18");
+    /** Two Curve c2pnb368w1, OID: 1.2.840.10045.1.0.19 */
     static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19");
+    /** Two Curve c2tnb431r1, OID: 1.2.840.10045.1.0.20 */
     static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20");
 
-    //
-    // Prime
-    //
+    /**
+     * Prime Curves
+     * <p>
+     * OID: 1.2.840.10045.1.1
+     */
     static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1");
 
+    /** Prime Curve prime192v1, OID: 1.2.840.10045.1.1.1 */
     static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1");
+    /** Prime Curve prime192v2, OID: 1.2.840.10045.1.1.2 */
     static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2");
+    /** Prime Curve prime192v3, OID: 1.2.840.10045.1.1.3 */
     static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3");
+    /** Prime Curve prime239v1, OID: 1.2.840.10045.1.1.4 */
     static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4");
+    /** Prime Curve prime239v2, OID: 1.2.840.10045.1.1.5 */
     static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5");
+    /** Prime Curve prime239v3, OID: 1.2.840.10045.1.1.6 */
     static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6");
+    /** Prime Curve prime256v1, OID: 1.2.840.10045.1.1.7 */
     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 }
+    /**
+     * DSA
+     * <pre>
+     * dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+     *                                         us(840) ansi-x957(10040) number-type(4) 1 }
+     * </pre>
+     * Base OID: 1.2.840.10040.4.1
+     */
     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 }
+     * <pre>
+     * id-dsa-with-sha1 OBJECT IDENTIFIER ::= {
+     *     iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 }
+     * </pre>
+     * OID: 1.2.840.10040.4.3
      */
-    public static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3");
+    static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3");
 
     /**
-     * X9.63
+     * X9.63 - Signature Specification
+     * <p>
+     * Base OID: 1.3.133.16.840.63.0
      */
-    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");
+    static final ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0");
+    /** OID: 1.3.133.16.840.63.0.2 */
+    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme      = x9_63_scheme.branch("2");
+    /** OID: 1.3.133.16.840.63.0.3 */
+    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3");
+    /** OID: 1.3.133.16.840.63.0.16 */
+    static final ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme           = x9_63_scheme.branch("16");
 
     /**
      * X9.42
@@ -112,21 +175,33 @@
 
     static final ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046");
 
-    //
-    // Diffie-Hellman
-    //
-    // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
-    //            us(840) ansi-x942(10046) number-type(2) 1 }
-    //
-    public static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1");
+    /**
+     * Diffie-Hellman
+     * <pre>
+     * dhpublicnumber OBJECT IDENTIFIER ::= {
+     *    iso(1) member-body(2)  us(840) ansi-x942(10046) number-type(2) 1
+     * }
+     * </pre>
+     * OID: 1.2.840.10046.2.1
+     */
+    static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1");
 
-    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");
+    /** X9.42 schemas base OID: 1.2.840.10046.3 */
+    static final ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3");
+    /** X9.42 dhStatic OID: 1.2.840.10046.3.1 */
+    static final ASN1ObjectIdentifier dhStatic        = x9_42_schemes.branch("1");
+    /** X9.42 dhEphem OID: 1.2.840.10046.3.2 */
+    static final ASN1ObjectIdentifier dhEphem         = x9_42_schemes.branch("2");
+    /** X9.42 dhOneFlow OID: 1.2.840.10046.3.3 */
+    static final ASN1ObjectIdentifier dhOneFlow       = x9_42_schemes.branch("3");
+    /** X9.42 dhHybrid1 OID: 1.2.840.10046.3.4 */
+    static final ASN1ObjectIdentifier dhHybrid1       = x9_42_schemes.branch("4");
+    /** X9.42 dhHybrid2 OID: 1.2.840.10046.3.5 */
+    static final ASN1ObjectIdentifier dhHybrid2       = x9_42_schemes.branch("5");
+    /** X9.42 dhHybridOneFlow OID: 1.2.840.10046.3.6 */
+    static final ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6");
+    /** X9.42 MQV2 OID: 1.2.840.10046.3.7 */
+    static final ASN1ObjectIdentifier mqv2            = x9_42_schemes.branch("7");
+    /** X9.42 MQV1 OID: 1.2.840.10046.3.8 */
+    static final ASN1ObjectIdentifier mqv1            = x9_42_schemes.branch("8");
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
index bdb694d..dd056ac 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
@@ -54,7 +54,7 @@
         }
         else
         {
-            partialBlockOkay = (idx > 0 && (name.startsWith("CFB", idx) || name.startsWith("OFB", idx) || name.startsWith("OpenPGP", idx) || name.startsWith("SIC", idx) || name.startsWith("GCTR", idx)));
+            partialBlockOkay = (idx > 0 && (name.startsWith("CFB", idx) || name.startsWith("GCFB", idx) ||name.startsWith("OFB", idx) || name.startsWith("OpenPGP", idx) || name.startsWith("SIC", idx) || name.startsWith("GCTR", idx)));
         }
     }
 
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java b/bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java
index ef6e29e..0e2b4b0 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java
@@ -7,11 +7,6 @@
 {
     public void init(DerivationParameters param);
 
-    /**
-     * return the message digest used as the basis for the function
-     */
-    public Digest getDigest();
-
     public int generateBytes(byte[] out, int outOff, int len)
         throws DataLengthException, IllegalArgumentException;
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
index 59944e0..a491b9d 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
@@ -42,10 +42,13 @@
         CipherParameters pubKey)
     {
         ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey;
-        ECPoint P = pub.getQ().multiply(key.getD());
+        ECPoint P = pub.getQ().multiply(key.getD()).normalize();
 
-        // if (p.isInfinity()) throw new RuntimeException("d*Q == infinity");
+        if (P.isInfinity())
+        {
+            throw new IllegalStateException("Infinity is not a valid agreement value for ECDH");
+        }
 
-        return P.getX().toBigInteger();
+        return P.getAffineXCoord().toBigInteger();
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactory.java
index b7bac28..cab9ca6 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactory.java
@@ -69,6 +69,10 @@
         return FACTORY.getSHA1();
     }
 
+    public static Digest getSHA224() {
+        return FACTORY.getSHA224();
+    }
+
     public static Digest getSHA256() {
         return FACTORY.getSHA256();
     }
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java
index 47d3852..5868046 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java
@@ -25,6 +25,9 @@
     public Digest getSHA1() {
         return new SHA1Digest();
     }
+    public Digest getSHA224() {
+        return new SHA224Digest();
+    }
     public Digest getSHA256() {
         return new SHA256Digest();
     }
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java
index e2e020b..9ac224e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java
@@ -21,6 +21,7 @@
 interface AndroidDigestFactoryInterface {
     public Digest getMD5();
     public Digest getSHA1();
+    public Digest getSHA224();
     public Digest getSHA256();
     public Digest getSHA384();
     public Digest getSHA512();
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java
index cd07bd9..908f485 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java
@@ -25,6 +25,9 @@
     public Digest getSHA1() {
         return new OpenSSLDigest.SHA1();
     }
+    public Digest getSHA224() {
+        return new OpenSSLDigest.SHA224();
+    }
     public Digest getSHA256() {
         return new OpenSSLDigest.SHA256();
     }
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java
index 07b4e50..37df370 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java
@@ -136,6 +136,13 @@
         public SHA1() { super("SHA-1", EVP_MD, SIZE, BLOCK_SIZE); }
     }
 
+    public static class SHA224 extends OpenSSLDigest {
+        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha224");
+        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
+        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
+        public SHA224() { super("SHA-224", EVP_MD, SIZE, BLOCK_SIZE); }
+    }
+
     public static class SHA256 extends OpenSSLDigest {
         private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256");
         private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
new file mode 100644
index 0000000..d430321
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
@@ -0,0 +1,311 @@
+package org.bouncycastle.crypto.digests;
+
+
+import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.util.Memoable;
+
+
+/**
+ * SHA-224 as described in RFC 3874
+ * <pre>
+ *         block  word  digest
+ * SHA-1   512    32    160
+ * SHA-224 512    32    224
+ * SHA-256 512    32    256
+ * SHA-384 1024   64    384
+ * SHA-512 1024   64    512
+ * </pre>
+ */
+public class SHA224Digest
+    extends GeneralDigest
+{
+    private static final int    DIGEST_LENGTH = 28;
+
+    private int     H1, H2, H3, H4, H5, H6, H7, H8;
+
+    private int[]   X = new int[64];
+    private int     xOff;
+
+    /**
+     * Standard constructor
+     */
+    public SHA224Digest()
+    {
+        reset();
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public SHA224Digest(SHA224Digest t)
+    {
+        super(t);
+
+        doCopy(t);
+    }
+
+    private void doCopy(SHA224Digest t)
+    {
+        super.copyIn(t);
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+        H5 = t.H5;
+        H6 = t.H6;
+        H7 = t.H7;
+        H8 = t.H8;
+
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+    }
+
+    public String getAlgorithmName()
+    {
+        return "SHA-224";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        // Note: Inlined for performance
+//        X[xOff] = Pack.bigEndianToInt(in, inOff);
+        int n = in[  inOff] << 24;
+        n |= (in[++inOff] & 0xff) << 16;
+        n |= (in[++inOff] & 0xff) << 8;
+        n |= (in[++inOff] & 0xff);
+        X[xOff] = n;
+
+        if (++xOff == 16)
+        {
+            processBlock();
+        }
+    }
+
+    protected void processLength(
+        long    bitLength)
+    {
+        if (xOff > 14)
+        {
+            processBlock();
+        }
+
+        X[14] = (int)(bitLength >>> 32);
+        X[15] = (int)(bitLength & 0xffffffff);
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        Pack.intToBigEndian(H1, out, outOff);
+        Pack.intToBigEndian(H2, out, outOff + 4);
+        Pack.intToBigEndian(H3, out, outOff + 8);
+        Pack.intToBigEndian(H4, out, outOff + 12);
+        Pack.intToBigEndian(H5, out, outOff + 16);
+        Pack.intToBigEndian(H6, out, outOff + 20);
+        Pack.intToBigEndian(H7, out, outOff + 24);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables
+     */
+    public void reset()
+    {
+        super.reset();
+
+        /* SHA-224 initial hash value
+         */
+
+        H1 = 0xc1059ed8;
+        H2 = 0x367cd507;
+        H3 = 0x3070dd17;
+        H4 = 0xf70e5939;
+        H5 = 0xffc00b31;
+        H6 = 0x68581511;
+        H7 = 0x64f98fa7;
+        H8 = 0xbefa4fa4;
+
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    protected void processBlock()
+    {
+        //
+        // expand 16 word block into 64 word blocks.
+        //
+        for (int t = 16; t <= 63; t++)
+        {
+            X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16];
+        }
+
+        //
+        // set up working variables.
+        //
+        int     a = H1;
+        int     b = H2;
+        int     c = H3;
+        int     d = H4;
+        int     e = H5;
+        int     f = H6;
+        int     g = H7;
+        int     h = H8;
+
+
+        int t = 0;     
+        for(int i = 0; i < 8; i ++)
+        {
+            // t = 8 * i
+            h += Sum1(e) + Ch(e, f, g) + K[t] + X[t];
+            d += h;
+            h += Sum0(a) + Maj(a, b, c);
+            ++t;
+
+            // t = 8 * i + 1
+            g += Sum1(d) + Ch(d, e, f) + K[t] + X[t];
+            c += g;
+            g += Sum0(h) + Maj(h, a, b);
+            ++t;
+
+            // t = 8 * i + 2
+            f += Sum1(c) + Ch(c, d, e) + K[t] + X[t];
+            b += f;
+            f += Sum0(g) + Maj(g, h, a);
+            ++t;
+
+            // t = 8 * i + 3
+            e += Sum1(b) + Ch(b, c, d) + K[t] + X[t];
+            a += e;
+            e += Sum0(f) + Maj(f, g, h);
+            ++t;
+
+            // t = 8 * i + 4
+            d += Sum1(a) + Ch(a, b, c) + K[t] + X[t];
+            h += d;
+            d += Sum0(e) + Maj(e, f, g);
+            ++t;
+
+            // t = 8 * i + 5
+            c += Sum1(h) + Ch(h, a, b) + K[t] + X[t];
+            g += c;
+            c += Sum0(d) + Maj(d, e, f);
+            ++t;
+
+            // t = 8 * i + 6
+            b += Sum1(g) + Ch(g, h, a) + K[t] + X[t];
+            f += b;
+            b += Sum0(c) + Maj(c, d, e);
+            ++t;
+
+            // t = 8 * i + 7
+            a += Sum1(f) + Ch(f, g, h) + K[t] + X[t];
+            e += a;
+            a += Sum0(b) + Maj(b, c, d);
+            ++t;
+        }
+
+        H1 += a;
+        H2 += b;
+        H3 += c;
+        H4 += d;
+        H5 += e;
+        H6 += f;
+        H7 += g;
+        H8 += h;
+
+        //
+        // reset the offset and clean out the word buffer.
+        //
+        xOff = 0;
+        for (int i = 0; i < 16; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    /* SHA-224 functions */
+    private int Ch(
+        int    x,
+        int    y,
+        int    z)
+    {
+        return ((x & y) ^ ((~x) & z));
+    }
+
+    private int Maj(
+        int    x,
+        int    y,
+        int    z)
+    {
+        return ((x & y) ^ (x & z) ^ (y & z));
+    }
+
+    private int Sum0(
+        int    x)
+    {
+        return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10));
+    }
+
+    private int Sum1(
+        int    x)
+    {
+        return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7));
+    }
+
+    private int Theta0(
+        int    x)
+    {
+        return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
+    }
+
+    private int Theta1(
+        int    x)
+    {
+        return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10);
+    }
+
+    /* SHA-224 Constants
+     * (represent the first 32 bits of the fractional parts of the
+     * cube roots of the first sixty-four prime numbers)
+     */
+    static final int K[] = {
+        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+    };
+
+    public Memoable copy()
+    {
+        return new SHA224Digest(this);
+    }
+
+    public void reset(Memoable other)
+    {
+        SHA224Digest d = (SHA224Digest)other;
+
+        doCopy(d);
+    }
+}
+
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java
index 540bd25..cfd86fb 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java
@@ -85,7 +85,7 @@
         byte[]  buf = new byte[8 + iv.length];
 
         System.arraycopy(iv, 0, block, 0, iv.length);
-        System.arraycopy(in, 0, block, iv.length, inLen);
+        System.arraycopy(in, inOff, block, iv.length, inLen);
 
         engine.init(true, param);
 
@@ -137,8 +137,8 @@
         byte[]  a = new byte[iv.length];
         byte[]  buf = new byte[8 + iv.length];
 
-        System.arraycopy(in, 0, a, 0, iv.length);
-        System.arraycopy(in, iv.length, block, 0, inLen - iv.length);
+        System.arraycopy(in, inOff, a, 0, iv.length);
+        System.arraycopy(in, inOff + iv.length, block, 0, inLen - iv.length);
 
         engine.init(false, param);
 
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java
index e7fb943..c9765bf 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java
@@ -1,5 +1,8 @@
 package org.bouncycastle.crypto.engines;
 
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
 import org.bouncycastle.crypto.AsymmetricBlockCipher;
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.DataLengthException;
@@ -8,16 +11,13 @@
 import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
 import org.bouncycastle.util.BigIntegers;
 
-import java.math.BigInteger;
-import java.security.SecureRandom;
-
 /**
  * this does your basic RSA algorithm with blinding
  */
 public class RSABlindedEngine
     implements AsymmetricBlockCipher
 {
-    private static BigInteger ONE = BigInteger.valueOf(1);
+    private static final BigInteger ONE = BigInteger.valueOf(1);
 
     private RSACoreEngine    core = new RSACoreEngine();
     private RSAKeyParameters key;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
index 50baa4d..d70ee8f 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
@@ -232,10 +232,10 @@
         int seedlen = N;
         byte[] seed = new byte[seedlen / 8];
 
-// 3. n = ceiling(L ⁄ outlen) – 1.
+// 3. n = ceiling(L / outlen) - 1.
         int n = (L - 1) / outlen;
 
-// 4. b = L – 1 – (n ∗ outlen).
+// 4. b = L - 1 - (n * outlen).
         int b = (L - 1) % outlen;
 
         byte[] output = new byte[d.getDigestSize()];
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
index d77bd74..d5f5fc8 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
@@ -26,6 +26,11 @@
 
         this.random = ecP.getRandom();
         this.params = ecP.getDomainParameters();
+
+        if (this.random == null)
+        {
+            this.random = new SecureRandom();
+        }
     }
 
     /**
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
index 316de64..082a1c8 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
@@ -62,7 +62,7 @@
         hMac.doFinal(state, 0);
 
         System.arraycopy(state, 0, out, outOff, state.length);
-        
+
         for (int count = 1; count < c; count++)
         {
             hMac.update(state, 0, state.length);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
deleted file mode 100644
index bb09a76..0000000
--- a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
+++ /dev/null
@@ -1,244 +0,0 @@
-package org.bouncycastle.crypto.io;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.bouncycastle.crypto.BufferedBlockCipher;
-import org.bouncycastle.crypto.StreamCipher;
-
-/**
- * A CipherInputStream is composed of an InputStream and a BufferedBlockCipher so
- * that read() methods return data that are read in from the
- * underlying InputStream but have been additionally processed by the
- * Cipher.  The Cipher must be fully initialized before being used by
- * a CipherInputStream.
- * <p>
- * For example, if the Cipher is initialized for decryption, the
- * CipherInputStream will attempt to read in data and decrypt them,
- * before returning the decrypted data.
- */
-public class CipherInputStream
-    extends FilterInputStream
-{
-    private BufferedBlockCipher bufferedBlockCipher;
-    private StreamCipher streamCipher;
-
-    private byte[] buf;
-    private byte[] inBuf;
-
-    private int bufOff;
-    private int maxBuf;
-    private boolean finalized;
-
-    private static final int INPUT_BUF_SIZE = 2048;
-
-    /**
-     * Constructs a CipherInputStream from an InputStream and a
-     * BufferedBlockCipher.
-     */
-    public CipherInputStream(
-        InputStream is,
-        BufferedBlockCipher cipher)
-    {
-        super(is);
-
-        this.bufferedBlockCipher = cipher;
-
-        buf = new byte[cipher.getOutputSize(INPUT_BUF_SIZE)];
-        inBuf = new byte[INPUT_BUF_SIZE];
-    }
-
-    public CipherInputStream(
-        InputStream is,
-        StreamCipher cipher)
-    {
-        super(is);
-
-        this.streamCipher = cipher;
-
-        buf = new byte[INPUT_BUF_SIZE];
-        inBuf = new byte[INPUT_BUF_SIZE];
-    }
-
-    /**
-     * grab the next chunk of input from the underlying input stream
-     */
-    private int nextChunk()
-        throws IOException
-    {
-        int available = super.available();
-
-        // must always try to read 1 byte!
-        // some buggy InputStreams return < 0!
-        if (available <= 0)
-        {
-            available = 1;
-        }
-
-        if (available > inBuf.length)
-        {
-            available = super.read(inBuf, 0, inBuf.length);
-        }
-        else
-        {
-            available = super.read(inBuf, 0, available);
-        }
-
-        if (available < 0)
-        {
-            if (finalized)
-            {
-                return -1;
-            }
-
-            try
-            {
-                if (bufferedBlockCipher != null)
-                {
-                    maxBuf = bufferedBlockCipher.doFinal(buf, 0);
-                }
-                else
-                {
-                    maxBuf = 0; // a stream cipher
-                }
-            }
-            catch (Exception e)
-            {
-                throw new IOException("error processing stream: " + e.toString());
-            }
-
-            bufOff = 0;
-
-            finalized = true;
-
-            if (bufOff == maxBuf)
-            {
-                return -1;
-            }
-        }
-        else
-        {
-            bufOff = 0;
-
-            try
-            {
-                if (bufferedBlockCipher != null)
-                {
-                    maxBuf = bufferedBlockCipher.processBytes(inBuf, 0, available, buf, 0);
-                }
-                else
-                {
-                    streamCipher.processBytes(inBuf, 0, available, buf, 0);
-                    maxBuf = available;
-                }
-            }
-            catch (Exception e)
-            {
-                throw new IOException("error processing stream: " + e.toString());
-            }
-
-            if (maxBuf == 0)    // not enough bytes read for first block...
-            {
-                return nextChunk();
-            }
-        }
-
-        return maxBuf;
-    }
-
-    public int read()
-        throws IOException
-    {
-        if (bufOff == maxBuf)
-        {
-            if (nextChunk() < 0)
-            {
-                return -1;
-            }
-        }
-
-        return buf[bufOff++] & 0xff;
-    }
-
-    public int read(
-        byte[] b)
-        throws IOException
-    {
-        return read(b, 0, b.length);
-    }
-
-    public int read(
-        byte[] b,
-        int off,
-        int len)
-        throws IOException
-    {
-        if (bufOff == maxBuf)
-        {
-            if (nextChunk() < 0)
-            {
-                return -1;
-            }
-        }
-
-        int available = maxBuf - bufOff;
-
-        if (len > available)
-        {
-            System.arraycopy(buf, bufOff, b, off, available);
-            bufOff = maxBuf;
-
-            return available;
-        }
-        else
-        {
-            System.arraycopy(buf, bufOff, b, off, len);
-            bufOff += len;
-
-            return len;
-        }
-    }
-
-    public long skip(
-        long n)
-        throws IOException
-    {
-        if (n <= 0)
-        {
-            return 0;
-        }
-
-        int available = maxBuf - bufOff;
-
-        if (n > available)
-        {
-            bufOff = maxBuf;
-
-            return available;
-        }
-        else
-        {
-            bufOff += (int)n;
-
-            return (int)n;
-        }
-    }
-
-    public int available()
-        throws IOException
-    {
-        return maxBuf - bufOff;
-    }
-
-    public void close()
-        throws IOException
-    {
-        super.close();
-    }
-
-    public boolean markSupported()
-    {
-        return false;
-    }
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java
deleted file mode 100644
index 17a7b6d..0000000
--- a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java
+++ /dev/null
@@ -1,188 +0,0 @@
-package org.bouncycastle.crypto.io;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.bouncycastle.crypto.BufferedBlockCipher;
-import org.bouncycastle.crypto.StreamCipher;
-
-public class CipherOutputStream
-    extends FilterOutputStream
-{
-    private BufferedBlockCipher bufferedBlockCipher;
-    private StreamCipher streamCipher;
-
-    private byte[] oneByte = new byte[1];
-    private byte[] buf;
-
-    /**
-     * Constructs a CipherOutputStream from an OutputStream and a
-     * BufferedBlockCipher.
-     */
-    public CipherOutputStream(
-        OutputStream os,
-        BufferedBlockCipher cipher)
-    {
-        super(os);
-        this.bufferedBlockCipher = cipher;
-        this.buf = new byte[cipher.getBlockSize()];
-    }
-
-    /**
-     * Constructs a CipherOutputStream from an OutputStream and a
-     * BufferedBlockCipher.
-     */
-    public CipherOutputStream(
-        OutputStream os,
-        StreamCipher cipher)
-    {
-        super(os);
-        this.streamCipher = cipher;
-    }
-
-    /**
-     * Writes the specified byte to this output stream.
-     *
-     * @param b the <code>byte</code>.
-     * @exception java.io.IOException if an I/O error occurs.
-     */
-    public void write(
-        int b)
-        throws IOException
-    {
-        oneByte[0] = (byte)b;
-
-        if (bufferedBlockCipher != null)
-        {
-            int len = bufferedBlockCipher.processBytes(oneByte, 0, 1, buf, 0);
-
-            if (len != 0)
-            {
-                out.write(buf, 0, len);
-            }
-        }
-        else
-        {
-            out.write(streamCipher.returnByte((byte)b));
-        }
-    }
-
-    /**
-     * Writes <code>b.length</code> bytes from the specified byte array
-     * to this output stream.
-     * <p>
-     * The <code>write</code> method of
-     * <code>CipherOutputStream</code> calls the <code>write</code>
-     * method of three arguments with the three arguments
-     * <code>b</code>, <code>0</code>, and <code>b.length</code>.
-     *
-     * @param b the data.
-     * @exception java.io.IOException if an I/O error occurs.
-     * @see #write(byte[], int, int)
-     */
-    public void write(
-        byte[] b)
-        throws IOException
-    {
-        write(b, 0, b.length);
-    }
-
-    /**
-     * Writes <code>len</code> bytes from the specified byte array
-     * starting at offset <code>off</code> to this output stream.
-     *
-     * @param b the data.
-     * @param off the start offset in the data.
-     * @param len the number of bytes to write.
-     * @exception java.io.IOException if an I/O error occurs.
-     */
-    public void write(
-        byte[] b,
-        int off,
-        int len)
-        throws IOException
-    {
-        if (bufferedBlockCipher != null)
-        {
-            byte[] buf = new byte[bufferedBlockCipher.getOutputSize(len)];
-
-            int outLen = bufferedBlockCipher.processBytes(b, off, len, buf, 0);
-
-            if (outLen != 0)
-            {
-                out.write(buf, 0, outLen);
-            }
-        }
-        else
-        {
-            byte[] buf = new byte[len];
-
-            streamCipher.processBytes(b, off, len, buf, 0);
-
-            out.write(buf, 0, len);
-        }
-    }
-
-    /**
-     * Flushes this output stream by forcing any buffered output bytes
-     * that have already been processed by the encapsulated cipher object
-     * to be written out.
-     *
-     * <p>
-     * Any bytes buffered by the encapsulated cipher
-     * and waiting to be processed by it will not be written out. For example,
-     * if the encapsulated cipher is a block cipher, and the total number of
-     * bytes written using one of the <code>write</code> methods is less than
-     * the cipher's block size, no bytes will be written out.
-     *
-     * @exception java.io.IOException if an I/O error occurs.
-     */
-    public void flush()
-        throws IOException
-    {
-        super.flush();
-    }
-
-    /**
-     * Closes this output stream and releases any system resources
-     * associated with this stream.
-     * <p>
-     * This method invokes the <code>doFinal</code> method of the encapsulated
-     * cipher object, which causes any bytes buffered by the encapsulated
-     * cipher to be processed. The result is written out by calling the
-     * <code>flush</code> method of this output stream.
-     * <p>
-     * This method resets the encapsulated cipher object to its initial state
-     * and calls the <code>close</code> method of the underlying output
-     * stream.
-     *
-     * @exception java.io.IOException if an I/O error occurs.
-     */
-    public void close()
-        throws IOException
-    {
-        try
-        {
-            if (bufferedBlockCipher != null)
-            {
-                byte[] buf = new byte[bufferedBlockCipher.getOutputSize(0)];
-
-                int outLen = bufferedBlockCipher.doFinal(buf, 0);
-
-                if (outLen != 0)
-                {
-                    out.write(buf, 0, outLen);
-                }
-            }
-        }
-        catch (Exception e)
-        {
-            throw new IOException("Error closing stream: " + e.toString());
-        }
-
-        flush();
-
-        super.close();
-    }
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java b/bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java
index c70a981..600a317 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java
@@ -50,9 +50,7 @@
         // END android-removed
         
         blockLengths.put("SHA-1", Integers.valueOf(64));
-        // BEGIN android-removed
-        // blockLengths.put("SHA-224", Integers.valueOf(64));
-        // END android-removed
+        blockLengths.put("SHA-224", Integers.valueOf(64));
         blockLengths.put("SHA-256", Integers.valueOf(64));
         blockLengths.put("SHA-384", Integers.valueOf(128));
         blockLengths.put("SHA-512", Integers.valueOf(128));
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
index 9a6e2e0..fef51fd 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
@@ -29,8 +29,8 @@
     private int                   macSize;
     private CipherParameters      keyParam;
     private byte[]                macBlock;
-    private ByteArrayOutputStream associatedText = new ByteArrayOutputStream();
-    private ByteArrayOutputStream data = new ByteArrayOutputStream();
+    private ExposedByteArrayOutputStream associatedText = new ExposedByteArrayOutputStream();
+    private ExposedByteArrayOutputStream data = new ExposedByteArrayOutputStream();
 
     /**
      * Basic constructor.
@@ -65,6 +65,7 @@
     {
         this.forEncryption = forEncryption;
 
+        CipherParameters cipherParameters;
         if (params instanceof AEADParameters)
         {
             AEADParameters param = (AEADParameters)params;
@@ -72,7 +73,7 @@
             nonce = param.getNonce();
             initialAssociatedText = param.getAssociatedText();
             macSize = param.getMacSize() / 8;
-            keyParam = param.getKey();
+            cipherParameters = param.getKey();
         }
         else if (params instanceof ParametersWithIV)
         {
@@ -81,17 +82,25 @@
             nonce = param.getIV();
             initialAssociatedText = null;
             macSize = macBlock.length / 2;
-            keyParam = param.getParameters();
+            cipherParameters = param.getParameters();
         }
         else
         {
             throw new IllegalArgumentException("invalid parameters passed to CCM");
         }
 
+        // NOTE: Very basic support for key re-use, but no performance gain from it
+        if (cipherParameters != null)
+        {
+            keyParam = cipherParameters;
+        }
+
         if (nonce == null || nonce.length < 7 || nonce.length > 13)
         {
             throw new IllegalArgumentException("nonce must have length from 7 to 13 octets");
         }
+        
+        reset();
     }
 
     public String getAlgorithmName()
@@ -129,14 +138,11 @@
     public int doFinal(byte[] out, int outOff)
         throws IllegalStateException, InvalidCipherTextException
     {
-        byte[] text = data.toByteArray();
-        byte[] enc = processPacket(text, 0, text.length);
-
-        System.arraycopy(enc, 0, out, outOff, enc.length);
+        int len = processPacket(data.getBuffer(), 0, data.size(), out, outOff);
 
         reset();
 
-        return enc.length;
+        return len;
     }
 
     public void reset()
@@ -178,9 +184,55 @@
         return totalData < macSize ? 0 : totalData - macSize;
     }
 
+    /**
+     * Process a packet of data for either CCM decryption or encryption.
+     *
+     * @param in data for processing.
+     * @param inOff offset at which data starts in the input array.
+     * @param inLen length of the data in the input array.
+     * @return a byte array containing the processed input..
+     * @throws IllegalStateException if the cipher is not appropriately set up.
+     * @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
+     */
     public byte[] processPacket(byte[] in, int inOff, int inLen)
         throws IllegalStateException, InvalidCipherTextException
     {
+        byte[] output;
+
+        if (forEncryption)
+        {
+            output = new byte[inLen + macSize];
+        }
+        else
+        {
+            if (inLen < macSize)
+            {
+                throw new InvalidCipherTextException("data too short");
+            }
+            output = new byte[inLen - macSize];
+        }
+
+        processPacket(in, inOff, inLen, output, 0);
+
+        return output;
+    }
+
+    /**
+     * Process a packet of data for either CCM decryption or encryption.
+     *
+     * @param in data for processing.
+     * @param inOff offset at which data starts in the input array.
+     * @param inLen length of the data in the input array.
+     * @param output output array.
+     * @param outOff offset into output array to start putting processed bytes.
+     * @return the number of bytes added to output.
+     * @throws IllegalStateException if the cipher is not appropriately set up.
+     * @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
+     * @throws DataLengthException if output buffer too short.
+     */
+    public int processPacket(byte[] in, int inOff, int inLen, byte[] output, int outOff)
+        throws IllegalStateException, InvalidCipherTextException, DataLengthException
+    {
         // TODO: handle null keyParam (e.g. via RepeatedKeySpec)
         // Need to keep the CTR and CBC Mac parts around and reset
         if (keyParam == null)
@@ -206,42 +258,52 @@
         BlockCipher ctrCipher = new SICBlockCipher(cipher);
         ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv));
 
-        int index = inOff;
-        int outOff = 0;
-        byte[] output;
+        int outputLen;
+        int inIndex = inOff;
+        int outIndex = outOff;
 
         if (forEncryption)
         {
-            output = new byte[inLen + macSize];
+            outputLen = inLen + macSize;
+            if (output.length < (outputLen + outOff))
+            {
+                throw new DataLengthException("Output buffer too short.");
+            }
 
             calculateMac(in, inOff, inLen, macBlock);
 
             ctrCipher.processBlock(macBlock, 0, macBlock, 0);   // S0
 
-            while (index < inLen - blockSize)                   // S1...
+            while (inIndex < (inOff + inLen - blockSize))                 // S1...
             {
-                ctrCipher.processBlock(in, index, output, outOff);
-                outOff += blockSize;
-                index += blockSize;
+                ctrCipher.processBlock(in, inIndex, output, outIndex);
+                outIndex += blockSize;
+                inIndex += blockSize;
             }
 
             byte[] block = new byte[blockSize];
 
-            System.arraycopy(in, index, block, 0, inLen - index);
+            System.arraycopy(in, inIndex, block, 0, inLen + inOff - inIndex);
 
             ctrCipher.processBlock(block, 0, block, 0);
 
-            System.arraycopy(block, 0, output, outOff, inLen - index);
+            System.arraycopy(block, 0, output, outIndex, inLen + inOff - inIndex);
 
-            outOff += inLen - index;
-
-            System.arraycopy(macBlock, 0, output, outOff, output.length - outOff);
+            System.arraycopy(macBlock, 0, output, outOff + inLen, macSize);
         }
         else
         {
-            output = new byte[inLen - macSize];
+            if (inLen < macSize)
+            {
+                throw new InvalidCipherTextException("data too short");
+            }
+            outputLen = inLen - macSize;
+            if (output.length < (outputLen + outOff))
+            {
+                throw new DataLengthException("Output buffer too short.");
+            }
 
-            System.arraycopy(in, inOff + inLen - macSize, macBlock, 0, macSize);
+            System.arraycopy(in, inOff + outputLen, macBlock, 0, macSize);
 
             ctrCipher.processBlock(macBlock, 0, macBlock, 0);
 
@@ -250,24 +312,24 @@
                 macBlock[i] = 0;
             }
 
-            while (outOff < output.length - blockSize)
+            while (inIndex < (inOff + outputLen - blockSize))
             {
-                ctrCipher.processBlock(in, index, output, outOff);
-                outOff += blockSize;
-                index += blockSize;
+                ctrCipher.processBlock(in, inIndex, output, outIndex);
+                outIndex += blockSize;
+                inIndex += blockSize;
             }
 
             byte[] block = new byte[blockSize];
 
-            System.arraycopy(in, index, block, 0, output.length - outOff);
+            System.arraycopy(in, inIndex, block, 0, outputLen - (inIndex - inOff));
 
             ctrCipher.processBlock(block, 0, block, 0);
 
-            System.arraycopy(block, 0, output, outOff, output.length - outOff);
+            System.arraycopy(block, 0, output, outIndex, outputLen - (inIndex - inOff));
 
             byte[] calculatedMacBlock = new byte[blockSize];
 
-            calculateMac(output, 0, output.length, calculatedMacBlock);
+            calculateMac(output, outOff, outputLen, calculatedMacBlock);
 
             if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock))
             {
@@ -275,7 +337,7 @@
             }
         }
 
-        return output;
+        return outputLen;
     }
 
     private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
@@ -344,8 +406,7 @@
             }
             if (associatedText.size() > 0)
             {
-                byte[] tmp = associatedText.toByteArray();
-                cMac.update(tmp, 0, tmp.length);
+                cMac.update(associatedText.getBuffer(), 0, associatedText.size());
             }
 
             extra = (extra + textLength) % 16;
@@ -375,4 +436,17 @@
     {
         return getAssociatedTextLength() > 0;
     }
+
+    private class ExposedByteArrayOutputStream
+        extends ByteArrayOutputStream
+    {
+        public ExposedByteArrayOutputStream()
+        {
+        }
+
+        public byte[] getBuffer()
+        {
+            return this.buf;
+        }
+    }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
index d0fb9bb..a885169 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
@@ -4,6 +4,7 @@
 import org.bouncycastle.crypto.CipherParameters;
 import org.bouncycastle.crypto.DataLengthException;
 import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.Arrays;
 
 /**
  * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
@@ -246,6 +247,16 @@
     }
 
     /**
+     * Return the current state of the initialisation vector.
+     *
+     * @return current IV
+     */
+    public byte[] getCurrentIV()
+    {
+        return Arrays.clone(cfbV);
+    }
+
+    /**
      * reset the chaining vector back to the IV and reset the underlying
      * cipher.
      */
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java
index b8e5b61..5388b40 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java
@@ -22,8 +22,9 @@
     public CTSBlockCipher(
         BlockCipher     cipher)
     {
-        if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher))
+        if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher) || (cipher instanceof SICBlockCipher))
         {
+            // TODO: This is broken - need to introduce marker interface to differentiate block cipher primitive from mode?
             throw new IllegalArgumentException("CTSBlockCipher can only accept ECB, or CBC ciphers");
         }
 
@@ -72,7 +73,7 @@
     }
 
     /**
-     * process a single byte, producing an output block if neccessary.
+     * process a single byte, producing an output block if necessary.
      *
      * @param in the input byte.
      * @param out the space for any output that might be produced.
@@ -200,60 +201,81 @@
 
         if (forEncryption)
         {
-            cipher.processBlock(buf, 0, block, 0);
-            
             if (bufOff < blockSize)
             {
                 throw new DataLengthException("need at least one block of input for CTS");
             }
 
-            for (int i = bufOff; i != buf.length; i++)
-            {
-                buf[i] = block[i - blockSize];
-            }
+            cipher.processBlock(buf, 0, block, 0);
 
-            for (int i = blockSize; i != bufOff; i++)
+            if (bufOff > blockSize)
             {
-                buf[i] ^= block[i - blockSize];
-            }
+                for (int i = bufOff; i != buf.length; i++)
+                {
+                    buf[i] = block[i - blockSize];
+                }
 
-            if (cipher instanceof CBCBlockCipher)
-            {
-                BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
+                for (int i = blockSize; i != bufOff; i++)
+                {
+                    buf[i] ^= block[i - blockSize];
+                }
 
-                c.processBlock(buf, blockSize, out, outOff);
+                if (cipher instanceof CBCBlockCipher)
+                {
+                    BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
+
+                    c.processBlock(buf, blockSize, out, outOff);
+                }
+                else
+                {
+                    cipher.processBlock(buf, blockSize, out, outOff);
+                }
+
+                System.arraycopy(block, 0, out, outOff + blockSize, len);
             }
             else
             {
-                cipher.processBlock(buf, blockSize, out, outOff);
+                System.arraycopy(block, 0, out, outOff, blockSize);
             }
-
-            System.arraycopy(block, 0, out, outOff + blockSize, len);
         }
         else
         {
+            if (bufOff < blockSize)
+            {
+                throw new DataLengthException("need at least one block of input for CTS");
+            }
+
             byte[]  lastBlock = new byte[blockSize];
 
-            if (cipher instanceof CBCBlockCipher)
+            if (bufOff > blockSize)
             {
-                BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
+                if (cipher instanceof CBCBlockCipher)
+                {
+                    BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
 
-                c.processBlock(buf, 0, block, 0);
+                    c.processBlock(buf, 0, block, 0);
+                }
+                else
+                {
+                    cipher.processBlock(buf, 0, block, 0);
+                }
+
+                for (int i = blockSize; i != bufOff; i++)
+                {
+                    lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
+                }
+
+                System.arraycopy(buf, blockSize, block, 0, len);
+
+                cipher.processBlock(block, 0, out, outOff);
+                System.arraycopy(lastBlock, 0, out, outOff + blockSize, len);
             }
             else
             {
                 cipher.processBlock(buf, 0, block, 0);
+
+                System.arraycopy(block, 0, out, outOff, blockSize);
             }
-
-            for (int i = blockSize; i != bufOff; i++)
-            {
-                lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
-            }
-
-            System.arraycopy(buf, blockSize, block, 0, len);
-
-            cipher.processBlock(block, 0, out, outOff);
-            System.arraycopy(lastBlock, 0, out, outOff + blockSize, len);
         }
 
         int offset = bufOff;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
index 031fe1b..9e617ec 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
@@ -22,11 +22,6 @@
     implements AEADBlockCipher
 {
     private static final int BLOCK_SIZE = 16;
-    // BEGIN android-added
-    // 2^36-32 : limitation imposed by NIST GCM as otherwise the counter is wrapped and it can leak
-    // plaintext and authentication key
-    private static final long MAX_INPUT_SIZE = 68719476704L;
-    // END android-added
 
     // not final due to a compiler bug 
     private BlockCipher   cipher;
@@ -199,14 +194,6 @@
         return totalData < macSize ? 0 : totalData - macSize;
     }
 
-    // BEGIN android-added
-    /** Helper used to ensure that {@link #MAX_INPUT_SIZE} is not exceeded. */
-    private long getTotalInputSizeAfterNewInput(int newInputLen)
-    {
-        return totalLength + newInputLen + bufOff;
-    }
-    // END android-added
-
     public int getUpdateOutputSize(int len)
     {
         int totalData = len + bufOff;
@@ -223,11 +210,6 @@
 
     public void processAADByte(byte in)
     {
-        // BEGIN android-added
-        if (getTotalInputSizeAfterNewInput(1) > MAX_INPUT_SIZE) {
-            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
-        }
-        // END android-added
         atBlock[atBlockPos] = in;
         if (++atBlockPos == BLOCK_SIZE)
         {
@@ -240,11 +222,6 @@
 
     public void processAADBytes(byte[] in, int inOff, int len)
     {
-        // BEGIN android-added
-        if (getTotalInputSizeAfterNewInput(len) > MAX_INPUT_SIZE) {
-            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
-        }
-        // END android-added
         for (int i = 0; i < len; ++i)
         {
             atBlock[atBlockPos] = in[inOff + i];
@@ -282,11 +259,6 @@
     public int processByte(byte in, byte[] out, int outOff)
         throws DataLengthException
     {
-        // BEGIN android-added
-        if (getTotalInputSizeAfterNewInput(1) > MAX_INPUT_SIZE) {
-            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
-        }
-        // END android-added
         bufBlock[bufOff] = in;
         if (++bufOff == bufBlock.length)
         {
@@ -299,11 +271,6 @@
     public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
         throws DataLengthException
     {
-        // BEGIN android-added
-        if (getTotalInputSizeAfterNewInput(len) > MAX_INPUT_SIZE) {
-            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
-        }
-        // END android-added
         int resultLen = 0;
 
         for (int i = 0; i < len; ++i)
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
index 4875301..3031a44 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
@@ -5,6 +5,32 @@
 
 abstract class GCMUtil
 {
+    private static final int E1 = 0xe1000000;
+    private static final byte E1B = (byte)0xe1;
+    private static final long E1L = (E1 & 0xFFFFFFFFL) << 24;
+
+    private static int[] generateLookup()
+    {
+        int[] lookup = new int[256];
+
+        for (int c = 0; c < 256; ++c)
+        {
+            int v = 0;
+            for (int i = 7; i >= 0; --i)
+            {
+                if ((c & (1 << i)) != 0)
+                {
+                    v ^= (E1 >>> (7 - i));
+                }
+            }
+            lookup[c] = v;
+        }
+
+        return lookup;
+    }
+
+    private static final int[] LOOKUP = generateLookup();
+
     static byte[] oneAsBytes()
     {
         byte[] tmp = new byte[16];
@@ -15,78 +41,155 @@
     static int[] oneAsInts()
     {
         int[] tmp = new int[4];
-        tmp[0] = 0x80000000;
+        tmp[0] = 1 << 31;
         return tmp;
     }
 
-    static byte[] asBytes(int[] ns)
+    static long[] oneAsLongs()
     {
-        byte[] output = new byte[16];
-        Pack.intToBigEndian(ns, output, 0);
-        return output;
+        long[] tmp = new long[2];
+        tmp[0] = 1L << 63;
+        return tmp;
     }
 
-    static int[] asInts(byte[] bs)
+    static byte[] asBytes(int[] x)
     {
-        int[] output = new int[4];
-        Pack.bigEndianToInt(bs, 0, output);
-        return output;
+        byte[] z = new byte[16];
+        Pack.intToBigEndian(x, z, 0);
+        return z;
     }
 
-    static void asInts(byte[] bs, int[] output)
+    static void asBytes(int[] x, byte[] z)
     {
-        Pack.bigEndianToInt(bs, 0, output);
+        Pack.intToBigEndian(x, z, 0);
     }
 
-    static void multiply(byte[] block, byte[] val)
+    static byte[] asBytes(long[] x)
     {
-        byte[] tmp = Arrays.clone(block);
-        byte[] c = new byte[16];
+        byte[] z = new byte[16];
+        Pack.longToBigEndian(x, z, 0);
+        return z;
+    }
+
+    static void asBytes(long[] x, byte[] z)
+    {
+        Pack.longToBigEndian(x, z, 0);
+    }
+
+    static int[] asInts(byte[] x)
+    {
+        int[] z = new int[4];
+        Pack.bigEndianToInt(x, 0, z);
+        return z;
+    }
+
+    static void asInts(byte[] x, int[] z)
+    {
+        Pack.bigEndianToInt(x, 0, z);
+    }
+
+    static long[] asLongs(byte[] x)
+    {
+        long[] z = new long[2];
+        Pack.bigEndianToLong(x, 0, z);
+        return z;
+    }
+
+    static void asLongs(byte[] x, long[] z)
+    {
+        Pack.bigEndianToLong(x, 0, z);
+    }
+
+    static void multiply(byte[] x, byte[] y)
+    {
+        byte[] r0 = Arrays.clone(x);
+        byte[] r1 = new byte[16];
 
         for (int i = 0; i < 16; ++i)
         {
-            byte bits = val[i];
+            byte bits = y[i];
             for (int j = 7; j >= 0; --j)
             {
                 if ((bits & (1 << j)) != 0)
                 {
-                    xor(c, tmp);
+                    xor(r1, r0);
                 }
 
-                boolean lsb = (tmp[15] & 1) != 0;
-                shiftRight(tmp);
-                if (lsb)
+                if (shiftRight(r0) != 0)
                 {
-                    // R = new byte[]{ 0xe1, ... };
-//                    GCMUtil.xor(v, R);
-                    tmp[0] ^= (byte)0xe1;
+                    r0[0] ^= E1B;
                 }
             }
         }
 
-        System.arraycopy(c, 0, block, 0, 16);
+        System.arraycopy(r1, 0, x, 0, 16);
+    }
+
+    static void multiply(int[] x, int[] y)
+    {
+        int[] r0 = Arrays.clone(x);
+        int[] r1 = new int[4];
+
+        for (int i = 0; i < 4; ++i)
+        {
+            int bits = y[i];
+            for (int j = 31; j >= 0; --j)
+            {
+                if ((bits & (1 << j)) != 0)
+                {
+                    xor(r1, r0);
+                }
+
+                if (shiftRight(r0) != 0)
+                {
+                    r0[0] ^= E1;
+                }
+            }
+        }
+
+        System.arraycopy(r1, 0, x, 0, 4);
+    }
+
+    static void multiply(long[] x, long[] y)
+    {
+        long[] r0 = new long[]{ x[0], x[1] };
+        long[] r1 = new long[2];
+
+        for (int i = 0; i < 2; ++i)
+        {
+            long bits = y[i];
+            for (int j = 63; j >= 0; --j)
+            {
+                if ((bits & (1L << j)) != 0)
+                {
+                    xor(r1, r0);
+                }
+
+                if (shiftRight(r0) != 0)
+                {
+                    r0[0] ^= E1L;
+                }
+            }
+        }
+
+        x[0] = r1[0];
+        x[1] = r1[1];
     }
 
     // P is the value with only bit i=1 set
     static void multiplyP(int[] x)
     {
-        boolean lsb = (x[3] & 1) != 0;
-        shiftRight(x);
-        if (lsb)
+        if (shiftRight(x) != 0)
         {
-            // R = new int[]{ 0xe1000000, 0, 0, 0 };
-//            xor(v, R);
-            x[0] ^= 0xe1000000;
+            x[0] ^= E1;
         }
     }
 
-    static void multiplyP(int[] x, int[] output)
+    static void multiplyP(int[] x, int[] y)
     {
-        boolean lsb = (x[3] & 1) != 0;
-        shiftRight(x, output);
-        if (lsb)
+        if (shiftRight(x, y) != 0)
         {
-            output[0] ^= 0xe1000000;
+            y[0] ^= E1;
         }
     }
 
@@ -98,163 +201,257 @@
 //            multiplyP(x);
 //        }
 
-        int lsw = x[3];
-        shiftRightN(x, 8);
-        for (int i = 7; i >= 0; --i)
-        {
-            if ((lsw & (1 << i)) != 0)
-            {
-                x[0] ^= (0xe1000000 >>> (7 - i));
-            }
-        }
+        int c = shiftRightN(x, 8);
+        x[0] ^= LOOKUP[c >>> 24];
     }
 
-    static void multiplyP8(int[] x, int[] output)
+    static void multiplyP8(int[] x, int[] y)
     {
-        int lsw = x[3];
-        shiftRightN(x, 8, output);
-        for (int i = 7; i >= 0; --i)
-        {
-            if ((lsw & (1 << i)) != 0)
-            {
-                output[0] ^= (0xe1000000 >>> (7 - i));
-            }
-        }
+        int c = shiftRightN(x, 8, y);
+        y[0] ^= LOOKUP[c >>> 24];
     }
 
-    static void shiftRight(byte[] block)
+    static byte shiftRight(byte[] x)
+    {
+//        int c = 0;
+//        for (int i = 0; i < 16; ++i)
+//        {
+//            int b = x[i] & 0xff;
+//            x[i] = (byte)((b >>> 1) | c);
+//            c = (b & 1) << 7;
+//        }
+//        return (byte)c;
+
+        int i = 0, c = 0;
+        do
+        {
+            int b = x[i] & 0xff;
+            x[i++] = (byte)((b >>> 1) | c);
+            c = (b & 1) << 7;
+            b = x[i] & 0xff;
+            x[i++] = (byte)((b >>> 1) | c);
+            c = (b & 1) << 7;
+            b = x[i] & 0xff;
+            x[i++] = (byte)((b >>> 1) | c);
+            c = (b & 1) << 7;
+            b = x[i] & 0xff;
+            x[i++] = (byte)((b >>> 1) | c);
+            c = (b & 1) << 7;
+        }
+        while (i < 16);
+        return (byte)c;
+    }
+
+    static byte shiftRight(byte[] x, byte[] z)
+    {
+//        int c = 0;
+//        for (int i = 0; i < 16; ++i)
+//        {
+//            int b = x[i] & 0xff;
+//            z[i] = (byte) ((b >>> 1) | c);
+//            c = (b & 1) << 7;
+//        }
+//        return (byte) c;
+
+        int i = 0, c = 0;
+        do
+        {
+            int b = x[i] & 0xff;
+            z[i++] = (byte)((b >>> 1) | c);
+            c = (b & 1) << 7;
+            b = x[i] & 0xff;
+            z[i++] = (byte)((b >>> 1) | c);
+            c = (b & 1) << 7;
+            b = x[i] & 0xff;
+            z[i++] = (byte)((b >>> 1) | c);
+            c = (b & 1) << 7;
+            b = x[i] & 0xff;
+            z[i++] = (byte)((b >>> 1) | c);
+            c = (b & 1) << 7;
+        }
+        while (i < 16);
+        return (byte)c;
+    }
+
+    static int shiftRight(int[] x)
+    {
+//        int c = 0;
+//        for (int i = 0; i < 4; ++i)
+//        {
+//            int b = x[i];
+//            x[i] = (b >>> 1) | c;
+//            c = b << 31;
+//        }
+//        return c;
+
+        int b = x[0];
+        x[0] = b >>> 1;
+        int c = b << 31;
+        b = x[1];
+        x[1] = (b >>> 1) | c;
+        c = b << 31;
+        b = x[2];
+        x[2] = (b >>> 1) | c;
+        c = b << 31;
+        b = x[3];
+        x[3] = (b >>> 1) | c;
+        return b << 31;
+    }
+
+    static int shiftRight(int[] x, int[] z)
+    {
+//      int c = 0;
+//      for (int i = 0; i < 4; ++i)
+//      {
+//          int b = x[i];
+//          z[i] = (b >>> 1) | c;
+//          c = b << 31;
+//      }
+//      return c;
+
+        int b = x[0];
+        z[0] = b >>> 1;
+        int c = b << 31;
+        b = x[1];
+        z[1] = (b >>> 1) | c;
+        c = b << 31;
+        b = x[2];
+        z[2] = (b >>> 1) | c;
+        c = b << 31;
+        b = x[3];
+        z[3] = (b >>> 1) | c;
+        return b << 31;
+    }
+
+    static long shiftRight(long[] x)
+    {
+        long b = x[0];
+        x[0] = b >>> 1;
+        long c = b << 63; 
+        b = x[1];
+        x[1] = (b >>> 1) | c;
+        return b << 63;
+    }
+
+    static long shiftRight(long[] x, long[] z)
+    {
+        long b = x[0];
+        z[0] = b >>> 1;
+        long c = b << 63; 
+        b = x[1];
+        z[1] = (b >>> 1) | c;
+        return b << 63;
+    }
+
+    static int shiftRightN(int[] x, int n)
+    {
+//        int c = 0, nInv = 32 - n;
+//        for (int i = 0; i < 4; ++i)
+//        {
+//            int b = x[i];
+//            x[i] = (b >>> n) | c;
+//            c = b << nInv;
+//        }
+//        return c;
+
+        int b = x[0], nInv = 32 - n;
+        x[0] = b >>> n;
+        int c = b << nInv;
+        b = x[1];
+        x[1] = (b >>> n) | c;
+        c = b << nInv;
+        b = x[2];
+        x[2] = (b >>> n) | c;
+        c = b << nInv;
+        b = x[3];
+        x[3] = (b >>> n) | c;
+        return b << nInv;
+    }
+
+    static int shiftRightN(int[] x, int n, int[] z)
+    {
+//        int c = 0, nInv = 32 - n;
+//        for (int i = 0; i < 4; ++i)
+//        {
+//            int b = x[i];
+//            z[i] = (b >>> n) | c;
+//            c = b << nInv;
+//        }
+//        return c;
+
+        int b = x[0], nInv = 32 - n;
+        z[0] = b >>> n;
+        int c = b << nInv;
+        b = x[1];
+        z[1] = (b >>> n) | c;
+        c = b << nInv;
+        b = x[2];
+        z[2] = (b >>> n) | c;
+        c = b << nInv;
+        b = x[3];
+        z[3] = (b >>> n) | c;
+        return b << nInv;
+    }
+
+    static void xor(byte[] x, byte[] y)
     {
         int i = 0;
-        int bit = 0;
-        for (;;)
+        do
         {
-            int b = block[i] & 0xff;
-            block[i] = (byte) ((b >>> 1) | bit);
-            if (++i == 16)
-            {
-                break;
-            }
-            bit = (b & 1) << 7;
+            x[i] ^= y[i]; ++i;
+            x[i] ^= y[i]; ++i;
+            x[i] ^= y[i]; ++i;
+            x[i] ^= y[i]; ++i;
+        }
+        while (i < 16);
+    }
+
+    static void xor(byte[] x, byte[] y, int yOff, int yLen)
+    {
+        while (yLen-- > 0)
+        {
+            x[yLen] ^= y[yOff + yLen];
         }
     }
 
-    static void shiftRight(byte[] block, byte[] output)
+    static void xor(byte[] x, byte[] y, byte[] z)
     {
         int i = 0;
-        int bit = 0;
-        for (;;)
+        do
         {
-            int b = block[i] & 0xff;
-            output[i] = (byte) ((b >>> 1) | bit);
-            if (++i == 16)
-            {
-                break;
-            }
-            bit = (b & 1) << 7;
+            z[i] = (byte)(x[i] ^ y[i]); ++i;
+            z[i] = (byte)(x[i] ^ y[i]); ++i;
+            z[i] = (byte)(x[i] ^ y[i]); ++i;
+            z[i] = (byte)(x[i] ^ y[i]); ++i;
         }
+        while (i < 16);
     }
 
-    static void shiftRight(int[] block)
+    static void xor(int[] x, int[] y)
     {
-        int i = 0;
-        int bit = 0;
-        for (;;)
-        {
-            int b = block[i];
-            block[i] = (b >>> 1) | bit;
-            if (++i == 4)
-            {
-                break;
-            }
-            bit = b << 31;
-        }
+        x[0] ^= y[0];
+        x[1] ^= y[1];
+        x[2] ^= y[2];
+        x[3] ^= y[3];
     }
 
-    static void shiftRight(int[] block, int[] output)
+    static void xor(int[] x, int[] y, int[] z)
     {
-        int i = 0;
-        int bit = 0;
-        for (;;)
-        {
-            int b = block[i];
-            output[i] = (b >>> 1) | bit;
-            if (++i == 4)
-            {
-                break;
-            }
-            bit = b << 31;
-        }
+        z[0] = x[0] ^ y[0];
+        z[1] = x[1] ^ y[1];
+        z[2] = x[2] ^ y[2];
+        z[3] = x[3] ^ y[3];
     }
 
-    static void shiftRightN(int[] block, int n)
+    static void xor(long[] x, long[] y)
     {
-        int i = 0;
-        int bits = 0;
-        for (;;)
-        {
-            int b = block[i];
-            block[i] = (b >>> n) | bits;
-            if (++i == 4)
-            {
-                break;
-            }
-            bits = b << (32 - n);
-        }
+        x[0] ^= y[0];
+        x[1] ^= y[1];
     }
 
-    static void shiftRightN(int[] block, int n, int[] output)
+    static void xor(long[] x, long[] y, long[] z)
     {
-        int i = 0;
-        int bits = 0;
-        for (;;)
-        {
-            int b = block[i];
-            output[i] = (b >>> n) | bits;
-            if (++i == 4)
-            {
-                break;
-            }
-            bits = b << (32 - n);
-        }
-    }
-
-    static void xor(byte[] block, byte[] val)
-    {
-        for (int i = 15; i >= 0; --i)
-        {
-            block[i] ^= val[i];
-        }
-    }
-
-    static void xor(byte[] block, byte[] val, int off, int len)
-    {
-        while (len-- > 0)
-        {
-            block[len] ^= val[off + len];
-        }
-    }
-
-    static void xor(byte[] block, byte[] val, byte[] output)
-    {
-        for (int i = 15; i >= 0; --i)
-        {
-            output[i] = (byte)(block[i] ^ val[i]);
-        }
-    }
-
-    static void xor(int[] block, int[] val)
-    {
-        for (int i = 3; i >= 0; --i)
-        {
-            block[i] ^= val[i];
-        }
-    }
-
-    static void xor(int[] block, int[] val, int[] output)
-    {
-        for (int i = 3; i >= 0; --i)
-        {
-            output[i] = block[i] ^ val[i];
-        }
+        z[0] = x[0] ^ y[0];
+        z[1] = x[1] ^ y[1];
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java
index a051208..6eff4e3 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java
@@ -12,31 +12,32 @@
 
     public void init(byte[] x)
     {
-        if (lookupPowX2 != null && Arrays.areEqual(x, (byte[])lookupPowX2.elementAt(0)))
+        int[] y = GCMUtil.asInts(x);
+        if (lookupPowX2 != null && Arrays.areEqual(y, (int[])lookupPowX2.elementAt(0)))
         {
             return;
         }
 
         lookupPowX2 = new Vector(8);
-        lookupPowX2.addElement(Arrays.clone(x));
+        lookupPowX2.addElement(y);
     }
 
     public void exponentiateX(long pow, byte[] output)
     {
-        byte[] y = GCMUtil.oneAsBytes();
+        int[] y = GCMUtil.oneAsInts();
         int bit = 0;
         while (pow > 0)
         {
             if ((pow & 1L) != 0)
             {
                 ensureAvailable(bit);
-                GCMUtil.multiply(y, (byte[])lookupPowX2.elementAt(bit));
+                GCMUtil.multiply(y, (int[])lookupPowX2.elementAt(bit));
             }
             ++bit;
             pow >>>= 1;
         }
 
-        System.arraycopy(y, 0, output, 0, 16);
+        GCMUtil.asBytes(y, output);
     }
 
     private void ensureAvailable(int bit)
@@ -44,7 +45,7 @@
         int count = lookupPowX2.size();
         if (count <= bit)
         {
-            byte[] tmp = (byte[])lookupPowX2.elementAt(count - 1);
+            int[] tmp = (int[])lookupPowX2.elementAt(count - 1);
             do
             {
                 tmp = Arrays.clone(tmp);
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java
index 05a1327..9cc6e72 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java
@@ -41,7 +41,7 @@
         byte[]      seed)
     {
         this.curve = curve;
-        this.G = G;
+        this.G = G.normalize();
         this.n = n;
         this.h = h;
         this.seed = seed;
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
index 5fbea19..b6b3fb6 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
@@ -12,7 +12,7 @@
         ECDomainParameters  params)
     {
         super(false, params);
-        this.Q = Q;
+        this.Q = Q.normalize();
     }
 
     public ECPoint getQ()
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSAKCalculator.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSAKCalculator.java
new file mode 100644
index 0000000..fced06e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSAKCalculator.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.crypto.signers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * Interface define calculators of K values for DSA/ECDSA.
+ */
+public interface DSAKCalculator
+{
+    /**
+     * Return true if this calculator is deterministic, false otherwise.
+     *
+     * @return true if deterministic, otherwise false.
+     */
+    boolean isDeterministic();
+
+    /**
+     * Non-deterministic initialiser.
+     *
+     * @param n the order of the DSA group.
+     * @param random a source of randomness.
+     */
+    void init(BigInteger n, SecureRandom random);
+
+    /**
+     * Deterministic initialiser.
+     *
+     * @param n the order of the DSA group.
+     * @param d the DSA private value.
+     * @param message the message being signed.
+     */
+    void init(BigInteger n, BigInteger d, byte[] message);
+
+    /**
+     * Return the next valid value of K.
+     *
+     * @return a K value.
+     */
+    BigInteger nextK();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
index a96cef0..292c408 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.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.DSAKeyParameters;
@@ -8,9 +11,6 @@
 import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
 import org.bouncycastle.crypto.params.ParametersWithRandom;
 
-import java.math.BigInteger;
-import java.security.SecureRandom;
-
 /**
  * The Digital Signature Algorithm - as described in "Handbook of Applied
  * Cryptography", pages 452 - 453.
@@ -18,9 +18,28 @@
 public class DSASigner
     implements DSA
 {
-    DSAKeyParameters key;
+    private final DSAKCalculator kCalculator;
 
-    SecureRandom    random;
+    private DSAKeyParameters key;
+    private SecureRandom    random;
+
+    /**
+     * Default configuration, random K values.
+     */
+    public DSASigner()
+    {
+        this.kCalculator = new RandomDSAKCalculator();
+    }
+
+    /**
+     * Configuration with an alternate, possibly deterministic calculator of K.
+     *
+     * @param kCalculator a K value calculator.
+     */
+    public DSASigner(DSAKCalculator kCalculator)
+    {
+        this.kCalculator = kCalculator;
+    }
 
     public void init(
         boolean                 forSigning,
@@ -59,14 +78,17 @@
     {
         DSAParameters   params = key.getParameters();
         BigInteger      m = calculateE(params.getQ(), message);
-        BigInteger      k;
-        int                  qBitLength = params.getQ().bitLength();
 
-        do 
+        if (kCalculator.isDeterministic())
         {
-            k = new BigInteger(qBitLength, random);
+            kCalculator.init(params.getQ(), ((DSAPrivateKeyParameters)key).getX(), message);
         }
-        while (k.compareTo(params.getQ()) >= 0);
+        else
+        {
+            kCalculator.init(params.getQ(), random);
+        }
+
+        BigInteger  k = kCalculator.nextK();
 
         BigInteger  r = params.getG().modPow(k, params.getP()).mod(params.getQ());
 
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
index a80c574..2a1f98e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
@@ -19,9 +19,28 @@
 public class ECDSASigner
     implements ECConstants, DSA
 {
-    ECKeyParameters key;
+    private final DSAKCalculator kCalculator;
 
-    SecureRandom    random;
+    private ECKeyParameters key;
+    private SecureRandom    random;
+
+    /**
+     * Default configuration, random K values.
+     */
+    public ECDSASigner()
+    {
+        this.kCalculator = new RandomDSAKCalculator();
+    }
+
+    /**
+     * Configuration with an alternate, possibly deterministic calculator of K.
+     *
+     * @param kCalculator a K value calculator.
+     */
+    public ECDSASigner(DSAKCalculator kCalculator)
+    {
+        this.kCalculator = kCalculator;
+    }
 
     public void init(
         boolean                 forSigning,
@@ -64,24 +83,28 @@
         BigInteger r = null;
         BigInteger s = null;
 
+        if (kCalculator.isDeterministic())
+        {
+            kCalculator.init(n, ((ECPrivateKeyParameters)key).getD(), message);
+        }
+        else
+        {
+            kCalculator.init(n, random);
+        }
+
         // 5.3.2
         do // generate s
         {
             BigInteger k = null;
-            int        nBitLength = n.bitLength();
 
             do // generate r
             {
-                do
-                {
-                    k = new BigInteger(nBitLength, random);
-                }
-                while (k.equals(ZERO) || k.compareTo(n) >= 0);
+                k = kCalculator.nextK();
 
-                ECPoint p = key.getParameters().getG().multiply(k);
+                ECPoint p = key.getParameters().getG().multiply(k).normalize();
 
                 // 5.3.3
-                BigInteger x = p.getX().toBigInteger();
+                BigInteger x = p.getAffineXCoord().toBigInteger();
 
                 r = x.mod(n);
             }
@@ -135,7 +158,7 @@
         ECPoint G = key.getParameters().getG();
         ECPoint Q = ((ECPublicKeyParameters)key).getQ();
 
-        ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2);
+        ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2).normalize();
 
         // components must be bogus.
         if (point.isInfinity())
@@ -143,7 +166,7 @@
             return false;
         }
 
-        BigInteger v = point.getX().toBigInteger().mod(n);
+        BigInteger v = point.getAffineXCoord().toBigInteger().mod(n);
 
         return v.equals(r);
     }
@@ -153,17 +176,11 @@
         int log2n = n.bitLength();
         int messageBitLength = message.length * 8;
 
-        if (log2n >= messageBitLength)
+        BigInteger e = new BigInteger(1, message);
+        if (log2n < messageBitLength)
         {
-            return new BigInteger(1, message);
+            e = e.shiftRight(messageBitLength - log2n);
         }
-        else
-        {
-            BigInteger trunc = new BigInteger(1, message);
-
-            trunc = trunc.shiftRight(messageBitLength - log2n);
-
-            return trunc;
-        }
+        return e;
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
index a975d27..18dd84e 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
@@ -46,9 +46,7 @@
         // END android-removed
 
         oidMap.put("SHA-1", X509ObjectIdentifiers.id_SHA1);
-        // BEGIN android-removed
-        // oidMap.put("SHA-224", NISTObjectIdentifiers.id_sha224);
-        // END android-removed
+        oidMap.put("SHA-224", NISTObjectIdentifiers.id_sha224);
         oidMap.put("SHA-256", NISTObjectIdentifiers.id_sha256);
         oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384);
         oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
@@ -63,9 +61,15 @@
     public RSADigestSigner(
         Digest digest)
     {
-        this.digest = digest;
+        this(digest, (ASN1ObjectIdentifier)oidMap.get(digest.getAlgorithmName()));
+    }
 
-        algId = new AlgorithmIdentifier((ASN1ObjectIdentifier)oidMap.get(digest.getAlgorithmName()), DERNull.INSTANCE);
+    public RSADigestSigner(
+        Digest digest,
+        ASN1ObjectIdentifier digestOid)
+    {
+        this.digest = digest;
+        this.algId = new AlgorithmIdentifier(digestOid, DERNull.INSTANCE);
     }
 
     /**
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java
new file mode 100644
index 0000000..bbd8cda
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java
@@ -0,0 +1,43 @@
+package org.bouncycastle.crypto.signers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+class RandomDSAKCalculator
+    implements DSAKCalculator
+{
+    private static final BigInteger ZERO = BigInteger.valueOf(0);
+
+    private BigInteger q;
+    private SecureRandom random;
+
+    public boolean isDeterministic()
+    {
+        return false;
+    }
+
+    public void init(BigInteger n, SecureRandom random)
+    {
+        this.q = n;
+        this.random = random;
+    }
+
+    public void init(BigInteger n, BigInteger d, byte[] message)
+    {
+        throw new IllegalStateException("Operation not supported");
+    }
+
+    public BigInteger nextK()
+    {
+        int qBitLength = q.bitLength();
+
+        BigInteger k;
+        do
+        {
+            k = new BigInteger(qBitLength, random);
+        }
+        while (k.equals(ZERO) || k.compareTo(q) >= 0);
+
+        return k;
+    }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
index 394f2c2..d997db7 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
@@ -10,7 +10,6 @@
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.nist.NISTNamedCurves;
 // BEGIN android-removed
 // import org.bouncycastle.asn1.oiw.ElGamalParameter;
 // END android-removed
@@ -20,13 +19,9 @@
 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
 import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
 import org.bouncycastle.asn1.sec.ECPrivateKey;
-import org.bouncycastle.asn1.sec.SECNamedCurves;
-// BEGIN android-removed
-// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
-// END android-removed
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.DSAParameter;
-import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
 import org.bouncycastle.asn1.x9.X962Parameters;
 import org.bouncycastle.asn1.x9.X9ECParameters;
 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
@@ -138,24 +133,7 @@
             if (params.isNamedCurve())
             {
                 ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
-                x9 = X962NamedCurves.getByOID(oid);
-
-                if (x9 == null)
-                {
-                    x9 = SECNamedCurves.getByOID(oid);
-
-                    if (x9 == null)
-                    {
-                        x9 = NISTNamedCurves.getByOID(oid);
-
-                        // BEGIN android-removed
-                        // if (x9 == null)
-                        // {
-                        //     x9 = TeleTrusTNamedCurves.getByOID(oid);
-                        // }
-                        // END android-removed
-                    }
-                }
+                x9 = ECNamedCurveTable.getByOID(oid);
             }
             else
             {
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
index 6a5c88e..7ade197 100644
--- a/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
@@ -12,7 +12,6 @@
 import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.nist.NISTNamedCurves;
 // BEGIN android-removed
 // import org.bouncycastle.asn1.oiw.ElGamalParameter;
 // END android-removed
@@ -20,10 +19,6 @@
 import org.bouncycastle.asn1.pkcs.DHParameter;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.RSAPublicKey;
-import org.bouncycastle.asn1.sec.SECNamedCurves;
-// BEGIN android-removed
-// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
-// END android-removed
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.DSAParameter;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
@@ -31,7 +26,7 @@
 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.ECNamedCurveTable;
 import org.bouncycastle.asn1.x9.X962Parameters;
 import org.bouncycastle.asn1.x9.X9ECParameters;
 import org.bouncycastle.asn1.x9.X9ECPoint;
@@ -168,31 +163,13 @@
         }
         else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey))
         {
-            X962Parameters params = new X962Parameters(
-                (ASN1Primitive)algId.getParameters());
+            X962Parameters params = X962Parameters.getInstance(algId.getParameters());
 
             X9ECParameters x9;
             if (params.isNamedCurve())
             {
                 ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
-                x9 = X962NamedCurves.getByOID(oid);
-
-                if (x9 == null)
-                {
-                    x9 = SECNamedCurves.getByOID(oid);
-
-                    if (x9 == null)
-                    {
-                        x9 = NISTNamedCurves.getByOID(oid);
-
-                        // BEGIN android-removed
-                        // if (x9 == null)
-                        // {
-                        //     x9 = TeleTrusTNamedCurves.getByOID(oid);
-                        // }
-                        // END android-removed
-                    }
-                }
+                x9 = ECNamedCurveTable.getByOID(oid);
             }
             else
             {
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceUtils.java b/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceUtils.java
new file mode 100644
index 0000000..d7677f3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceUtils.java
@@ -0,0 +1,53 @@
+package org.bouncycastle.jcajce;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Primitive;
+
+public class JcaJceUtils
+{
+    private JcaJceUtils()
+    {
+
+    }
+
+    /**
+     * Extract an ASN.1 encodable from an AlgorithmParameters object.
+     *
+     * @param params the object to get the encoding used to create the return value.
+     * @return an ASN.1 object representing the primitives making up the params parameter.
+     * @throws IOException if an encoding cannot be extracted.
+     */
+    public static ASN1Encodable extractParameters(AlgorithmParameters params)
+        throws IOException
+    {
+        // we try ASN.1 explicitly first just in case and then role back to the default.
+        ASN1Encodable asn1Params;
+        try
+        {
+            asn1Params = ASN1Primitive.fromByteArray(params.getEncoded("ASN.1"));
+        }
+        catch (Exception ex)
+        {
+            asn1Params = ASN1Primitive.fromByteArray(params.getEncoded());
+        }
+
+        return asn1Params;
+    }
+
+    public static void loadParameters(AlgorithmParameters params, ASN1Encodable sParams)
+        throws IOException
+    {
+        // we try ASN.1 explicitly first just in case and then role back to the default.
+        try
+        {
+            params.init(sParams.toASN1Primitive().getEncoded(), "ASN.1");
+        }
+        catch (Exception ex)
+        {
+            params.init(sParams.toASN1Primitive().getEncoded());
+        }
+    }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java b/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java
deleted file mode 100644
index 235bfe5..0000000
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.bouncycastle.jcajce.io;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-import javax.crypto.Mac;
-
-public class MacOutputStream
-    extends OutputStream
-{
-    protected Mac mac;
-
-    public MacOutputStream(
-        Mac          mac)
-    {
-        this.mac = mac;
-    }
-
-    public void write(int b)
-        throws IOException
-    {
-        mac.update((byte)b);
-    }
-
-    public void write(
-        byte[] b,
-        int off,
-        int len)
-        throws IOException
-    {
-        mac.update(b, off, len);
-    }
-
-    public byte[] getMac()
-    {
-        return mac.doFinal();
-    }
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
index b908f58..2bede7e 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
@@ -35,8 +35,17 @@
             provider.addAlgorithm("Alg.Alias.Signature.RAWDSA", "NONEWITHDSA");
 
             // BEGIN android-removed
-            // addSignatureAlgorithm(provider, "SHA224", "DSA", PREFIX + "DSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
-            // addSignatureAlgorithm(provider, "SHA256", "DSA", PREFIX + "DSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
+            // provider.addAlgorithm("Signature.DETDSA", PREFIX + "DSASigner$detDSA");
+            // provider.addAlgorithm("Signature.SHA1WITHDETDSA", PREFIX + "DSASigner$detDSA");
+            // provider.addAlgorithm("Signature.SHA224WITHDETDSA", PREFIX + "DSASigner$detDSA224");
+            // provider.addAlgorithm("Signature.SHA256WITHDETDSA", PREFIX + "DSASigner$detDSA256");
+            // provider.addAlgorithm("Signature.SHA384WITHDETDSA", PREFIX + "DSASigner$detDSA384");
+            // provider.addAlgorithm("Signature.SHA512WITHDETDSA", PREFIX + "DSASigner$detDSA512");
+            // END android-removed
+
+            addSignatureAlgorithm(provider, "SHA224", "DSA", PREFIX + "DSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
+            addSignatureAlgorithm(provider, "SHA256", "DSA", PREFIX + "DSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
+            // BEGIN android-removed
             // addSignatureAlgorithm(provider, "SHA384", "DSA", PREFIX + "DSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384);
             // addSignatureAlgorithm(provider, "SHA512", "DSA", PREFIX + "DSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512);
             // END android-removed
@@ -46,6 +55,7 @@
             // END android-added
             // BEGIN android-changed
             provider.addAlgorithm("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA");
+            provider.addAlgorithm("Alg.Alias.Signature.SHA1withDSA", "SHA1withDSA");
             provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDSA", "SHA1withDSA");
             provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "SHA1withDSA");
             provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA");
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
index 8d50a54..43e5861 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
@@ -79,11 +79,16 @@
             provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
             // BEGIN android-removed
             // provider.addAlgorithm("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
+            //
+            // provider.addAlgorithm("Signature.DETECDSA", PREFIX + "SignatureSpi$ecDetDSA");
+            // provider.addAlgorithm("Signature.SHA1WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA");
+            // provider.addAlgorithm("Signature.SHA224WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA224");
+            // provider.addAlgorithm("Signature.SHA256WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA256");
+            // provider.addAlgorithm("Signature.SHA384WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA384");
+            // provider.addAlgorithm("Signature.SHA512WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA512");
             // END android-removed
 
-            // BEGIN android-removed
-            // addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
-            // END android-removed
+            addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
             addSignatureAlgorithm(provider, "SHA256", "ECDSA", PREFIX + "SignatureSpi$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
             addSignatureAlgorithm(provider, "SHA384", "ECDSA", PREFIX + "SignatureSpi$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
             addSignatureAlgorithm(provider, "SHA512", "ECDSA", PREFIX + "SignatureSpi$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
index d570cf6..901e27d 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
@@ -157,9 +157,7 @@
                 provider.addAlgorithm("Alg.Alias.Signature.OID." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
             }
 
-            // BEGIN android-removed
-            // addDigestSignature(provider, "SHA224", PREFIX + "DigestSignatureSpi$SHA224", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-            // END android-removed
+            addDigestSignature(provider, "SHA224", PREFIX + "DigestSignatureSpi$SHA224", PKCSObjectIdentifiers.sha224WithRSAEncryption);
             addDigestSignature(provider, "SHA256", PREFIX + "DigestSignatureSpi$SHA256", PKCSObjectIdentifiers.sha256WithRSAEncryption);
             addDigestSignature(provider, "SHA384", PREFIX + "DigestSignatureSpi$SHA384", PKCSObjectIdentifiers.sha384WithRSAEncryption);
             addDigestSignature(provider, "SHA512", PREFIX + "DigestSignatureSpi$SHA512", PKCSObjectIdentifiers.sha512WithRSAEncryption);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
index c9462a6..f2b5314 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
@@ -50,17 +50,34 @@
     private byte[] bigIntToBytes(
         BigInteger    r)
     {
+        //
+        // RFC 2631 (2.1.2) specifies that the secret should be padded with leading zeros if necessary
+        // must be the same length as p
+        //
+        int expectedLength = (p.bitLength() + 7) / 8;
+
         byte[]    tmp = r.toByteArray();
-        
-        if (tmp[0] == 0)
+
+        if (tmp.length == expectedLength)
         {
-            byte[]    ntmp = new byte[tmp.length - 1];
-            
-            System.arraycopy(tmp, 1, ntmp, 0, ntmp.length);
-            return ntmp;
+            return tmp;
         }
-        
-        return tmp;
+
+        if (tmp[0] == 0 && tmp.length == expectedLength + 1)
+        {
+            byte[]    rv = new byte[tmp.length - 1];
+            
+            System.arraycopy(tmp, 1, rv, 0, rv.length);
+            return rv;
+        }
+
+        // tmp must be shorter than expectedLength
+        // pad to the left with zeros.
+        byte[]    rv = new byte[expectedLength];
+
+        System.arraycopy(tmp, 0, rv, rv.length - tmp.length, tmp.length);
+
+        return rv;
     }
     
     protected Key engineDoPhase(
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
index c8b326f..bdda6a2 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
@@ -34,6 +34,9 @@
 // import org.bouncycastle.crypto.digests.SHA512Digest;
 // END android-removed
 import org.bouncycastle.crypto.params.ParametersWithRandom;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
+// END android-removed
 
 public class DSASigner
     extends SignatureSpi
@@ -228,21 +231,56 @@
     }
 
     // BEGIN android-removed
-    // static public class dsa224
+    // static public class detDSA
     //     extends DSASigner
     // {
-    //     public dsa224()
+    //     public detDSA()
     //     {
-    //         super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+    //         super(new SHA1Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA1Digest())));
     //     }
     // }
-    //
-    // static public class dsa256
+    // END android-removed
+
+    static public class dsa224
+        extends DSASigner
+    {
+        public dsa224()
+        {
+            // BEGIN android-changed
+            super(AndroidDigestFactory.getSHA224(), new org.bouncycastle.crypto.signers.DSASigner());
+            // END android-changed
+        }
+    }
+
+    // BEGIN android-removed
+    // static public class detDSA224
     //     extends DSASigner
     // {
-    //     public dsa256()
+    //     public detDSA224()
     //     {
-    //         super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+    //         super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA224Digest())));
+    //     }
+    // }
+    // END android-removed
+
+    static public class dsa256
+        extends DSASigner
+    {
+        public dsa256()
+        {
+            // BEGIN android-changed
+            super(AndroidDigestFactory.getSHA256(), new org.bouncycastle.crypto.signers.DSASigner());
+            // END android-changed
+        }
+    }
+
+    // BEGIN android-removed
+    // static public class detDSA256
+    //     extends DSASigner
+    // {
+    //     public detDSA256()
+    //     {
+    //         super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA256Digest())));
     //     }
     // }
     //
@@ -255,6 +293,15 @@
     //     }
     // }
     //
+    // static public class detDSA384
+    //     extends DSASigner
+    // {
+    //     public detDSA384()
+    //     {
+    //         super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA384Digest())));
+    //     }
+    // }
+    //
     // static public class dsa512
     //     extends DSASigner
     // {
@@ -263,6 +310,15 @@
     //         super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner());
     //     }
     // }
+    //
+    // static public class detDSA512
+    //     extends DSASigner
+    // {
+    //     public detDSA512()
+    //     {
+    //         super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA512Digest())));
+    //     }
+    // }
     // END android-removed
 
     static public class noneDSA
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
index 3d64c83..45d5b08 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
@@ -13,16 +13,11 @@
 
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Integer;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERInteger;
 import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-// BEGIN android-removed
-// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
-// END android-removed
 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
@@ -140,8 +135,8 @@
             this.ecSpec = new ECParameterSpec(
                             ellipticCurve,
                             new ECPoint(
-                                    dp.getG().getX().toBigInteger(),
-                                    dp.getG().getY().toBigInteger()),
+                                    dp.getG().getAffineXCoord().toBigInteger(),
+                                    dp.getG().getAffineYCoord().toBigInteger()),
                             dp.getN(),
                             dp.getH().intValue());
         }
@@ -173,22 +168,16 @@
             this.ecSpec = new ECParameterSpec(
                             ellipticCurve,
                             new ECPoint(
-                                    dp.getG().getX().toBigInteger(),
-                                    dp.getG().getY().toBigInteger()),
+                                    dp.getG().getAffineXCoord().toBigInteger(),
+                                    dp.getG().getAffineYCoord().toBigInteger()),
                             dp.getN(),
                             dp.getH().intValue());
         }
         else
         {
             EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
-            
-            this.ecSpec = new ECParameterSpec(
-                                ellipticCurve,
-                                new ECPoint(
-                                        spec.getG().getX().toBigInteger(),
-                                        spec.getG().getY().toBigInteger()),
-                                spec.getN(),
-                                spec.getH().intValue());
+
+            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
         }
 
         publicKey = getPublicKeyDetails(pubKey);
@@ -225,36 +214,16 @@
         {
             ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
             X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+            EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
 
-            // BEGIN android-removed
-            // if (ecP == null) // GOST Curve
-            // {
-            //     ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
-            //     EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
-            //
-            //     ecSpec = new ECNamedCurveSpec(
-            //             ECGOST3410NamedCurves.getName(oid),
-            //             ellipticCurve,
-            //             new ECPoint(
-            //                     gParam.getG().getX().toBigInteger(),
-            //                     gParam.getG().getY().toBigInteger()),
-            //             gParam.getN(),
-            //             gParam.getH());
-            // }
-            // else
-            // END android-removed
-            {
-                EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
-
-                ecSpec = new ECNamedCurveSpec(
-                        ECUtil.getCurveName(oid),
-                        ellipticCurve,
-                        new ECPoint(
-                                ecP.getG().getX().toBigInteger(),
-                                ecP.getG().getY().toBigInteger()),
-                        ecP.getN(),
-                        ecP.getH());
-            }
+            ecSpec = new ECNamedCurveSpec(
+                    ECUtil.getCurveName(oid),
+                    ellipticCurve,
+                    new ECPoint(
+                            ecP.getG().getAffineXCoord().toBigInteger(),
+                            ecP.getG().getAffineYCoord().toBigInteger()),
+                    ecP.getN(),
+                    ecP.getH());
         }
         else if (params.isImplicitlyCA())
         {
@@ -268,16 +237,16 @@
             this.ecSpec = new ECParameterSpec(
                 ellipticCurve,
                 new ECPoint(
-                        ecP.getG().getX().toBigInteger(),
-                        ecP.getG().getY().toBigInteger()),
+                        ecP.getG().getAffineXCoord().toBigInteger(),
+                        ecP.getG().getAffineYCoord().toBigInteger()),
                 ecP.getN(),
                 ecP.getH().intValue());
         }
 
         ASN1Encodable privKey = info.parsePrivateKey();
-        if (privKey instanceof DERInteger)
+        if (privKey instanceof ASN1Integer)
         {
-            DERInteger          derD = DERInteger.getInstance(privKey);
+            ASN1Integer          derD = ASN1Integer.getInstance(privKey);
 
             this.d = derD.getValue();
         }
@@ -317,11 +286,12 @@
 
         if (ecSpec instanceof ECNamedCurveSpec)
         {
-            DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+            ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
             if (curveOid == null)  // guess it's the OID
             {
-                curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+                curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
             }
+
             params = new X962Parameters(curveOid);
         }
         else if (ecSpec == null)
@@ -356,17 +326,7 @@
 
         try
         {
-            // BEGIN android-removed
-            // if (algorithm.equals("ECGOST3410"))
-            // {
-            //     info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive());
-            // }
-            // else
-            // END android-removed
-            {
-
-                info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
-            }
+            info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure);
 
             return info.getEncoded(ASN1Encoding.DER);
         }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
index 2b61727..0eaae1d 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
@@ -90,7 +90,7 @@
             {
                 org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa();
 
-                q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
+                q = s.getCurve().createPoint(q.getXCoord().toBigInteger(), q.getYCoord().toBigInteger(), false);
             }               
             this.ecSpec = null;
         }
@@ -188,8 +188,8 @@
         return new ECParameterSpec(
                 ellipticCurve,
                 new ECPoint(
-                        dp.getG().getX().toBigInteger(),
-                        dp.getG().getY().toBigInteger()),
+                        dp.getG().getAffineXCoord().toBigInteger(),
+                        dp.getG().getAffineYCoord().toBigInteger()),
                         dp.getN(),
                         dp.getH().intValue());
     }
@@ -212,8 +212,8 @@
                     ECUtil.getCurveName(oid),
                     ellipticCurve,
                     new ECPoint(
-                            ecP.getG().getX().toBigInteger(),
-                            ecP.getG().getY().toBigInteger()),
+                            ecP.getG().getAffineXCoord().toBigInteger(),
+                            ecP.getG().getAffineYCoord().toBigInteger()),
                     ecP.getN(),
                     ecP.getH());
         }
@@ -232,8 +232,8 @@
             this.ecSpec = new ECParameterSpec(
                     ellipticCurve,
                     new ECPoint(
-                            ecP.getG().getX().toBigInteger(),
-                            ecP.getG().getY().toBigInteger()),
+                            ecP.getG().getAffineXCoord().toBigInteger(),
+                            ecP.getG().getAffineYCoord().toBigInteger()),
                     ecP.getN(),
                     ecP.getH().intValue());
         }
@@ -310,8 +310,19 @@
         }
 
         ECCurve curve = this.engineGetQ().getCurve();
-        ASN1OctetString p = (ASN1OctetString)
-            new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).toASN1Primitive();
+        ASN1OctetString p;
+
+        // stored curve is null if ImplicitlyCa
+        if (ecSpec == null)
+        {
+            p = (ASN1OctetString)
+                new X9ECPoint(curve.createPoint(this.getQ().getXCoord().toBigInteger(), this.getQ().getYCoord().toBigInteger(), withCompression)).toASN1Primitive();
+        }
+        else
+        {
+            p = (ASN1OctetString)
+                            new X9ECPoint(curve.createPoint(this.getQ().getAffineXCoord().toBigInteger(), this.getQ().getAffineYCoord().toBigInteger(), withCompression)).toASN1Primitive();
+        }
 
         info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
 
@@ -351,7 +362,7 @@
 
     public ECPoint getW()
     {
-        return new ECPoint(q.getX().toBigInteger(), q.getY().toBigInteger());
+        return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
     }
 
     public org.bouncycastle.math.ec.ECPoint getQ()
@@ -360,11 +371,11 @@
         {
             if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp)
             {
-                return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY());
+                return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getAffineXCoord(), q.getAffineYCoord());
             }
             else
             {
-                return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY());
+                return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getAffineXCoord(), q.getAffineYCoord());
             }
         }
 
@@ -392,8 +403,8 @@
         String          nl = System.getProperty("line.separator");
 
         buf.append("EC Public Key").append(nl);
-        buf.append("            X: ").append(this.q.getX().toBigInteger().toString(16)).append(nl);
-        buf.append("            Y: ").append(this.q.getY().toBigInteger().toString(16)).append(nl);
+        buf.append("            X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
+        buf.append("            Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
 
         return buf.toString();
 
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
index 35a804c..ea36dfd 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
@@ -15,7 +15,7 @@
 import javax.crypto.ShortBufferException;
 import javax.crypto.spec.SecretKeySpec;
 
-import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.x9.X9IntegerConverter;
@@ -84,7 +84,7 @@
     private byte[] bigIntToBytes(
         BigInteger    r)
     {
-        return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getX()));
+        return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getAffineXCoord()));
     }
 
     protected KeyAgreementSpi(
@@ -197,10 +197,10 @@
         //     {
         //         throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
         //     }
-        //  
+        //     
         //     int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
         //
-        //     DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
+        //     DHKDFParameters params = new DHKDFParameters(new ASN1ObjectIdentifier(algorithm), keySize, secret);
         //
         //     byte[] keyBytes = new byte[keySize / 8];
         //     kdf.init(params);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
index c0c825c..42bb895 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
@@ -10,12 +10,7 @@
 import java.util.Hashtable;
 
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-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.ECNamedCurveTable;
 import org.bouncycastle.asn1.x9.X9ECParameters;
 import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
 import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
@@ -161,50 +156,22 @@
                     curveName = ((ECNamedCurveGenParameterSpec)params).getName();
                 }
 
-                X9ECParameters  ecP = X962NamedCurves.getByName(curveName);
+                X9ECParameters  ecP = ECNamedCurveTable.getByName(curveName);
                 if (ecP == null)
                 {
-                    ecP = SECNamedCurves.getByName(curveName);
-                    if (ecP == null)
+                    // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
+                    try
                     {
-                        ecP = NISTNamedCurves.getByName(curveName);
+                        ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(curveName);
+                        ecP = ECNamedCurveTable.getByOID(oid);
+                        if (ecP == null)
+                        {
+                            throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
+                        }
                     }
-                    // BEGIN android-removed
-                    // if (ecP == null)
-                    // {
-                    //     ecP = TeleTrusTNamedCurves.getByName(curveName);
-                    // }
-                    // END android-removed
-                    if (ecP == null)
+                    catch (IllegalArgumentException ex)
                     {
-                        // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
-                        try
-                        {
-                            ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(curveName);
-                            ecP = X962NamedCurves.getByOID(oid);
-                            if (ecP == null)
-                            {
-                                ecP = SECNamedCurves.getByOID(oid);
-                            }
-                            if (ecP == null)
-                            {
-                                ecP = NISTNamedCurves.getByOID(oid);
-                            }
-                            // BEGIN android-removed
-                            // if (ecP == null)
-                            // {
-                            //     ecP = TeleTrusTNamedCurves.getByOID(oid);
-                            // }
-                            // END android-removed
-                            if (ecP == null)
-                            {
-                                throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
-                            }
-                        }
-                        catch (IllegalArgumentException ex)
-                        {
-                            throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
-                        }
+                        throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
                     }
                 }
 
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
index c6b4bce..3757229 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
@@ -31,6 +31,7 @@
 import org.bouncycastle.crypto.signers.ECDSASigner;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.signers.ECNRSigner;
+// import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
 // END android-removed
 import org.bouncycastle.jcajce.provider.asymmetric.util.DSABase;
 import org.bouncycastle.jcajce.provider.asymmetric.util.DSAEncoder;
@@ -82,6 +83,17 @@
         }
     }
 
+    // BEGIN android-removed
+    // static public class ecDetDSA
+    //     extends SignatureSpi
+    // {
+    //     public ecDetDSA()
+    //     {
+    //         super(new SHA1Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA1Digest())), new StdDSAEncoder());
+    //     }
+    // }
+    // END android-removed
+
     static public class ecDSAnone
         extends SignatureSpi
     {
@@ -91,13 +103,24 @@
         }
     }
 
+    static public class ecDSA224
+        extends SignatureSpi
+    {
+        public ecDSA224()
+        {
+            // BEGIN android-changed
+            super(AndroidDigestFactory.getSHA224(), new ECDSASigner(), new StdDSAEncoder());
+            // END android-changed
+        }
+    }
+
     // BEGIN android-removed
-    // static public class ecDSA224
+    // static public class ecDetDSA224
     //     extends SignatureSpi
     // {
-    //     public ecDSA224()
+    //     public ecDetDSA224()
     //     {
-    //         super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
+    //         super(new SHA224Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA224Digest())), new StdDSAEncoder());
     //     }
     // }
     // END android-removed
@@ -113,6 +136,17 @@
         }
     }
 
+    // BEGIN android-removed
+    // static public class ecDetDSA256
+    //     extends SignatureSpi
+    // {
+    //     public ecDetDSA256()
+    //     {
+    //         super(new SHA256Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest())), new StdDSAEncoder());
+    //     }
+    // }
+    // END android-removed
+
     static public class ecDSA384
         extends SignatureSpi
     {
@@ -124,6 +158,17 @@
         }
     }
 
+    // BEGIN android-removed
+    // static public class ecDetDSA384
+    //     extends SignatureSpi
+    // {
+    //     public ecDetDSA384()
+    //     {
+    //         super(new SHA384Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA384Digest())), new StdDSAEncoder());
+    //     }
+    // }
+    // END android-removed
+
     static public class ecDSA512
         extends SignatureSpi
     {
@@ -136,6 +181,15 @@
     }
 
     // BEGIN android-removed
+    // static public class ecDetDSA512
+    //     extends SignatureSpi
+    // {
+    //     public ecDetDSA512()
+    //     {
+    //         super(new SHA512Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA512Digest())), new StdDSAEncoder());
+    //     }
+    // }
+    //
     // static public class ecDSARipeMD160
     //     extends SignatureSpi
     // {
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
index ce0e603..a2114fa 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
@@ -1,6 +1,9 @@
 package org.bouncycastle.jcajce.provider.asymmetric.rsa;
 
 import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OptionalDataException;
 import java.math.BigInteger;
 import java.security.interfaces.RSAPublicKey;
 import java.security.spec.RSAPublicKeySpec;
@@ -15,14 +18,18 @@
 public class BCRSAPublicKey
     implements RSAPublicKey
 {
+    private static final AlgorithmIdentifier DEFAULT_ALGORITHM_IDENTIFIER = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
+
     static final long serialVersionUID = 2675817738516720772L;
-    
+
     private BigInteger modulus;
     private BigInteger publicExponent;
+    private transient AlgorithmIdentifier algorithmIdentifier;
 
     BCRSAPublicKey(
         RSAKeyParameters key)
     {
+        this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
         this.modulus = key.getModulus();
         this.publicExponent = key.getExponent();
     }
@@ -30,6 +37,7 @@
     BCRSAPublicKey(
         RSAPublicKeySpec spec)
     {
+        this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
         this.modulus = spec.getModulus();
         this.publicExponent = spec.getPublicExponent();
     }
@@ -37,6 +45,7 @@
     BCRSAPublicKey(
         RSAPublicKey key)
     {
+        this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
         this.modulus = key.getModulus();
         this.publicExponent = key.getPublicExponent();
     }
@@ -44,10 +53,16 @@
     BCRSAPublicKey(
         SubjectPublicKeyInfo info)
     {
+        populateFromPublicKeyInfo(info);
+    }
+
+    private void populateFromPublicKeyInfo(SubjectPublicKeyInfo info)
+    {
         try
         {
             org.bouncycastle.asn1.pkcs.RSAPublicKey  pubKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(info.parsePublicKey());
 
+            this.algorithmIdentifier = info.getAlgorithm();
             this.modulus = pubKey.getModulus();
             this.publicExponent = pubKey.getPublicExponent();
         }
@@ -89,7 +104,7 @@
 
     public byte[] getEncoded()
     {
-        return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent()));
+        return KeyUtil.getEncodedSubjectPublicKeyInfo(algorithmIdentifier, new org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent()));
     }
 
     public int hashCode()
@@ -126,4 +141,32 @@
 
         return buf.toString();
     }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        try
+        {
+            algorithmIdentifier = AlgorithmIdentifier.getInstance(in.readObject());
+        }
+        catch (OptionalDataException e)
+        {
+            algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+        }
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        if (!algorithmIdentifier.equals(DEFAULT_ALGORITHM_IDENTIFIER))
+        {
+            out.writeObject(algorithmIdentifier.getEncoded());
+        }
+    }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
index d0a60f6..ae40cbe 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -217,12 +217,10 @@
         {
             initFromSpec(OAEPParameterSpec.DEFAULT);
         }
-        // BEGIN android-removed
-        // else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-224ANDMGF1PADDING"))
-        // {
-        //     initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), PSource.PSpecified.DEFAULT));
-        // }
-        // END android-removed
+        else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-224ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), PSource.PSpecified.DEFAULT));
+        }
         else if (pad.equals("OAEPWITHSHA256ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-256ANDMGF1PADDING"))
         {
             initFromSpec(new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
index a1bdc65..13f7c93 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
@@ -274,16 +274,16 @@
         }
     }
 
-    // BEGIN android-removed
-    // static public class SHA224
-    //     extends DigestSignatureSpi
-    // {
-    //     public SHA224()
-    //     {
-    //         super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine()));
-    //     }
-    // }
-    // END android-removed
+    static public class SHA224
+        extends DigestSignatureSpi
+    {
+        public SHA224()
+        {
+            // BEGIN android-changed
+            super(NISTObjectIdentifiers.id_sha224, AndroidDigestFactory.getSHA224(), new PKCS1Encoding(new RSABlindedEngine()));
+            // END android-changed
+        }
+    }
 
     static public class SHA256
         extends DigestSignatureSpi
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java
index d4065ac..5eea1b9 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java
@@ -74,8 +74,8 @@
                 ((ECNamedCurveParameterSpec)spec).getName(),
                 ellipticCurve,
                 new ECPoint(
-                    spec.getG().getX().toBigInteger(),
-                    spec.getG().getY().toBigInteger()),
+                    spec.getG().getAffineXCoord().toBigInteger(),
+                    spec.getG().getAffineYCoord().toBigInteger()),
                 spec.getN(),
                 spec.getH());
         }
@@ -84,8 +84,8 @@
             return new ECParameterSpec(
                 ellipticCurve,
                 new ECPoint(
-                    spec.getG().getX().toBigInteger(),
-                    spec.getG().getY().toBigInteger()),
+                    spec.getG().getAffineXCoord().toBigInteger(),
+                    spec.getG().getAffineYCoord().toBigInteger()),
                 spec.getN(),
                 spec.getH().intValue());
         }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
index 1888328..32e595c 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
@@ -31,7 +31,7 @@
  * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
  * (critical)
  */
-class X509CRLEntryObject extends X509CRLEntry
+public class X509CRLEntryObject extends X509CRLEntry
 {
     private TBSCertList.CRLEntry c;
 
@@ -39,7 +39,7 @@
     private int           hashValue;
     private boolean       isHashValueSet;
 
-    public X509CRLEntryObject(TBSCertList.CRLEntry c)
+    protected X509CRLEntryObject(TBSCertList.CRLEntry c)
     {
         this.c = c;
         this.certificateIssuer = null;
@@ -62,7 +62,7 @@
      * @param previousCertificateIssuer
      *            Certificate issuer of the previous CRLEntry.
      */
-    public X509CRLEntryObject(
+    protected X509CRLEntryObject(
         TBSCertList.CRLEntry c,
         boolean isIndirect,
         X500Name previousCertificateIssuer)
@@ -211,6 +211,23 @@
         return hashValue;
     }
 
+    public boolean equals(Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (o instanceof X509CRLEntryObject)
+        {
+            X509CRLEntryObject other = (X509CRLEntryObject)o;
+
+            return this.c.equals(other.c);
+        }
+
+        return super.equals(this);
+    }
+
     public byte[] getEncoded()
         throws CRLException
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
index 2fc0826..c7d0402 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
@@ -54,13 +54,15 @@
  * Delta CRL Indicator (critical)
  * Issuing Distribution Point (critical)
  */
-class X509CRLObject
+public class X509CRLObject
     extends X509CRL
 {
     private CertificateList c;
     private String sigAlgName;
     private byte[] sigAlgParams;
     private boolean isIndirect;
+    private boolean isHashCodeSet = false;
+    private int     hashCodeValue;
 
     static boolean isIndirectCRL(X509CRL crl)
         throws CRLException
@@ -78,7 +80,7 @@
         }
     }
 
-    public X509CRLObject(
+    protected X509CRLObject(
         CertificateList c)
         throws CRLException
     {
@@ -522,19 +524,21 @@
             throw new RuntimeException("X.509 CRL used with non X.509 Cert");
         }
 
-        TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
+        Enumeration certs = c.getRevokedCertificateEnumeration();
 
         X500Name caName = c.getIssuer();
 
-        if (certs != null)
+        if (certs.hasMoreElements())
         {
             BigInteger serial = ((X509Certificate)cert).getSerialNumber();
 
-            for (int i = 0; i < certs.length; i++)
+            while (certs.hasMoreElements())
             {
-                if (isIndirect && certs[i].hasExtensions())
+                TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement());
+
+                if (isIndirect && entry.hasExtensions())
                 {
-                    Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer);
+                    Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
 
                     if (currentCaName != null)
                     {
@@ -542,7 +546,7 @@
                     }
                 }
 
-                if (certs[i].getUserCertificate().getValue().equals(serial))
+                if (entry.getUserCertificate().getValue().equals(serial))
                 {
                     X500Name issuer;
 
@@ -574,5 +578,50 @@
 
         return false;
     }
+
+    public boolean equals(Object other)
+    {
+        if (this == other)
+        {
+            return true;
+        }
+
+        if (!(other instanceof X509CRL))
+        {
+            return false;
+        }
+
+        if (other instanceof X509CRLObject)
+        {
+            X509CRLObject crlObject = (X509CRLObject)other;
+
+            if (isHashCodeSet)
+            {
+                boolean otherIsHashCodeSet = crlObject.isHashCodeSet;
+                if (otherIsHashCodeSet)
+                {
+                    if (crlObject.hashCodeValue != hashCodeValue)
+                    {
+                        return false;
+                    }
+                }
+            }
+
+            return this.c.equals(crlObject.c);
+        }
+
+        return super.equals(other);
+    }
+
+    public int hashCode()
+    {
+        if (!isHashCodeSet)
+        {
+            isHashCodeSet = true;
+            hashCodeValue = super.hashCode();
+        }
+
+        return hashCodeValue;
+    }
 }
 
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
index df5d41a..c7502c7 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
@@ -193,7 +193,6 @@
 
             provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACSHA1", PREFIX + "$PBEWithMacKeyFactory");
             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1", PREFIX + "$PBKDF2WithHmacSHA1UTF8");
-            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2WithHmacSHA1");
             provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WithHmacSHA1AndUTF8", "PBKDF2WithHmacSHA1");
             provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1And8BIT", PREFIX + "$PBKDF2WithHmacSHA18BIT");
         }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java
new file mode 100644
index 0000000..ba06a0f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA224.java
@@ -0,0 +1,76 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class SHA224
+{
+    private SHA224()
+    {
+
+    }
+
+    static public class Digest
+        extends BCMessageDigest
+        implements Cloneable
+    {
+        public Digest()
+        {
+            super(new SHA224Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            Digest d = (Digest)super.clone();
+            d.digest = new SHA224Digest((SHA224Digest)digest);
+
+            return d;
+        }
+    }
+
+    public static class HashMac
+        extends BaseMac
+    {
+        public HashMac()
+        {
+            super(new HMac(new SHA224Digest()));
+        }
+    }
+
+    public static class KeyGenerator
+        extends BaseKeyGenerator
+    {
+        public KeyGenerator()
+        {
+            super("HMACSHA224", 224, new CipherKeyGenerator());
+        }
+    }
+
+    public static class Mappings
+        extends DigestAlgorithmProvider
+    {
+        private static final String PREFIX = SHA224.class.getName();
+
+        public Mappings()
+        {
+        }
+
+        public void configure(ConfigurableProvider provider)
+        {
+            provider.addAlgorithm("MessageDigest.SHA-224", PREFIX + "$Digest");
+            provider.addAlgorithm("Alg.Alias.MessageDigest.SHA224", "SHA-224");
+            provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha224, "SHA-224");
+
+            addHMACAlgorithm(provider, "SHA224", PREFIX + "$HashMac",  PREFIX + "$KeyGenerator");
+            addHMACAlias(provider, "SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
+
+        }
+    }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
index 0d4f0ad..24dac19 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -6,6 +6,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
 import java.security.Key;
 import java.security.KeyStore;
 import java.security.KeyStore.LoadStoreParameter;
@@ -24,13 +26,18 @@
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Map;
 import java.util.Vector;
 
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.IvParameterSpec;
@@ -54,6 +61,12 @@
 import org.bouncycastle.asn1.DEROutputStream;
 import org.bouncycastle.asn1.DERSequence;
 import org.bouncycastle.asn1.DERSet;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// import org.bouncycastle.asn1.cryptopro.GOST28147Parameters;
+// END android-removed
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
 import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
 import org.bouncycastle.asn1.pkcs.CertBag;
 import org.bouncycastle.asn1.pkcs.ContentInfo;
@@ -75,12 +88,16 @@
 import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
 import org.bouncycastle.jcajce.provider.config.PKCS12StoreParameter;
 import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
-import org.bouncycastle.jcajce.provider.util.SecretKeyUtil;
+// BEGIN android-removed
+// import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
+// END android-removed
+import org.bouncycastle.jcajce.spec.PBKDF2KeySpec;
 import org.bouncycastle.jce.interfaces.BCKeyStore;
 import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.jce.provider.JDKPKCS12StoreParameter;
 import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Integers;
 import org.bouncycastle.util.Strings;
 import org.bouncycastle.util.encoders.Hex;
 
@@ -92,6 +109,7 @@
     private static final int MIN_ITERATIONS = 1024;
 
     private static final Provider bcProvider = new BouncyCastleProvider();
+    private static final DefaultSecretKeyProvider keySizeProvider = new DefaultSecretKeyProvider();
 
     private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
     private Hashtable localIds = new Hashtable();
@@ -593,16 +611,8 @@
             }
             else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
             {
-                PBES2Parameters alg = PBES2Parameters.getInstance(algId.getParameters());
-                PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
 
-                SecretKeyFactory keyFact = SecretKeyFactory.getInstance(alg.getKeyDerivationFunc().getAlgorithm().getId(), bcProvider);
-
-                SecretKey k = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), SecretKeyUtil.getKeySize(alg.getEncryptionScheme().getAlgorithm())));
-
-                Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId(), bcProvider);
-
-                cipher.init(Cipher.UNWRAP_MODE, k, new IvParameterSpec(ASN1OctetString.getInstance(alg.getEncryptionScheme().getParameters()).getOctets()));
+                Cipher cipher = createCipher(Cipher.UNWRAP_MODE, password, algId);
 
                 // we pass "" as the key algorithm type as it is unknown at this point
                 return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
@@ -656,29 +666,90 @@
         byte[] data)
         throws IOException
     {
-        String algorithm = algId.getAlgorithm().getId();
-        PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
-        PBEKeySpec pbeSpec = new PBEKeySpec(password);
+        ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
 
-        try
+        if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
         {
-            SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, bcProvider);
-            PBEParameterSpec defParams = new PBEParameterSpec(
-                pbeParams.getIV(),
-                pbeParams.getIterations().intValue());
-            BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
+            PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+            PBEKeySpec pbeSpec = new PBEKeySpec(password);
 
-            key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
+            try
+            {
+                SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm.getId(), bcProvider);
+                PBEParameterSpec defParams = new PBEParameterSpec(
+                    pbeParams.getIV(),
+                    pbeParams.getIterations().intValue());
+                BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
 
-            Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
-            int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
-            cipher.init(mode, key, defParams);
-            return cipher.doFinal(data);
+                key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+                Cipher cipher = Cipher.getInstance(algorithm.getId(), bcProvider);
+                int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+                cipher.init(mode, key, defParams);
+                return cipher.doFinal(data);
+            }
+            catch (Exception e)
+            {
+                throw new IOException("exception decrypting data - " + e.toString());
+            }
         }
-        catch (Exception e)
+        else  if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
         {
-            throw new IOException("exception decrypting data - " + e.toString());
+            try
+            {
+                Cipher cipher = createCipher(Cipher.DECRYPT_MODE, password, algId);
+
+                return cipher.doFinal(data);
+            }
+            catch (Exception e)
+            {
+                throw new IOException("exception decrypting data - " + e.toString());
+            }
         }
+        else
+        {
+            throw new IOException("unknown PBE algorithm: " + algorithm);
+        }
+    }
+
+    private Cipher createCipher(int mode, char[] password, AlgorithmIdentifier algId)
+        throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        PBES2Parameters alg = PBES2Parameters.getInstance(algId.getParameters());
+        PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
+        AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
+
+        SecretKeyFactory keyFact = SecretKeyFactory.getInstance(alg.getKeyDerivationFunc().getAlgorithm().getId(), bcProvider);
+        SecretKey key;
+
+        if (func.isDefaultPrf())
+        {
+            key = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme)));
+        }
+        else
+        {
+            key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme), func.getPrf()));
+        }
+
+        Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId());
+
+        AlgorithmIdentifier encryptionAlg = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
+
+        ASN1Encodable encParams = alg.getEncryptionScheme().getParameters();
+        if (encParams instanceof ASN1OctetString)
+        {
+            cipher.init(mode, key, new IvParameterSpec(ASN1OctetString.getInstance(encParams).getOctets()));
+        }
+        // BEGIN android-removed
+        // else
+        // {
+        //     // TODO: at the moment it's just GOST, but...
+        //     GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams);
+        //
+        //     cipher.init(mode, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV()));
+        // }
+        // END android-removed
+        return cipher;
     }
 
     public void engineLoad(
@@ -1673,4 +1744,45 @@
             return orig.elements();
         }
     }
+
+    private static class DefaultSecretKeyProvider
+    {
+        private final Map KEY_SIZES;
+
+        DefaultSecretKeyProvider()
+        {
+            Map keySizes = new HashMap();
+
+            keySizes.put(new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"), Integers.valueOf(128));
+
+            keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192));
+
+            keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128));
+            keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192));
+            keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256));
+
+            keySizes.put(NTTObjectIdentifiers.id_camellia128_cbc, Integers.valueOf(128));
+            keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192));
+            keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256));
+
+            // BEGIN android-removed
+            // keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256));
+            // END android-removed
+
+            KEY_SIZES = Collections.unmodifiableMap(keySizes);
+        }
+
+        public int getKeySize(AlgorithmIdentifier algorithmIdentifier)
+        {
+            // TODO: not all ciphers/oid relationships are this simple.
+            Integer keySize = (Integer)KEY_SIZES.get(algorithmIdentifier.getAlgorithm());
+
+            if (keySize != null)
+            {
+                return keySize.intValue();
+            }
+
+            return -1;
+        }
+    }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
index f561b8a..500bf2d 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
@@ -1,17 +1,22 @@
 package org.bouncycastle.jcajce.provider.symmetric;
 
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
 // BEGIN android-removed
 // import java.security.AlgorithmParameters;
 // import java.security.InvalidAlgorithmParameterException;
 // END android-removed
 import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
 // BEGIN android-removed
-// import java.security.spec.AlgorithmParameterSpec;
-//
 // import javax.crypto.spec.IvParameterSpec;
 // END android-removed
 
 import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
+import org.bouncycastle.asn1.cms.GCMParameters;
 import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
 import org.bouncycastle.crypto.BlockCipher;
 import org.bouncycastle.crypto.BufferedBlockCipher;
@@ -20,6 +25,7 @@
 import org.bouncycastle.crypto.engines.AESWrapEngine;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+// import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
 // import org.bouncycastle.crypto.macs.CMac;
 // import org.bouncycastle.crypto.macs.GMac;
 // END android-removed
@@ -31,6 +37,7 @@
 // BEGIN android-removed
 // import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
 // END android-removed
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
 import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
 import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
 // BEGIN android-removed
@@ -43,9 +50,12 @@
 // BEGIN android-removed
 // import org.bouncycastle.jce.provider.BouncyCastleProvider;
 // END android-removed
+import org.bouncycastle.util.Integers;
 
 public final class AES
 {
+    private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec");
+
     private AES()
     {
     }
@@ -92,6 +102,15 @@
         }
     }
 
+    static public class GCM
+        extends BaseBlockCipher
+    {
+        public GCM()
+        {
+            super(new GCMBlockCipher(new AESFastEngine()));
+        }
+    }
+
     // BEGIN android-removed
     // public static class AESCMAC
     //     extends BaseMac
@@ -110,6 +129,24 @@
     //         super(new GMac(new GCMBlockCipher(new AESFastEngine())));
     //     }
     // }
+    //
+    // public static class Poly1305
+    //     extends BaseMac
+    // {
+    //     public Poly1305()
+    //     {
+    //         super(new org.bouncycastle.crypto.macs.Poly1305(new AESFastEngine()));
+    //     }
+    // }
+    //
+    // public static class Poly1305KeyGen
+    //     extends BaseKeyGenerator
+    // {
+    //     public Poly1305KeyGen()
+    //     {
+    //         super("Poly1305-AES", 256, new Poly1305KeyGenerator());
+    //     }
+    // }
     // END android-removed
 
     static public class Wrap
@@ -345,6 +382,95 @@
         }
     }
 
+    public static class AlgParamsGCM
+        extends BaseAlgorithmParameters
+    {
+        private GCMParameters gcmParams;
+
+        protected void engineInit(AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (gcmSpecClass != null)
+            {
+                try
+                {
+                    Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
+                    Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
+
+
+                    gcmParams = new GCMParameters((byte[])iv.invoke(paramSpec, new Object[0]), ((Integer)tLen.invoke(paramSpec, new Object[0])).intValue());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidParameterSpecException("Cannot process GCMParameterSpec.");
+                }
+            }
+        }
+
+        protected void engineInit(byte[] params)
+            throws IOException
+        {
+            gcmParams = GCMParameters.getInstance(params);
+        }
+
+        protected void engineInit(byte[] params, String format)
+            throws IOException
+        {
+            if (!isASN1FormatString(format))
+            {
+                throw new IOException("unknown format specified");
+            }
+
+            gcmParams = GCMParameters.getInstance(params);
+        }
+
+        protected byte[] engineGetEncoded()
+            throws IOException
+        {
+            return gcmParams.getEncoded();
+        }
+
+        protected byte[] engineGetEncoded(String format)
+            throws IOException
+        {
+            if (!isASN1FormatString(format))
+            {
+                throw new IOException("unknown format specified");
+            }
+
+            return gcmParams.getEncoded();
+        }
+
+        protected String engineToString()
+        {
+            return "GCM";
+        }
+
+        protected AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+            throws InvalidParameterSpecException
+        {
+            if (gcmSpecClass != null)
+            {
+                try
+                {
+                    Constructor constructor = gcmSpecClass.getConstructor(new Class[] { byte[].class, Integer.class });
+
+                    return (AlgorithmParameterSpec)constructor.newInstance(new Object[] { gcmParams.getNonce(), Integers.valueOf(gcmParams.getIcvLen()) });
+                }
+                catch (NoSuchMethodException e)
+                {
+                    throw new InvalidParameterSpecException("no constructor found!");   // should never happen
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidParameterSpecException("construction failed: " + e.getMessage());   // should never happen
+                }
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec: " + paramSpec.getName());
+        }
+    }
+
     public static class Mappings
         extends SymmetricAlgorithmProvider
     {
@@ -373,6 +499,11 @@
             provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
             provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
 
+            provider.addAlgorithm("AlgorithmParameters.GCM", PREFIX + "$AlgParamsGCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_GCM, "GCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_GCM, "GCM");
+            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_GCM, "GCM");
+
             // BEGIN android-removed
             // provider.addAlgorithm("AlgorithmParameterGenerator.AES", PREFIX + "$AlgParamGen");
             // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
@@ -409,6 +540,11 @@
             // provider.addAlgorithm("Cipher.AESRFC3211WRAP", PREFIX + "$RFC3211Wrap");
             // END android-removed
 
+            provider.addAlgorithm("Cipher.GCM", PREFIX + "$GCM");
+            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_GCM, "GCM");
+            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_GCM, "GCM");
+            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_GCM, "GCM");
+
             provider.addAlgorithm("KeyGenerator.AES", PREFIX + "$KeyGen");
             // BEGIN android-removed
             // provider.addAlgorithm("KeyGenerator." + wrongAES128, PREFIX + "$KeyGen128");
@@ -513,7 +649,22 @@
 
             // BEGIN android-removed
             // addGMacAlgorithm(provider, "AES", PREFIX + "$AESGMAC", PREFIX + "$KeyGen128");
+            // addPoly1305Algorithm(provider, "AES", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
             // END android-removed
         }
     }
+
+    private static Class lookup(String className)
+    {
+        try
+        {
+            Class def = AES.class.getClassLoader().loadClass(className);
+
+            return def;
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
index d96d5e6..fc34865 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
@@ -19,5 +19,18 @@
     //     provider.addAlgorithm("KeyGenerator." + algorithm + "-GMAC", keyGeneratorClassName);
     //     provider.addAlgorithm("Alg.Alias.KeyGenerator." + algorithm + "GMAC",  algorithm + "-GMAC");
     // }
+    //
+    // protected void addPoly1305Algorithm(ConfigurableProvider provider,
+    //                                     String algorithm,
+    //                                     String algorithmClassName,
+    //                                     String keyGeneratorClassName)
+    // {
+    //     provider.addAlgorithm("Mac.POLY1305-" + algorithm, algorithmClassName);
+    //     provider.addAlgorithm("Alg.Alias.Mac.POLY1305" + algorithm, "POLY1305-" + algorithm);
+    //
+    //     provider.addAlgorithm("KeyGenerator.POLY1305-" + algorithm, keyGeneratorClassName);
+    //     provider.addAlgorithm("Alg.Alias.KeyGenerator.POLY1305" + algorithm, "POLY1305-" + algorithm);
+    // }
     // END android-removed
+
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
index dafdc39..e2b2efd 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
@@ -6,6 +6,7 @@
 // END android-removed
 import org.bouncycastle.crypto.engines.TwofishEngine;
 // BEGIN android-removed
+// import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
 // import org.bouncycastle.crypto.macs.GMac;
 // END android-removed
 import org.bouncycastle.crypto.modes.CBCBlockCipher;
@@ -61,6 +62,24 @@
     //         super(new GMac(new GCMBlockCipher(new TwofishEngine())));
     //     }
     // }
+    //
+    // public static class Poly1305
+    //     extends BaseMac
+    // {
+    //     public Poly1305()
+    //     {
+    //         super(new org.bouncycastle.crypto.macs.Poly1305(new TwofishEngine()));
+    //     }
+    // }
+    //
+    // public static class Poly1305KeyGen
+    //     extends BaseKeyGenerator
+    // {
+    //     public Poly1305KeyGen()
+    //     {
+    //         super("Poly1305-Twofish", 256, new Poly1305KeyGenerator());
+    //     }
+    // }
     // END android-removed
 
     /**
@@ -122,6 +141,7 @@
 
             // BEGIN android-removed
             // addGMacAlgorithm(provider, "Twofish", PREFIX + "$GMAC", PREFIX + "$KeyGen");
+            // addPoly1305Algorithm(provider, "Twofish", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
             // END android-removed
         }
     }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
index d342775..5b85ef5 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
@@ -1,5 +1,7 @@
 package org.bouncycastle.jcajce.provider.symmetric.util;
 
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
 import java.security.AlgorithmParameters;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -22,6 +24,7 @@
 // import javax.crypto.spec.RC5ParameterSpec;
 // END android-removed
 
+import org.bouncycastle.asn1.cms.GCMParameters;
 import org.bouncycastle.crypto.BlockCipher;
 import org.bouncycastle.crypto.BufferedBlockCipher;
 import org.bouncycastle.crypto.CipherParameters;
@@ -35,6 +38,7 @@
 import org.bouncycastle.crypto.modes.CTSBlockCipher;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.modes.EAXBlockCipher;
+// import org.bouncycastle.crypto.modes.GCFBBlockCipher;
 // END android-removed
 import org.bouncycastle.crypto.modes.GCMBlockCipher;
 // BEGIN android-removed
@@ -54,6 +58,7 @@
 import org.bouncycastle.crypto.paddings.TBCPadding;
 import org.bouncycastle.crypto.paddings.X923Padding;
 import org.bouncycastle.crypto.paddings.ZeroBytePadding;
+import org.bouncycastle.crypto.params.AEADParameters;
 import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithIV;
 import org.bouncycastle.crypto.params.ParametersWithRandom;
@@ -63,18 +68,18 @@
 import org.bouncycastle.crypto.params.RC2Parameters;
 // BEGIN android-removed
 // import org.bouncycastle.crypto.params.RC5Parameters;
+// import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
+// import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec;
 // END android-removed
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
-// BEGIN android-removed
-// import org.bouncycastle.jce.spec.GOST28147ParameterSpec;
-// END android-removed
-import org.bouncycastle.jce.spec.RepeatedSecretKeySpec;
 import org.bouncycastle.util.Strings;
 
 public class BaseBlockCipher
     extends BaseWrapCipher
     implements PBE
 {
+    private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec");
+
     //
     // specs we can handle.
     //
@@ -87,14 +92,16 @@
                                         IvParameterSpec.class,
                                         PBEParameterSpec.class,
                                         // BEGIN android-removed
-                                        // GOST28147ParameterSpec.class
+                                        // GOST28147ParameterSpec.class,
                                         // END android-removed
+                                        gcmSpecClass
                                     };
 
     private BlockCipher             baseEngine;
     private BlockCipherProvider     engineProvider;
     private GenericBlockCipher      cipher;
     private ParametersWithIV        ivParam;
+    private AEADParameters          aeadParams;
 
     private int                     ivLength = 0;
 
@@ -105,6 +112,20 @@
 
     private String                  modeName = null;
 
+    private static Class lookup(String className)
+    {
+        try
+        {
+            Class def = BaseBlockCipher.class.getClassLoader().loadClass(className);
+
+            return def;
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
     protected BaseBlockCipher(
         BlockCipher engine)
     {
@@ -123,6 +144,14 @@
     }
 
     protected BaseBlockCipher(
+        AEADBlockCipher engine)
+    {
+        baseEngine = engine.getUnderlyingCipher();
+        ivLength = baseEngine.getBlockSize();
+        cipher = new AEADGenericBlockCipher(engine);
+    }
+
+    protected BaseBlockCipher(
         org.bouncycastle.crypto.BlockCipher engine,
         int ivLength)
     {
@@ -149,6 +178,11 @@
 
     protected byte[] engineGetIV()
     {
+        // BEGIN android-added
+        if (aeadParams != null) {
+            return aeadParams.getNonce();
+        }
+        // END android-added
         return (ivParam != null) ? ivParam.getIV() : null;
     }
 
@@ -199,6 +233,18 @@
                     throw new RuntimeException(e.toString());
                 }
             }
+            else if (aeadParams != null)
+            {
+                try
+                {
+                    engineParams = AlgorithmParameters.getInstance("GCM", BouncyCastleProvider.PROVIDER_NAME);
+                    engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize()).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
         }
 
         return engineParams;
@@ -257,7 +303,7 @@
         // else if (modeName.startsWith("PGP"))
         // {
         //     boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
-
+        //
         //     ivLength = baseEngine.getBlockSize();
         //     cipher = new BufferedGenericBlockCipher(
         //         new PGPCFBBlockCipher(baseEngine, inlineIV));
@@ -268,17 +314,17 @@
         //     cipher = new BufferedGenericBlockCipher(
         //         new OpenPGPCFBBlockCipher(baseEngine));
         // }
+        // else if (modeName.startsWith("SIC"))
+        // {
+        //     ivLength = baseEngine.getBlockSize();
+        //     if (ivLength < 16)
+        //     {
+        //         throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
+        //     }
+        //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+        //                 new SICBlockCipher(baseEngine)));
+        // }
         // END android-removed
-        else if (modeName.startsWith("SIC"))
-        {
-            ivLength = baseEngine.getBlockSize();
-            if (ivLength < 16)
-            {
-                throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
-            }
-            cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
-                        new SICBlockCipher(baseEngine)));
-        }
         else if (modeName.startsWith("CTR"))
         {
             ivLength = baseEngine.getBlockSize();
@@ -292,6 +338,12 @@
         //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
         //                 new GOFBBlockCipher(baseEngine)));
         // }
+        // else if (modeName.startsWith("GCFB"))
+        // {
+        //     ivLength = baseEngine.getBlockSize();
+        //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+        //                 new GCFBBlockCipher(baseEngine)));
+        // }
         // END android-removed
         else if (modeName.startsWith("CTS"))
         {
@@ -300,7 +352,7 @@
         }
         else if (modeName.startsWith("CCM"))
         {
-            ivLength = baseEngine.getBlockSize();
+            ivLength = 13; // CCM nonce 7..13 bytes
             cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
         }
         // BEGIN android-removed
@@ -308,7 +360,8 @@
         // {
         //     if (engineProvider != null)
         //     {
-        //         ivLength = baseEngine.getBlockSize();
+        //         // Nonce restricted to max 120 bits over 128 bit block cipher since draft-irtf-cfrg-ocb-03
+        //         ivLength = 15;
         //         cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get()));
         //     }
         //     else
@@ -401,6 +454,7 @@
         this.pbeSpec = null;
         this.pbeAlgorithm = null;
         this.engineParams = null;
+        this.aeadParams = null;
 
         //
         // basic key check
@@ -443,6 +497,20 @@
 
                     param = new ParametersWithIV(param, iv.getIV());
                 }
+                // BEGIN android-removed
+                // else if (params instanceof GOST28147ParameterSpec)
+                // {
+                //     // need to pick up IV and SBox.
+                //     GOST28147ParameterSpec    gost28147Param = (GOST28147ParameterSpec)params;
+                //
+                //     param = new ParametersWithSBox(param, gost28147Param.getSbox());
+                //
+                //     if (gost28147Param.getIV() != null && ivLength != 0)
+                //     {
+                //         param = new ParametersWithIV(param, gost28147Param.getIV());
+                //     }
+                // }
+                // END android-removed
             }
             else if (params instanceof PBEParameterSpec)
             {
@@ -474,12 +542,14 @@
                     throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
                 }
 
-                if (key instanceof RepeatedSecretKeySpec)
-                {
-                    param = new ParametersWithIV(null, p.getIV());
-                    ivParam = (ParametersWithIV)param;
-                }
-                else
+                // BEGIN android-removed
+                // if (key instanceof RepeatedSecretKeySpec)
+                // {
+                //     param = new ParametersWithIV(null, p.getIV());
+                //     ivParam = (ParametersWithIV)param;
+                // }
+                // else
+                // END android-removed
                 {
                     param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
                     ivParam = (ParametersWithIV)param;
@@ -554,12 +624,40 @@
         //     }
         // }
         // END android-removed
+        else if (gcmSpecClass != null && gcmSpecClass.isInstance(params))
+        {
+            if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher))
+            {
+                throw new InvalidAlgorithmParameterException("GCMParameterSpec can only be used with AEAD modes.");
+            }
+
+            try
+            {
+                Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
+                Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
+
+                // BEGIN android-removed
+                // if (key instanceof RepeatedSecretKeySpec)
+                // {
+                //     param = aeadParams = new AEADParameters(null, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+                // }
+                // else
+                // END android-removed
+                {
+                    param = aeadParams = new AEADParameters(new KeyParameter(key.getEncoded()), ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+                }
+            }
+            catch (Exception e)
+            {
+                throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec.");
+            }
+        }
         else
         {
             throw new InvalidAlgorithmParameterException("unknown parameter type.");
         }
 
-        if ((ivLength != 0) && !(param instanceof ParametersWithIV))
+        if ((ivLength != 0) && !(param instanceof ParametersWithIV) && !(param instanceof AEADParameters))
         {
             SecureRandom    ivRandom = random;
 
@@ -622,6 +720,11 @@
         {
             for (int i = 0; i != availableSpecs.length; i++)
             {
+                if (availableSpecs[i] == null)
+                {
+                    continue;
+                }
+
                 try
                 {
                     paramSpec = params.getParameterSpec(availableSpecs[i]);
@@ -660,6 +763,18 @@
         }
     }
 
+    protected void engineUpdateAAD(byte[] input, int offset, int length)
+    {
+        cipher.updateAAD(input, offset, length);
+    }
+
+    protected void engineUpdateAAD(ByteBuffer bytebuffer)
+    {
+        int offset = bytebuffer.arrayOffset() + bytebuffer.position();
+        int length = bytebuffer.limit() - bytebuffer.position();
+        engineUpdateAAD(bytebuffer.array(), offset, length);
+    }
+
     protected byte[] engineUpdate(
         byte[]  input,
         int     inputOffset,
@@ -811,6 +926,8 @@
 
         public int getUpdateOutputSize(int len);
 
+        public void updateAAD(byte[] input, int offset, int length);
+
         public int processByte(byte in, byte[] out, int outOff)
             throws DataLengthException;
 
@@ -872,6 +989,11 @@
             return cipher.getUpdateOutputSize(len);
         }
 
+        public void updateAAD(byte[] input, int offset, int length)
+        {
+            throw new UnsupportedOperationException("AAD is not supported in the current mode.");
+        }
+
         public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
         {
             return cipher.processByte(in, out, outOff);
@@ -929,6 +1051,11 @@
             return cipher.getUpdateOutputSize(len);
         }
 
+        public void updateAAD(byte[] input, int offset, int length)
+        {
+            cipher.processAADBytes(input, offset, length);
+        }
+
         public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
         {
             return cipher.processByte(in, out, outOff);
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
index 442dcdd..d014972 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
@@ -4,6 +4,9 @@
 import java.security.InvalidKeyException;
 import java.security.Key;
 import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
 
 import javax.crypto.MacSpi;
 import javax.crypto.spec.IvParameterSpec;
@@ -13,6 +16,10 @@
 import org.bouncycastle.crypto.Mac;
 import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.crypto.params.ParametersWithIV;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.SkeinParameters;
+// import org.bouncycastle.jcajce.spec.SkeinParameterSpec;
+// END android-removed
 
 public class BaseMac
     extends MacSpi implements PBE
@@ -74,6 +81,12 @@
         {
             param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
         }
+        // BEGIN android-removed
+        // else if (params instanceof SkeinParameterSpec)
+        // {
+        //     param = new SkeinParameters.Builder(copyMap(((SkeinParameterSpec)params).getParameters())).setKey(key.getEncoded()).build();
+        // }
+        // END android-removed
         else if (params == null)
         {
             param = new KeyParameter(key.getEncoded());
@@ -118,4 +131,18 @@
 
         return out;
     }
+
+    private static Hashtable copyMap(Map paramsMap)
+    {
+        Hashtable newTable = new Hashtable();
+
+        Iterator keys = paramsMap.keySet().iterator();
+        while (keys.hasNext())
+        {
+            Object key = keys.next();
+            newTable.put(key, paramsMap.get(key));
+        }
+
+        return newTable;
+    }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
index 2031929..eb045bf 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
@@ -3,6 +3,7 @@
 import java.security.AlgorithmParameters;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
 import java.security.Key;
 import java.security.SecureRandom;
 import java.security.spec.AlgorithmParameterSpec;
@@ -205,7 +206,7 @@
         }
         else
         {
-            throw new IllegalArgumentException("unknown parameter type.");
+            throw new InvalidAlgorithmParameterException("unknown parameter type.");
         }
 
         if ((ivLength != 0) && !(param instanceof ParametersWithIV))
@@ -231,18 +232,25 @@
             }
         }
 
-        switch (opmode)
+        try
         {
-        case Cipher.ENCRYPT_MODE:
-        case Cipher.WRAP_MODE:
-            cipher.init(true, param);
-            break;
-        case Cipher.DECRYPT_MODE:
-        case Cipher.UNWRAP_MODE:
-            cipher.init(false, param);
-            break;
-        default:
-            System.out.println("eeek!");
+            switch (opmode)
+            {
+            case Cipher.ENCRYPT_MODE:
+            case Cipher.WRAP_MODE:
+                cipher.init(true, param);
+                break;
+            case Cipher.DECRYPT_MODE:
+            case Cipher.UNWRAP_MODE:
+                cipher.init(false, param);
+                break;
+            default:
+                throw new InvalidParameterException("unknown opmode " + opmode + " passed");
+            }
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeyException(e.getMessage());
         }
     }
 
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
index 951beee..c39a2d3 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
@@ -87,7 +87,44 @@
             }
             else if (type == PKCS5S2 || type == PKCS5S2_UTF8)
             {
-                generator = new PKCS5S2ParametersGenerator();
+                switch (hash)
+                {
+                // BEGIN android-removed
+                // case MD2:
+                //     generator = new PKCS5S2ParametersGenerator(new MD2Digest());
+                //     break;
+                // END android-removed
+                case MD5:
+                    // BEGIN android-changed
+                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getMD5());
+                    // END android-changed
+                    break;
+                case SHA1:
+                    // BEGIN android-changed
+                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA1());
+                    // END android-changed
+                    break;
+                // BEGIN android-removed
+                // case RIPEMD160:
+                //     generator = new PKCS5S2ParametersGenerator(new RIPEMD160Digest());
+                //     break;
+                // case TIGER:
+                //     generator = new PKCS5S2ParametersGenerator(new TigerDigest());
+                //     break;
+                // END android-removed
+                case SHA256:
+                    // BEGIN android-changed
+                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA256());
+                    // END android-changed
+                    break;
+                // BEGIN android-removed
+                // case GOST3411:
+                //     generator = new PKCS5S2ParametersGenerator(new GOST3411Digest());
+                //     break;
+                // END android-removed
+                default:
+                    throw new IllegalStateException("unknown digest scheme for PBE PKCS5S2 encryption.");
+                }
             }
             else if (type == PKCS12)
             {
@@ -288,9 +325,9 @@
             key = convertPassword(type, keySpec);
             
             generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
-    
+
             param = generator.generateDerivedMacParameters(keySize);
-    
+
             for (int i = 0; i != key.length; i++)
             {
                 key[i] = 0;
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
index c4b0f18..19ca6b1 100644
--- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
@@ -27,9 +27,7 @@
 {
     private static Set md5 = new HashSet();
     private static Set sha1 = new HashSet();
-    // BEGIN android-removed
-    // private static Set sha224 = new HashSet();
-    // END android-removed
+    private static Set sha224 = new HashSet();
     private static Set sha256 = new HashSet();
     private static Set sha384 = new HashSet();
     private static Set sha512 = new HashSet();
@@ -45,11 +43,9 @@
         sha1.add("SHA-1");
         sha1.add(OIWObjectIdentifiers.idSHA1.getId());
         
-        // BEGIN android-removed
-        // sha224.add("SHA224");
-        // sha224.add("SHA-224");
-        // sha224.add(NISTObjectIdentifiers.id_sha224.getId());
-        // END android-removed
+        sha224.add("SHA224");
+        sha224.add("SHA-224");
+        sha224.add(NISTObjectIdentifiers.id_sha224.getId());
         
         sha256.add("SHA256");
         sha256.add("SHA-256");
@@ -70,11 +66,9 @@
         oids.put("SHA-1", OIWObjectIdentifiers.idSHA1);
         oids.put(OIWObjectIdentifiers.idSHA1.getId(), OIWObjectIdentifiers.idSHA1);
         
-        // BEGIN android-removed
-        // oids.put("SHA224", NISTObjectIdentifiers.id_sha224);
-        // oids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
-        // oids.put(NISTObjectIdentifiers.id_sha224.getId(), NISTObjectIdentifiers.id_sha224);
-        // END android-removed
+        oids.put("SHA224", NISTObjectIdentifiers.id_sha224);
+        oids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+        oids.put(NISTObjectIdentifiers.id_sha224.getId(), NISTObjectIdentifiers.id_sha224);
         
         oids.put("SHA256", NISTObjectIdentifiers.id_sha256);
         oids.put("SHA-256", NISTObjectIdentifiers.id_sha256);
@@ -106,12 +100,12 @@
             return AndroidDigestFactory.getMD5();
             // END android-changed
         }
-        // BEGIN android-removed
-        // if (sha224.contains(digestName))
-        // {
-        //     return new SHA224Digest();
-        // }
-        // END android-removed
+        if (sha224.contains(digestName))
+        {
+            // BEGIN android-changed
+            return AndroidDigestFactory.getSHA224();
+            // END android-changed
+        }
         if (sha256.contains(digestName))
         {
             // BEGIN android-changed
@@ -139,9 +133,7 @@
         String digest2)
     {
         return (sha1.contains(digest1) && sha1.contains(digest2))
-            // BEGIN android-removed
-            // || (sha224.contains(digest1) && sha224.contains(digest2))
-            // END android-removed
+            || (sha224.contains(digest1) && sha224.contains(digest2))
             || (sha256.contains(digest1) && sha256.contains(digest2))
             || (sha384.contains(digest1) && sha384.contains(digest2))
             || (sha512.contains(digest1) && sha512.contains(digest2))
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java
new file mode 100644
index 0000000..214a5eb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.jcajce.spec;
+
+import javax.crypto.spec.PBEKeySpec;
+
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class PBKDF2KeySpec
+    extends PBEKeySpec
+{
+    private AlgorithmIdentifier prf;
+
+    public PBKDF2KeySpec(char[] password, byte[] salt, int iterationCount, int keySize, AlgorithmIdentifier prf)
+    {
+        super(password, salt, iterationCount, keySize);
+
+        this.prf = prf;
+    }
+
+    public AlgorithmIdentifier getPrf()
+    {
+        return prf;
+    }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java b/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
new file mode 100644
index 0000000..941f476
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
@@ -0,0 +1,60 @@
+package org.bouncycastle.jce;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+
+/**
+ * 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 = org.bouncycastle.asn1.x9.ECNamedCurveTable.getByName(name);
+        if (ecP == null)
+        {
+            try
+            {
+                ecP = org.bouncycastle.asn1.x9.ECNamedCurveTable.getByOID(new ASN1ObjectIdentifier(name));
+            }
+            catch (IllegalArgumentException e)
+            {
+                // ignore - not an oid
+            }
+        }
+        
+        if (ecP == null)
+        {
+            return null;
+        }
+
+        return new ECNamedCurveParameterSpec(
+                                        name,
+                                        ecP.getCurve(),
+                                        ecP.getG(),
+                                        ecP.getN(),
+                                        ecP.getH(),
+                                        ecP.getSeed());
+    }
+
+    /**
+     * return an enumeration of the names of the available curves.
+     *
+     * @return an enumeration of the names of the available curves.
+     */
+    public static Enumeration getNames()
+    {
+        return org.bouncycastle.asn1.x9.ECNamedCurveTable.getNames();
+    }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java b/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
index f3a3849..4c34850 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
@@ -95,10 +95,8 @@
         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"));
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-        // algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-        // END android-removed
+        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
         algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
         algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
         algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
@@ -106,9 +104,7 @@
         algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
         algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
         algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
-        // END android-removed
+        algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
         algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
         algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
         algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
@@ -123,16 +119,12 @@
         // 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"));
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
-        // END android-removed
+        algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
         algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
         algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
         algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
         algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
-        // END android-removed
+        algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
         algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
         algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
         algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
@@ -149,9 +141,7 @@
         // reverse mappings
         //
         oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
-        // BEGIN android-removed
-        // oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
-        // END android-removed
+        oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
         oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
         oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
         oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
@@ -167,17 +157,13 @@
         // END android-removed
         oids.put(new DERObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
-        // BEGIN android-removed
-        // oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
-        // END android-removed
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
         oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
         oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA");
-        // BEGIN android-removed
-        // oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
-        // END android-removed
+        oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
         oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
         
         //
@@ -191,16 +177,12 @@
         // The parameters field SHALL be NULL for RSA based signature algorithms.
         //
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
-        // BEGIN android-removed
-        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
-        // END android-removed
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
         noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
-        // BEGIN android-removed
-        // noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
-        // END android-removed
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
         noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
 
         //
@@ -216,10 +198,8 @@
         AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
         params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
 
-        // BEGIN android-removed
-        // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
-        // params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
-        // END android-removed
+        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+        params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
 
         AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
         params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
@@ -638,12 +618,10 @@
         {
             return "SHA1";
         }
-        // BEGIN android-removed
-        // else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
-        // {
-        //     return "SHA224";
-        // }
-        // END android-removed
+        else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+        {
+            return "SHA224";
+        }
         else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
         {
             return "SHA256";
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java b/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java
index efa0f66..ddd38e8 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java
@@ -19,6 +19,7 @@
  * PrincipalUtil class.
  * </p>
  * @see org.bouncycastle.jce.PrincipalUtil
+ * @deprecated use the X500Name class.
  */
 public class X509Principal
     extends X509Name
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index b3c34d3..ab6c42f 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -44,7 +44,7 @@
 public final class BouncyCastleProvider extends Provider
     implements ConfigurableProvider
 {
-    private static String info = "BouncyCastle Security Provider v1.49";
+    private static String info = "BouncyCastle Security Provider v1.50";
 
     public static final String PROVIDER_NAME = "BC";
 
@@ -72,11 +72,13 @@
     private static final String[] SYMMETRIC_CIPHERS =
     {
         // BEGIN android-removed
-        // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DES", "DESede", "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
-        // "Noekeon", "RC2", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
+        // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede",
+        // "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5",
+        // "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "TEA", "Twofish", "Threefish",
+        // "VMPC", "VMPCKSA3", "XTEA", "XSalsa20"
         // END android-removed
         // BEGIN android-added
-        "AES", "ARC4", "Blowfish", "DES", "DESede", "RC2", "Twofish"
+        "AES", "ARC4", "Blowfish", "DES", "DESede", "RC2", "Twofish",
         // END android-added
     };
 
@@ -114,15 +116,15 @@
     private static final String[] DIGESTS =
     {
         // BEGIN android-removed
-        // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Tiger", "Whirlpool"
+        // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool"
         // END android-removed
         // BEGIN android-added
-        "MD5", "SHA1", "SHA256", "SHA384", "SHA512",
+        "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512",
         // END android-added
     };
 
     /*
-     * Configurable digests
+     * Configurable keystores
      */
     private static final String KEYSTORE_PACKAGE = "org.bouncycastle.jcajce.provider.keystore.";
     private static final String[] KEYSTORES =
@@ -137,7 +139,7 @@
      */
     public BouncyCastleProvider()
     {
-        super(PROVIDER_NAME, 1.49, info);
+        super(PROVIDER_NAME, 1.50, info);
 
         AccessController.doPrivileged(new PrivilegedAction()
         {
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
index a76aff7..eb663dc 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
@@ -76,7 +76,9 @@
 import org.bouncycastle.x509.X509AttributeCertificate;
 import org.bouncycastle.x509.X509CRLStoreSelector;
 import org.bouncycastle.x509.X509CertStoreSelector;
-import org.bouncycastle.x509.X509Store;
+// BEGIN android-removed
+// import org.bouncycastle.x509.X509Store;
+// END android-removed
 
 public class CertPathValidatorUtilities
 {
@@ -726,20 +728,22 @@
         {
             Object obj = iter.next();
 
-            if (obj instanceof X509Store)
-            {
-                X509Store certStore = (X509Store)obj;
-                try
-                {
-                    certs.addAll(certStore.getMatches(certSelect));
-                }
-                catch (StoreException e)
-                {
-                    throw new AnnotatedException(
-                            "Problem while picking certificates from X.509 store.", e);
-                }
-            }
-            else
+            // BEGIN android-removed
+            // if (obj instanceof X509Store)
+            // {
+            //     X509Store certStore = (X509Store)obj;
+            //     try
+            //     {
+            //         certs.addAll(certStore.getMatches(certSelect));
+            //     }
+            //     catch (StoreException e)
+            //     {
+            //         throw new AnnotatedException(
+            //                 "Problem while picking certificates from X.509 store.", e);
+            //     }
+            // }
+            // else
+            // END android-removed
             {
                 CertStore certStore = (CertStore)obj;
 
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
index 7d561b3..53f4ec7 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
@@ -127,8 +127,8 @@
             this.ecSpec = new ECParameterSpec(
                             ellipticCurve,
                             new ECPoint(
-                                    dp.getG().getX().toBigInteger(),
-                                    dp.getG().getY().toBigInteger()),
+                                    dp.getG().getAffineXCoord().toBigInteger(),
+                                    dp.getG().getAffineYCoord().toBigInteger()),
                             dp.getN(),
                             dp.getH().intValue());
         }
@@ -158,8 +158,8 @@
             this.ecSpec = new ECParameterSpec(
                             ellipticCurve,
                             new ECPoint(
-                                    dp.getG().getX().toBigInteger(),
-                                    dp.getG().getY().toBigInteger()),
+                                    dp.getG().getAffineXCoord().toBigInteger(),
+                                    dp.getG().getAffineYCoord().toBigInteger()),
                             dp.getN(),
                             dp.getH().intValue());
         }
@@ -170,8 +170,8 @@
             this.ecSpec = new ECParameterSpec(
                                 ellipticCurve,
                                 new ECPoint(
-                                        spec.getG().getX().toBigInteger(),
-                                        spec.getG().getY().toBigInteger()),
+                                    spec.getG().getAffineXCoord().toBigInteger(),
+                                    spec.getG().getAffineYCoord().toBigInteger()),
                                 spec.getN(),
                                 spec.getH().intValue());
         }
@@ -215,8 +215,8 @@
             //             ECGOST3410NamedCurves.getName(oid),
             //             ellipticCurve,
             //             new ECPoint(
-            //                     gParam.getG().getX().toBigInteger(),
-            //                     gParam.getG().getY().toBigInteger()),
+            //                     gParam.getG().getAffineXCoord().toBigInteger(),
+            //                     gParam.getG().getAffineYCoord().toBigInteger()),
             //             gParam.getN(),
             //             gParam.getH());
             // }
@@ -229,8 +229,8 @@
                         ECUtil.getCurveName(oid),
                         ellipticCurve,
                         new ECPoint(
-                                ecP.getG().getX().toBigInteger(),
-                                ecP.getG().getY().toBigInteger()),
+                                ecP.getG().getAffineXCoord().toBigInteger(),
+                                ecP.getG().getAffineYCoord().toBigInteger()),
                         ecP.getN(),
                         ecP.getH());
             }
@@ -247,8 +247,8 @@
             this.ecSpec = new ECParameterSpec(
                 ellipticCurve,
                 new ECPoint(
-                        ecP.getG().getX().toBigInteger(),
-                        ecP.getG().getY().toBigInteger()),
+                        ecP.getG().getAffineXCoord().toBigInteger(),
+                        ecP.getG().getAffineYCoord().toBigInteger()),
                 ecP.getN(),
                 ecP.getH().intValue());
         }
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
index cfed770..6fff8a6 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
@@ -98,7 +98,7 @@
             {
                 org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
 
-                q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
+                q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger(), false);
             }               
             this.ecSpec = null;
         }
@@ -167,8 +167,8 @@
         return new ECParameterSpec(
                 ellipticCurve,
                 new ECPoint(
-                        dp.getG().getX().toBigInteger(),
-                        dp.getG().getY().toBigInteger()),
+                        dp.getG().getAffineXCoord().toBigInteger(),
+                        dp.getG().getAffineYCoord().toBigInteger()),
                         dp.getN(),
                         dp.getH().intValue());
     }
@@ -189,7 +189,6 @@
 
     private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
     {
-        // BEGIN android-removed
         // if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
         // {
         //     DERBitString bits = info.getPublicKeyData();
@@ -232,8 +231,8 @@
         //             ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
         //             ellipticCurve,
         //             new ECPoint(
-        //                     spec.getG().getX().toBigInteger(),
-        //                     spec.getG().getY().toBigInteger()),
+        //                     spec.getG().getAffineXCoord().toBigInteger(),
+        //                     spec.getG().getAffineYCoord().toBigInteger()),
         //                     spec.getN(), spec.getH());
         //
         // }
@@ -256,8 +255,8 @@
                         ECUtil.getCurveName(oid),
                         ellipticCurve,
                         new ECPoint(
-                                ecP.getG().getX().toBigInteger(),
-                                ecP.getG().getY().toBigInteger()),
+                                ecP.getG().getAffineXCoord().toBigInteger(),
+                                ecP.getG().getAffineYCoord().toBigInteger()),
                         ecP.getN(),
                         ecP.getH());
             }
@@ -276,8 +275,8 @@
                 this.ecSpec = new ECParameterSpec(
                         ellipticCurve,
                         new ECPoint(
-                                ecP.getG().getX().toBigInteger(),
-                                ecP.getG().getY().toBigInteger()),
+                                ecP.getG().getAffineXCoord().toBigInteger(),
+                                ecP.getG().getAffineYCoord().toBigInteger()),
                         ecP.getN(),
                         ecP.getH().intValue());
             }
@@ -357,8 +356,8 @@
         //         }
         //     }
         //
-        //     BigInteger      bX = this.q.getX().toBigInteger();
-        //     BigInteger      bY = this.q.getY().toBigInteger();
+        //     BigInteger      bX = this.q.getAffineXCoord().toBigInteger();
+        //     BigInteger      bY = this.q.getAffineYCoord().toBigInteger();
         //     byte[]          encKey = new byte[64];
         //
         //     extractBytes(encKey, 0, bX);
@@ -405,7 +404,7 @@
 
             ECCurve curve = this.engineGetQ().getCurve();
             ASN1OctetString p = (ASN1OctetString)
-                new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).toASN1Primitive();
+                new X9ECPoint(curve.createPoint(this.getQ().getAffineXCoord().toBigInteger(), this.getQ().getAffineYCoord().toBigInteger(), withCompression)).toASN1Primitive();
 
             info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
         }
@@ -446,7 +445,7 @@
 
     public ECPoint getW()
     {
-        return new ECPoint(q.getX().toBigInteger(), q.getY().toBigInteger());
+        return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
     }
 
     public org.bouncycastle.math.ec.ECPoint getQ()
@@ -455,11 +454,11 @@
         {
             if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp)
             {
-                return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY());
+                return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getAffineXCoord(), q.getAffineYCoord());
             }
             else
             {
-                return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY());
+                return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getAffineXCoord(), q.getAffineYCoord());
             }
         }
 
@@ -487,8 +486,8 @@
         String          nl = System.getProperty("line.separator");
 
         buf.append("EC Public Key").append(nl);
-        buf.append("            X: ").append(this.q.getX().toBigInteger().toString(16)).append(nl);
-        buf.append("            Y: ").append(this.q.getY().toBigInteger().toString(16)).append(nl);
+        buf.append("            X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
+        buf.append("            Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
 
         return buf.toString();
 
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java
index c94016d..ebd2f2a 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java
@@ -15,7 +15,9 @@
 import org.bouncycastle.util.StoreException;
 import org.bouncycastle.x509.ExtendedPKIXParameters;
 import org.bouncycastle.x509.X509CRLStoreSelector;
-import org.bouncycastle.x509.X509Store;
+// BEGIN android-removed
+// import org.bouncycastle.x509.X509Store;
+// END android-removed
 
 public class PKIXCRLUtil
 {
@@ -114,22 +116,24 @@
         {
             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
+            // BEGIN android-removed
+            // 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
+            // END android-removed
             {
                 CertStore store = (CertStore)obj;
 
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
index d5c3700..7e76a89 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
@@ -211,6 +211,23 @@
         return hashValue;
     }
 
+    public boolean equals(Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+
+        if (o instanceof X509CRLEntryObject)
+        {
+            X509CRLEntryObject other = (X509CRLEntryObject)o;
+
+            return this.c.equals(other.c);
+        }
+
+        return super.equals(this);
+    }
+
     public byte[] getEncoded()
         throws CRLException
     {
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
index cd83211..b5b4f13 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
@@ -59,6 +59,8 @@
     private String sigAlgName;
     private byte[] sigAlgParams;
     private boolean isIndirect;
+    private boolean isHashCodeSet = false;
+    private int     hashCodeValue;
 
     static boolean isIndirectCRL(X509CRL crl)
         throws CRLException
@@ -520,7 +522,7 @@
             throw new RuntimeException("X.509 CRL used with non X.509 Cert");
         }
 
-        TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
+        Enumeration certs = c.getRevokedCertificateEnumeration();
 
         X500Name caName = c.getIssuer();
 
@@ -528,11 +530,13 @@
         {
             BigInteger serial = ((X509Certificate)cert).getSerialNumber();
 
-            for (int i = 0; i < certs.length; i++)
+            while (certs.hasMoreElements())
             {
-                if (isIndirect && certs[i].hasExtensions())
+                TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement());
+
+                if (isIndirect && entry.hasExtensions())
                 {
-                    Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer);
+                    Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
 
                     if (currentCaName != null)
                     {
@@ -540,7 +544,7 @@
                     }
                 }
 
-                if (certs[i].getUserCertificate().getValue().equals(serial))
+                if (entry.getUserCertificate().getValue().equals(serial))
                 {
                     X500Name issuer;
 
@@ -572,5 +576,50 @@
 
         return false;
     }
+
+    public boolean equals(Object other)
+    {
+        if (this == other)
+        {
+            return true;
+        }
+
+        if (!(other instanceof X509CRL))
+        {
+            return false;
+        }
+
+        if (other instanceof X509CRLObject)
+        {
+            X509CRLObject crlObject = (X509CRLObject)other;
+
+            if (isHashCodeSet)
+            {
+                boolean otherIsHashCodeSet = crlObject.isHashCodeSet;
+                if (otherIsHashCodeSet)
+                {
+                    if (crlObject.hashCodeValue != hashCodeValue)
+                    {
+                        return false;
+                    }
+                }
+            }
+
+            return this.c.equals(crlObject.c);
+        }
+
+        return super.equals(other);
+    }
+
+    public int hashCode()
+    {
+        if (!isHashCodeSet)
+        {
+            isHashCodeSet = true;
+            hashCodeValue = super.hashCode();
+        }
+
+        return hashCodeValue;
+    }
 }
 
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
index 3e2b1ce..b8b0097 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
@@ -102,12 +102,10 @@
         {
             return "SHA1";
         }
-        // BEGIN android-removed
-        // else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
-        // {
-        //     return "SHA224";
-        // }
-        // END android-removed
+        else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+        {
+            return "SHA224";
+        }
         else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
         {
             return "SHA256";
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java
index 84ebf70..b3d239e 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java
@@ -49,7 +49,8 @@
     private static ECPoint convertPoint(
         org.bouncycastle.math.ec.ECPoint  g)
     {
-        return new ECPoint(g.getX().toBigInteger(), g.getY().toBigInteger());
+        g = g.normalize();
+        return new ECPoint(g.getAffineXCoord().toBigInteger(), g.getAffineYCoord().toBigInteger());
     }
     
     public ECNamedCurveSpec(
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java
index e774a11..df91412 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java
@@ -24,7 +24,7 @@
         BigInteger  n)
     {
         this.curve = curve;
-        this.G = G;
+        this.G = G.normalize();
         this.n = n;
         this.h = BigInteger.valueOf(1);
         this.seed = null;
@@ -37,7 +37,7 @@
         BigInteger  h)
     {
         this.curve = curve;
-        this.G = G;
+        this.G = G.normalize();
         this.n = n;
         this.h = h;
         this.seed = null;
@@ -51,7 +51,7 @@
         byte[]      seed)
     {
         this.curve = curve;
-        this.G = G;
+        this.G = G.normalize();
         this.n = n;
         this.h = h;
         this.seed = seed;
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java
index debab00..0e21a5b 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java
@@ -22,7 +22,14 @@
     {
         super(spec);
 
-        this.q = q;
+        if (q.getCurve() != null)
+        {
+            this.q = q.normalize();
+        }
+        else
+        {
+            this.q = q;
+        }
     }
 
     /**
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java
deleted file mode 100644
index 2a7ceb5..0000000
--- a/bcprov/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.bouncycastle.jce.spec;
-
-
-import javax.crypto.SecretKey;
-
-/**
- * A simple object to indicate that a symmetric cipher should reuse the
- * last key provided.
- */
-public class RepeatedSecretKeySpec
-    implements SecretKey
-{
-    private String algorithm;
-
-    public RepeatedSecretKeySpec(String algorithm)
-    {
-        this.algorithm = algorithm;
-    }
-
-    public String getAlgorithm()
-    {
-        return algorithm;
-    }
-
-    public String getFormat()
-    {
-        return null;
-    }
-
-    public byte[] getEncoded()
-    {
-        return null;
-    }
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java
new file mode 100644
index 0000000..69ab797
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+public abstract class AbstractECMultiplier implements ECMultiplier
+{
+    public ECPoint multiply(ECPoint p, BigInteger k)
+    {
+        int sign = k.signum();
+        if (sign == 0 || p.isInfinity())
+        {
+            return p.getCurve().getInfinity();
+        }
+
+        ECPoint positive = multiplyPositive(p, k.abs());
+        return sign > 0 ? positive : positive.negate();
+    }
+
+    protected abstract ECPoint multiplyPositive(ECPoint p, BigInteger k);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
index 78a7a8f..d640b5f 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
@@ -7,16 +7,13 @@
     public static ECPoint sumOfTwoMultiplies(ECPoint P, BigInteger a,
         ECPoint Q, BigInteger b)
     {
-        ECCurve c = P.getCurve();
-        if (!c.equals(Q.getCurve()))
-        {
-            throw new IllegalArgumentException("P and Q must be on same curve");
-        }
+        ECCurve cp = P.getCurve();
+        Q = importPoint(cp, Q);
 
         // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
-        if (c instanceof ECCurve.F2m)
+        if (cp instanceof ECCurve.F2m)
         {
-            ECCurve.F2m f2mCurve = (ECCurve.F2m)c;
+            ECCurve.F2m f2mCurve = (ECCurve.F2m)cp;
             if (f2mCurve.isKoblitz())
             {
                 return P.multiply(a).add(Q.multiply(b));
@@ -48,43 +45,83 @@
     public static ECPoint shamirsTrick(ECPoint P, BigInteger k,
         ECPoint Q, BigInteger l)
     {
-        if (!P.getCurve().equals(Q.getCurve()))
-        {
-            throw new IllegalArgumentException("P and Q must be on same curve");
-        }
+        ECCurve cp = P.getCurve();
+        Q = importPoint(cp, Q);
 
         return implShamirsTrick(P, k, Q, l);
     }
 
-    private static ECPoint implShamirsTrick(ECPoint P, BigInteger k,
+    public static ECPoint importPoint(ECCurve c, ECPoint p)
+    {
+        ECCurve cp = p.getCurve();
+        if (!c.equals(cp))
+        {
+            throw new IllegalArgumentException("Point must be on the same curve");
+        }
+        return c.importPoint(p);
+    }
+
+    static void implMontgomeryTrick(ECFieldElement[] zs, int off, int len)
+    {
+        /*
+         * Uses the "Montgomery Trick" to invert many field elements, with only a single actual
+         * field inversion. See e.g. the paper:
+         * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick"
+         * by Katsuyuki Okeya, Kouichi Sakurai.
+         */
+
+        ECFieldElement[] c = new ECFieldElement[len];
+        c[0] = zs[off];
+
+        int i = 0;
+        while (++i < len)
+        {
+            c[i] = c[i - 1].multiply(zs[off + i]);
+        }
+
+        ECFieldElement u = c[--i].invert();
+
+        while (i > 0)
+        {
+            int j = off + i--;
+            ECFieldElement tmp = zs[j];
+            zs[j] = c[i].multiply(u);
+            u = u.multiply(tmp);
+        }
+
+        zs[off] = u;
+    }
+
+    static ECPoint implShamirsTrick(ECPoint P, BigInteger k,
         ECPoint Q, BigInteger l)
     {
-        int m = Math.max(k.bitLength(), l.bitLength());
-        ECPoint Z = P.add(Q);
-        ECPoint R = P.getCurve().getInfinity();
+        ECCurve curve = P.getCurve();
+        ECPoint infinity = curve.getInfinity();
 
-        for (int i = m - 1; i >= 0; --i)
+        // TODO conjugate co-Z addition (ZADDC) can return both of these
+        ECPoint PaddQ = P.add(Q);
+        ECPoint PsubQ = P.subtract(Q);
+
+        ECPoint[] points = new ECPoint[]{ Q, PsubQ, P, PaddQ };
+        curve.normalizeAll(points);
+
+        ECPoint[] table = new ECPoint[] {
+            points[3].negate(), points[2].negate(), points[1].negate(),
+            points[0].negate(), infinity, points[0],
+            points[1], points[2], points[3] };
+
+        byte[] jsf = WNafUtil.generateJSF(k, l);
+
+        ECPoint R = infinity;
+
+        int i = jsf.length;
+        while (--i >= 0)
         {
-            R = R.twice();
+            int jsfi = jsf[i];
+            int kDigit = (jsfi >> 4), lDigit = ((jsfi << 28) >> 28);
 
-            if (k.testBit(i))
-            {
-                if (l.testBit(i))
-                {
-                    R = R.add(Z);
-                }
-                else
-                {
-                    R = R.add(P);
-                }
-            }
-            else
-            {
-                if (l.testBit(i))
-                {
-                    R = R.add(Q);
-                }
-            }
+            int index = 4 + (kDigit * 3) + lDigit;
+            R = R.twicePlus(table[index]);
         }
 
         return R;
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java
index 58281af..19f0062 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java
@@ -3,18 +3,199 @@
 import java.math.BigInteger;
 import java.util.Random;
 
+import org.bouncycastle.util.BigIntegers;
+
 /**
  * base class for an elliptic curve
  */
 public abstract class ECCurve
 {
-    ECFieldElement a, b;
+    public static final int COORD_AFFINE = 0;
+    public static final int COORD_HOMOGENEOUS = 1;
+    public static final int COORD_JACOBIAN = 2;
+    public static final int COORD_JACOBIAN_CHUDNOVSKY = 3;
+    public static final int COORD_JACOBIAN_MODIFIED = 4;
+    public static final int COORD_LAMBDA_AFFINE = 5;
+    public static final int COORD_LAMBDA_PROJECTIVE = 6;
+    public static final int COORD_SKEWED = 7;
+
+    public static int[] getAllCoordinateSystems()
+    {
+        return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY,
+            COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED };
+    }
+
+    public class Config
+    {
+        protected int coord;
+        protected ECMultiplier multiplier;
+
+        Config(int coord, ECMultiplier multiplier)
+        {
+            this.coord = coord;
+            this.multiplier = multiplier;
+        }
+
+        public Config setCoordinateSystem(int coord)
+        {
+            this.coord = coord;
+            return this;
+        }
+
+        public Config setMultiplier(ECMultiplier multiplier)
+        {
+            this.multiplier = multiplier;
+            return this;
+        }
+
+        public ECCurve create()
+        {
+            if (!supportsCoordinateSystem(coord))
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+
+            ECCurve c = cloneCurve();
+            if (c == ECCurve.this)
+            {
+                throw new IllegalStateException("implementation returned current curve");
+            }
+
+            c.coord = coord;
+            c.multiplier = multiplier;
+
+            return c;
+        }
+    }
+
+    protected ECFieldElement a, b;
+    protected int coord = COORD_AFFINE;
+    protected ECMultiplier multiplier = null;
 
     public abstract int getFieldSize();
 
     public abstract ECFieldElement fromBigInteger(BigInteger x);
 
-    public abstract ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression);
+    public Config configure()
+    {
+        return new Config(this.coord, this.multiplier);
+    }
+
+    public ECPoint createPoint(BigInteger x, BigInteger y)
+    {
+        return createPoint(x, y, false);
+    }
+
+    /**
+     * @deprecated per-point compression property will be removed, use {@link #createPoint(BigInteger, BigInteger)}
+     * and refer {@link ECPoint#getEncoded(boolean)}
+     */
+    public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+    {
+        return createRawPoint(fromBigInteger(x), fromBigInteger(y), withCompression);
+    }
+
+    protected abstract ECCurve cloneCurve();
+
+    protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression);
+
+    protected ECMultiplier createDefaultMultiplier()
+    {
+        return new WNafL2RMultiplier();
+    }
+
+    public boolean supportsCoordinateSystem(int coord)
+    {
+        return coord == COORD_AFFINE;
+    }
+
+    public PreCompInfo getPreCompInfo(ECPoint p)
+    {
+        checkPoint(p);
+        return p.preCompInfo;
+    }
+
+    /**
+     * Sets the <code>PreCompInfo</code> for a point on this curve. Used by
+     * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use
+     * by subsequent multiplication.
+     * 
+     * @param point
+     *            The <code>ECPoint</code> to store precomputations for.
+     * @param preCompInfo
+     *            The values precomputed by the <code>ECMultiplier</code>.
+     */
+    public void setPreCompInfo(ECPoint point, PreCompInfo preCompInfo)
+    {
+        checkPoint(point);
+        point.preCompInfo = preCompInfo;
+    }
+
+    public ECPoint importPoint(ECPoint p)
+    {
+        if (this == p.getCurve())
+        {
+            return p;
+        }
+        if (p.isInfinity())
+        {
+            return getInfinity();
+        }
+
+        // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
+        p = p.normalize();
+
+        return createPoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger(), p.withCompression);
+    }
+
+    /**
+     * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+     * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
+     * than one point is to be normalized, this method will generally be more efficient than
+     * normalizing each point separately.
+     * 
+     * @param points
+     *            An array of points that will be updated in place with their normalized versions,
+     *            where necessary
+     */
+    public void normalizeAll(ECPoint[] points)
+    {
+        checkPoints(points);
+
+        if (this.getCoordinateSystem() == ECCurve.COORD_AFFINE)
+        {
+            return;
+        }
+
+        /*
+         * Figure out which of the points actually need to be normalized
+         */
+        ECFieldElement[] zs = new ECFieldElement[points.length];
+        int[] indices = new int[points.length];
+        int count = 0;
+        for (int i = 0; i < points.length; ++i)
+        {
+            ECPoint p = points[i];
+            if (null != p && !p.isNormalized())
+            {
+                zs[count] = p.getZCoord(0);
+                indices[count++] = i;
+            }
+        }
+
+        if (count == 0)
+        {
+            return;
+        }
+
+        ECAlgorithms.implMontgomeryTrick(zs, 0, count);
+
+        for (int j = 0; j < count; ++j)
+        {
+            int index = indices[j];
+            points[index] = points[index].normalize(zs[j]);
+        }
+    }
 
     public abstract ECPoint getInfinity();
 
@@ -28,9 +209,26 @@
         return b;
     }
 
+    public int getCoordinateSystem()
+    {
+        return coord;
+    }
+
     protected abstract ECPoint decompressPoint(int yTilde, BigInteger X1);
 
     /**
+     * Sets the default <code>ECMultiplier</code>, unless already set. 
+     */
+    public ECMultiplier getMultiplier()
+    {
+        if (this.multiplier == null)
+        {
+            this.multiplier = createDefaultMultiplier();
+        }
+        return this.multiplier;
+    }
+
+    /**
      * Decode a point on this curve from its ASN.1 encoding. The different
      * encodings are taken account of, including point compression for
      * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
@@ -62,9 +260,9 @@
             }
 
             int yTilde = encoded[0] & 1;
-            BigInteger X1 = fromArray(encoded, 1, expectedLength);
+            BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
 
-            p = decompressPoint(yTilde, X1);
+            p = decompressPoint(yTilde, X);
             break;
         }
         case 0x04: // uncompressed
@@ -76,10 +274,10 @@
                 throw new IllegalArgumentException("Incorrect length for uncompressed/hybrid encoding");
             }
 
-            BigInteger X1 = fromArray(encoded, 1, expectedLength);
-            BigInteger Y1 = fromArray(encoded, 1 + expectedLength, expectedLength);
+            BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
+            BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength);
 
-            p = createPoint(X1, Y1, false);
+            p = createPoint(X, Y);
             break;
         }
         default:
@@ -89,11 +287,29 @@
         return p;
     }
 
-    private static BigInteger fromArray(byte[] buf, int off, int length)
+    protected void checkPoint(ECPoint point)
     {
-        byte[] mag = new byte[length];
-        System.arraycopy(buf, off, mag, 0, length);
-        return new BigInteger(1, mag);
+        if (null == point || (this != point.getCurve()))
+        {
+            throw new IllegalArgumentException("'point' must be non-null and on this curve");
+        }
+    }
+
+    protected void checkPoints(ECPoint[] points)
+    {
+        if (points == null)
+        {
+            throw new IllegalArgumentException("'points' cannot be null");
+        }
+
+        for (int i = 0; i < points.length; ++i)
+        {
+            ECPoint point = points[i];
+            if (null != point && this != point.getCurve())
+            {
+                throw new IllegalArgumentException("'points' entries must be null or on this curve");
+            }
+        }
     }
 
     /**
@@ -101,15 +317,50 @@
      */
     public static class Fp extends ECCurve
     {
-        BigInteger q;
+        private static final int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
+
+        BigInteger q, r;
         ECPoint.Fp infinity;
 
         public Fp(BigInteger q, BigInteger a, BigInteger b)
         {
             this.q = q;
+            this.r = ECFieldElement.Fp.calculateResidue(q);
+            this.infinity = new ECPoint.Fp(this, null, null);
+
             this.a = fromBigInteger(a);
             this.b = fromBigInteger(b);
+            this.coord = FP_DEFAULT_COORDS;
+        }
+
+        protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
+        {
+            this.q = q;
+            this.r = r;
             this.infinity = new ECPoint.Fp(this, null, null);
+
+            this.a = a;
+            this.b = b;
+            this.coord = FP_DEFAULT_COORDS;
+        }
+
+        protected ECCurve cloneCurve()
+        {
+            return new Fp(q, r, a, b);
+        }
+
+        public boolean supportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_AFFINE:
+            case COORD_HOMOGENEOUS:
+            case COORD_JACOBIAN:
+            case COORD_JACOBIAN_MODIFIED:
+                return true;
+            default:
+                return false;
+            }
         }
 
         public BigInteger getQ()
@@ -124,12 +375,34 @@
 
         public ECFieldElement fromBigInteger(BigInteger x)
         {
-            return new ECFieldElement.Fp(this.q, x);
+            return new ECFieldElement.Fp(this.q, this.r, x);
         }
 
-        public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+        protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
         {
-            return new ECPoint.Fp(this, fromBigInteger(x), fromBigInteger(y), withCompression);
+            return new ECPoint.Fp(this, x, y, withCompression);
+        }
+
+        public ECPoint importPoint(ECPoint p)
+        {
+            if (this != p.getCurve() && this.getCoordinateSystem() == COORD_JACOBIAN && !p.isInfinity())
+            {
+                switch (p.getCurve().getCoordinateSystem())
+                {
+                case COORD_JACOBIAN:
+                case COORD_JACOBIAN_CHUDNOVSKY:
+                case COORD_JACOBIAN_MODIFIED:
+                    return new ECPoint.Fp(this,
+                        fromBigInteger(p.x.toBigInteger()),
+                        fromBigInteger(p.y.toBigInteger()),
+                        new ECFieldElement[]{ fromBigInteger(p.zs[0].toBigInteger()) },
+                        p.withCompression);
+                default:
+                    break;
+                }
+            }
+
+            return super.importPoint(p);
         }
 
         protected ECPoint decompressPoint(int yTilde, BigInteger X1)
@@ -148,9 +421,7 @@
             }
 
             BigInteger betaValue = beta.toBigInteger();
-            int bit0 = betaValue.testBit(0) ? 1 : 0;
-
-            if (bit0 != yTilde)
+            if (betaValue.testBit(0) != (yTilde == 1))
             {
                 // Use the other root
                 beta = fromBigInteger(q.subtract(betaValue));
@@ -195,6 +466,8 @@
      */
     public static class F2m extends ECCurve
     {
+        private static final int F2M_DEFAULT_COORDS = COORD_AFFINE;
+
         /**
          * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
          */
@@ -401,9 +674,53 @@
                 }
             }
 
+            this.infinity = new ECPoint.F2m(this, null, null);
             this.a = fromBigInteger(a);
             this.b = fromBigInteger(b);
+            this.coord = F2M_DEFAULT_COORDS;
+        }
+
+        protected F2m(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger n, BigInteger h)
+        {
+            this.m = m;
+            this.k1 = k1;
+            this.k2 = k2;
+            this.k3 = k3;
+            this.n = n;
+            this.h = h;
+
             this.infinity = new ECPoint.F2m(this, null, null);
+            this.a = a;
+            this.b = b;
+            this.coord = F2M_DEFAULT_COORDS;
+        }
+
+        protected ECCurve cloneCurve()
+        {
+            return new F2m(m, k1, k2, k3, a, b, n, h);
+        }
+
+        public boolean supportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_AFFINE:
+            case COORD_HOMOGENEOUS:
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        protected ECMultiplier createDefaultMultiplier()
+        {
+            if (isKoblitz())
+            {
+                return new WTauNafMultiplier();
+            }
+
+            return super.createDefaultMultiplier();
         }
 
         public int getFieldSize()
@@ -418,7 +735,32 @@
 
         public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
         {
-            return new ECPoint.F2m(this, fromBigInteger(x), fromBigInteger(y), withCompression);
+            ECFieldElement X = fromBigInteger(x), Y = fromBigInteger(y);
+
+            switch (this.getCoordinateSystem())
+            {
+            case COORD_LAMBDA_AFFINE:
+            case COORD_LAMBDA_PROJECTIVE:
+            {
+                if (!X.isZero())
+                {
+                    // Y becomes Lambda (X + Y/X) here
+                    Y = Y.divide(X).add(X);
+                }
+                break;
+            }
+            default:
+            {
+                break;
+            }
+            }
+
+            return createRawPoint(X, Y, withCompression);
+        }
+
+        protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
+        {
+            return new ECPoint.F2m(this, x, y, withCompression);
         }
 
         public ECPoint getInfinity()
@@ -432,10 +774,7 @@
          */
         public boolean isKoblitz()
         {
-            return ((n != null) && (h != null) &&
-                    ((a.toBigInteger().equals(ECConstants.ZERO)) ||
-                    (a.toBigInteger().equals(ECConstants.ONE))) &&
-                    (b.toBigInteger().equals(ECConstants.ONE)));
+            return n != null && h != null && a.bitLength() <= 1 && b.bitLength() == 1;
         }
 
         /**
@@ -480,7 +819,7 @@
         {
             ECFieldElement xp = fromBigInteger(X1);
             ECFieldElement yp = null;
-            if (xp.toBigInteger().equals(ECConstants.ZERO))
+            if (xp.isZero())
             {
                 yp = (ECFieldElement.F2m)b;
                 for (int i = 0; i < m - 1; i++)
@@ -491,17 +830,31 @@
             else
             {
                 ECFieldElement beta = xp.add(a).add(b.multiply(xp.square().invert()));
-                ECFieldElement z = solveQuadradicEquation(beta);
+                ECFieldElement z = solveQuadraticEquation(beta);
                 if (z == null)
                 {
                     throw new IllegalArgumentException("Invalid point compression");
                 }
-                int zBit = z.toBigInteger().testBit(0) ? 1 : 0;
-                if (zBit != yTilde)
+                if (z.testBitZero() != (yTilde == 1))
                 {
-                    z = z.add(fromBigInteger(ECConstants.ONE));
+                    z = z.addOne();
                 }
+
                 yp = xp.multiply(z);
+
+                switch (this.getCoordinateSystem())
+                {
+                case COORD_LAMBDA_AFFINE:
+                case COORD_LAMBDA_PROJECTIVE:
+                {
+                    yp = yp.divide(xp).add(xp);
+                    break;
+                }
+                default:
+                {
+                    break;
+                }
+                }
             }
 
             return new ECPoint.F2m(this, xp, yp, true);
@@ -512,28 +865,26 @@
          * D.1.6) The other solution is <code>z + 1</code>.
          * 
          * @param beta
-         *            The value to solve the qradratic equation for.
+         *            The value to solve the quadratic equation for.
          * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
          *         <code>null</code> if no solution exists.
          */
-        private ECFieldElement solveQuadradicEquation(ECFieldElement beta)
+        private ECFieldElement solveQuadraticEquation(ECFieldElement beta)
         {
-            ECFieldElement zeroElement = new ECFieldElement.F2m(
-                    this.m, this.k1, this.k2, this.k3, ECConstants.ZERO);
-
-            if (beta.toBigInteger().equals(ECConstants.ZERO))
+            if (beta.isZero())
             {
-                return zeroElement;
+                return beta;
             }
 
+            ECFieldElement zeroElement = fromBigInteger(ECConstants.ZERO);
+
             ECFieldElement z = null;
-            ECFieldElement gamma = zeroElement;
+            ECFieldElement gamma = null;
 
             Random rand = new Random();
             do
             {
-                ECFieldElement t = new ECFieldElement.F2m(this.m, this.k1,
-                        this.k2, this.k3, new BigInteger(m, rand));
+                ECFieldElement t = fromBigInteger(new BigInteger(m, rand));
                 z = zeroElement;
                 ECFieldElement w = beta;
                 for (int i = 1; i <= m - 1; i++)
@@ -542,13 +893,13 @@
                     z = z.square().add(w2.multiply(t));
                     w = w2.add(beta);
                 }
-                if (!w.toBigInteger().equals(ECConstants.ZERO))
+                if (!w.isZero())
                 {
                     return null;
                 }
                 gamma = z.square().add(z);
             }
-            while (gamma.toBigInteger().equals(ECConstants.ZERO));
+            while (gamma.isZero());
 
             return z;
         }
@@ -567,7 +918,7 @@
             }
 
             ECCurve.F2m other = (ECCurve.F2m)anObject;
-            
+
             return (this.m == other.m) && (this.k1 == other.k1)
                 && (this.k2 == other.k2) && (this.k3 == other.k3)
                 && a.equals(other.a) && b.equals(other.b);
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java
index b5e9aa5..87608eb 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java
@@ -3,14 +3,17 @@
 import java.math.BigInteger;
 import java.util.Random;
 
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+
 public abstract class ECFieldElement
     implements ECConstants
 {
-
     public abstract BigInteger     toBigInteger();
     public abstract String         getFieldName();
     public abstract int            getFieldSize();
     public abstract ECFieldElement add(ECFieldElement b);
+    public abstract ECFieldElement addOne();
     public abstract ECFieldElement subtract(ECFieldElement b);
     public abstract ECFieldElement multiply(ECFieldElement b);
     public abstract ECFieldElement divide(ECFieldElement b);
@@ -19,27 +22,99 @@
     public abstract ECFieldElement invert();
     public abstract ECFieldElement sqrt();
 
+    public int bitLength()
+    {
+        return toBigInteger().bitLength();
+    }
+
+    public boolean isZero()
+    {
+        return 0 == toBigInteger().signum();
+    }
+
+    public boolean testBitZero()
+    {
+        return toBigInteger().testBit(0);
+    }
+
     public String toString()
     {
-        return this.toBigInteger().toString(2);
+        return this.toBigInteger().toString(16);
+    }
+
+    public byte[] getEncoded()
+    {
+        return BigIntegers.asUnsignedByteArray((getFieldSize() + 7) / 8, toBigInteger());
     }
 
     public static class Fp extends ECFieldElement
     {
-        BigInteger x;
+        BigInteger q, r, x;
 
-        BigInteger q;
-        
+//        static int[] calculateNaf(BigInteger p)
+//        {
+//            int[] naf = WNafUtil.generateCompactNaf(p);
+//
+//            int bit = 0;
+//            for (int i = 0; i < naf.length; ++i)
+//            {
+//                int ni = naf[i];
+//                int digit = ni >> 16, zeroes = ni & 0xFFFF;
+//
+//                bit += zeroes;
+//                naf[i] = digit < 0 ? ~bit : bit;
+//                ++bit;
+//            }
+//
+//            int last = naf.length - 1;
+//            if (last > 0 && last <= 16)
+//            {
+//                int top = naf[last], top2 = naf[last - 1];
+//                if (top2 < 0)
+//                {
+//                    top2 = ~top2;
+//                }
+//                if (top - top2 >= 64)
+//                {
+//                    return naf;
+//                }
+//            }
+//
+//            return null;
+//        }
+
+        static BigInteger calculateResidue(BigInteger p)
+        {
+            int bitLength = p.bitLength();
+            if (bitLength > 128)
+            {
+                BigInteger firstWord = p.shiftRight(bitLength - 64);
+                if (firstWord.longValue() == -1L)
+                {
+                    return ONE.shiftLeft(bitLength).subtract(p);
+                }
+            }
+            return null;
+        }
+
+        /**
+         * @deprecated Use ECCurve.fromBigInteger to construct field elements
+         */
         public Fp(BigInteger q, BigInteger x)
         {
-            this.x = x;
-            
-            if (x.compareTo(q) >= 0)
+            this(q, calculateResidue(q), x);
+        }
+
+        Fp(BigInteger q, BigInteger r, BigInteger x)
+        {
+            if (x == null || x.signum() < 0 || x.compareTo(q) >= 0)
             {
-                throw new IllegalArgumentException("x value too large in field element");
+                throw new IllegalArgumentException("x value invalid in Fp field element");
             }
 
             this.q = q;
+            this.r = r;
+            this.x = x;
         }
 
         public BigInteger toBigInteger()
@@ -66,40 +141,70 @@
         {
             return q;
         }
-        
+
         public ECFieldElement add(ECFieldElement b)
         {
-            return new Fp(q, x.add(b.toBigInteger()).mod(q));
+            return new Fp(q, r, modAdd(x, b.toBigInteger()));
+        }
+
+        public ECFieldElement addOne()
+        {
+            BigInteger x2 = x.add(ECConstants.ONE);
+            if (x2.compareTo(q) == 0)
+            {
+                x2 = ECConstants.ZERO;
+            }
+            return new Fp(q, r, x2);
         }
 
         public ECFieldElement subtract(ECFieldElement b)
         {
-            return new Fp(q, x.subtract(b.toBigInteger()).mod(q));
+            BigInteger x2 = b.toBigInteger();
+            BigInteger x3 = x.subtract(x2);
+            if (x3.signum() < 0)
+            {
+                x3 = x3.add(q);
+            }
+            return new Fp(q, r, x3);
         }
 
         public ECFieldElement multiply(ECFieldElement b)
         {
-            return new Fp(q, x.multiply(b.toBigInteger()).mod(q));
+            return new Fp(q, r, modMult(x, b.toBigInteger()));
         }
 
         public ECFieldElement divide(ECFieldElement b)
         {
-            return new Fp(q, x.multiply(b.toBigInteger().modInverse(q)).mod(q));
+            return new Fp(q, modMult(x, b.toBigInteger().modInverse(q)));
         }
 
         public ECFieldElement negate()
         {
-            return new Fp(q, x.negate().mod(q));
+            BigInteger x2;
+            if (x.signum() == 0)
+            {
+                x2 = x;
+            }
+            else if (ONE.equals(r))
+            {
+                x2 = q.xor(x);
+            }
+            else
+            {
+                x2 = q.subtract(x);
+            }
+            return new Fp(q, r, x2);
         }
 
         public ECFieldElement square()
         {
-            return new Fp(q, x.multiply(x).mod(q));
+            return new Fp(q, r, modMult(x, x));
         }
 
         public ECFieldElement invert()
         {
-            return new Fp(q, x.modInverse(q));
+            // TODO Modular inversion can be faster for a (Generalized) Mersenne Prime.
+            return new Fp(q, r, x.modInverse(q));
         }
 
         // D.1.4 91
@@ -120,7 +225,7 @@
             if (q.testBit(1))
             {
                 // z = g^(u+1) + p, p = 4u + 3
-                ECFieldElement z = new Fp(q, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q));
+                ECFieldElement z = new Fp(q, r, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q));
 
                 return z.square().equals(this) ? z : null;
             }
@@ -138,7 +243,7 @@
             BigInteger k = u.shiftLeft(1).add(ECConstants.ONE);
 
             BigInteger Q = this.x;
-            BigInteger fourQ = Q.shiftLeft(2).mod(q);
+            BigInteger fourQ = modDouble(modDouble(Q));
 
             BigInteger U, V;
             Random rand = new Random();
@@ -152,11 +257,11 @@
                 while (P.compareTo(q) >= 0
                     || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, q).equals(qMinusOne)));
 
-                BigInteger[] result = lucasSequence(q, P, Q, k);
+                BigInteger[] result = lucasSequence(P, Q, k);
                 U = result[0];
                 V = result[1];
 
-                if (V.multiply(V).mod(q).equals(fourQ))
+                if (modMult(V, V).equals(fourQ))
                 {
                     // Integer division by 2, mod q
                     if (V.testBit(0))
@@ -168,7 +273,7 @@
 
                     //assert V.multiply(V).mod(q).equals(x);
 
-                    return new ECFieldElement.Fp(q, V);
+                    return new ECFieldElement.Fp(q, r, V);
                 }
             }
             while (U.equals(ECConstants.ONE) || U.equals(qMinusOne));
@@ -230,8 +335,7 @@
 //            return r.multiply(r).multiply(x.modPow(q.subtract(ECConstants.TWO), q)).subtract(ECConstants.TWO).mod(p);
 //        }
 
-        private static BigInteger[] lucasSequence(
-            BigInteger  p,
+        private BigInteger[] lucasSequence(
             BigInteger  P,
             BigInteger  Q,
             BigInteger  k)
@@ -247,40 +351,122 @@
 
             for (int j = n - 1; j >= s + 1; --j)
             {
-                Ql = Ql.multiply(Qh).mod(p);
+                Ql = modMult(Ql, Qh);
 
                 if (k.testBit(j))
                 {
-                    Qh = Ql.multiply(Q).mod(p);
-                    Uh = Uh.multiply(Vh).mod(p);
-                    Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
-                    Vh = Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p);
+                    Qh = modMult(Ql, Q);
+                    Uh = modMult(Uh, Vh);
+                    Vl = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
+                    Vh = modReduce(Vh.multiply(Vh).subtract(Qh.shiftLeft(1)));
                 }
                 else
                 {
                     Qh = Ql;
-                    Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
-                    Vh = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
-                    Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
+                    Uh = modReduce(Uh.multiply(Vl).subtract(Ql));
+                    Vh = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
+                    Vl = modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));
                 }
             }
 
-            Ql = Ql.multiply(Qh).mod(p);
-            Qh = Ql.multiply(Q).mod(p);
-            Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
-            Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
-            Ql = Ql.multiply(Qh).mod(p);
+            Ql = modMult(Ql, Qh);
+            Qh = modMult(Ql, Q);
+            Uh = modReduce(Uh.multiply(Vl).subtract(Ql));
+            Vl = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
+            Ql = modMult(Ql, Qh);
 
             for (int j = 1; j <= s; ++j)
             {
-                Uh = Uh.multiply(Vl).mod(p);
-                Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
-                Ql = Ql.multiply(Ql).mod(p);
+                Uh = modMult(Uh, Vl);
+                Vl = modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));
+                Ql = modMult(Ql, Ql);
             }
 
             return new BigInteger[]{ Uh, Vl };
         }
-        
+
+        protected BigInteger modAdd(BigInteger x1, BigInteger x2)
+        {
+            BigInteger x3 = x1.add(x2);
+            if (x3.compareTo(q) >= 0)
+            {
+                x3 = x3.subtract(q);
+            }
+            return x3;
+        }
+
+        protected BigInteger modDouble(BigInteger x)
+        {
+            BigInteger _2x = x.shiftLeft(1);
+            if (_2x.compareTo(q) >= 0)
+            {
+                _2x = _2x.subtract(q);
+            }
+            return _2x;
+        }
+
+        protected BigInteger modMult(BigInteger x1, BigInteger x2)
+        {
+            return modReduce(x1.multiply(x2));
+        }
+
+        protected BigInteger modReduce(BigInteger x)
+        {
+//            if (naf != null)
+//            {
+//                int last = naf.length - 1;
+//                int bits = naf[last];
+//                while (x.bitLength() > (bits + 1))
+//                {
+//                    BigInteger u = x.shiftRight(bits);
+//                    BigInteger v = x.subtract(u.shiftLeft(bits));
+//
+//                    x = v;
+//
+//                    for (int i = 0; i < last; ++i)
+//                    {
+//                        int ni = naf[i];
+//                        if (ni < 0)
+//                        {
+//                            x = x.add(u.shiftLeft(~ni));
+//                        }
+//                        else
+//                        {
+//                            x = x.subtract(u.shiftLeft(ni));
+//                        }
+//                    }
+//                }
+//                while (x.compareTo(q) >= 0)
+//                {
+//                    x = x.subtract(q);
+//                }
+//            }
+//            else
+            if (r != null)
+            {
+                int qLen = q.bitLength();
+                while (x.bitLength() > (qLen + 1))
+                {
+                    BigInteger u = x.shiftRight(qLen);
+                    BigInteger v = x.subtract(u.shiftLeft(qLen));
+                    if (!r.equals(ONE))
+                    {
+                        u = u.multiply(r);
+                    }
+                    x = u.add(v); 
+                }
+                while (x.compareTo(q) >= 0)
+                {
+                    x = x.subtract(q);
+                }
+            }
+            else
+            {
+                x = x.mod(q);
+            }
+            return x;
+        }
+
         public boolean equals(Object other)
         {
             if (other == this)
@@ -669,7 +855,7 @@
 //                g1z = g1z.xor(g2z.shiftLeft(j));
 ////                if (g1z.bitLength() > this.m) {
 ////                    throw new ArithmeticException(
-////                            "deg(g1z) >= m, g1z = " + g1z.toString(2));
+////                            "deg(g1z) >= m, g1z = " + g1z.toString(16));
 ////                }
 //            }
 //            return new ECFieldElement.F2m(
@@ -801,41 +987,38 @@
          */
         private int m;
 
-        /**
-         * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
-         * x<sup>k</sup> + 1</code> represents the reduction polynomial
-         * <code>f(z)</code>.<br>
-         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
-         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-         * represents the reduction polynomial <code>f(z)</code>.<br>
-         */
-        private int k1;
+//        /**
+//         * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+//         * x<sup>k</sup> + 1</code> represents the reduction polynomial
+//         * <code>f(z)</code>.<br>
+//         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.<br>
+//         */
+//        private int k1;
+//
+//        /**
+//         * TPB: Always set to <code>0</code><br>
+//         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.<br>
+//         */
+//        private int k2;
+//
+//        /**
+//         * TPB: Always set to <code>0</code><br>
+//         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+//         * represents the reduction polynomial <code>f(z)</code>.<br>
+//         */
+//        private int k3;
+
+        private int[] ks;
 
         /**
-         * TPB: Always set to <code>0</code><br>
-         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
-         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-         * represents the reduction polynomial <code>f(z)</code>.<br>
+         * The <code>LongArray</code> holding the bits.
          */
-        private int k2;
-
-        /**
-         * TPB: Always set to <code>0</code><br>
-         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
-         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-         * represents the reduction polynomial <code>f(z)</code>.<br>
-         */
-        private int k3;
-
-        /**
-         * The <code>IntArray</code> holding the bits.
-         */
-        private IntArray x;
-
-        /**
-         * The number of <code>int</code>s required to hold <code>m</code> bits.
-         */
-        private int t;
+        private LongArray x;
 
         /**
          * Constructor for PPB.
@@ -851,6 +1034,7 @@
          * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
          * represents the reduction polynomial <code>f(z)</code>.
          * @param x The BigInteger representing the value of the field element.
+         * @deprecated Use ECCurve.fromBigInteger to construct field elements
          */
         public F2m(
             int m, 
@@ -859,13 +1043,10 @@
             int k3,
             BigInteger x)
         {
-            // t = m / 32 rounded up to the next integer
-            t = (m + 31) >> 5;
-            this.x = new IntArray(x, t);
-
             if ((k2 == 0) && (k3 == 0))
             {
                 this.representation = TPB;
+                this.ks = new int[]{ k1 }; 
             }
             else
             {
@@ -880,17 +1061,11 @@
                             "k2 must be larger than 0");
                 }
                 this.representation = PPB;
-            }
-
-            if (x.signum() < 0)
-            {
-                throw new IllegalArgumentException("x value cannot be negative");
+                this.ks = new int[]{ k1, k2, k3 }; 
             }
 
             this.m = m;
-            this.k1 = k1;
-            this.k2 = k2;
-            this.k3 = k3;
+            this.x = new LongArray(x);
         }
 
         /**
@@ -901,6 +1076,7 @@
          * x<sup>k</sup> + 1</code> represents the reduction
          * polynomial <code>f(z)</code>.
          * @param x The BigInteger representing the value of the field element.
+         * @deprecated Use ECCurve.fromBigInteger to construct field elements
          */
         public F2m(int m, int k, BigInteger x)
         {
@@ -908,24 +1084,27 @@
             this(m, k, 0, 0, x);
         }
 
-        private F2m(int m, int k1, int k2, int k3, IntArray x)
+        private F2m(int m, int[] ks, LongArray x)
         {
-            t = (m + 31) >> 5;
-            this.x = x;
             this.m = m;
-            this.k1 = k1;
-            this.k2 = k2;
-            this.k3 = k3;
+            this.representation = (ks.length == 1) ? TPB : PPB;
+            this.ks = ks;
+            this.x = x;
+        }
 
-            if ((k2 == 0) && (k3 == 0))
-            {
-                this.representation = TPB;
-            }
-            else
-            {
-                this.representation = PPB;
-            }
+        public int bitLength()
+        {
+            return x.degree();
+        }
 
+        public boolean isZero()
+        {
+            return x.isZero();
+        }
+
+        public boolean testBitZero()
+        {
+            return x.testBitZero();
         }
 
         public BigInteger toBigInteger()
@@ -967,19 +1146,15 @@
             ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a;
             ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b;
 
-            if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1)
-                    || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3))
-            {
-                throw new IllegalArgumentException("Field elements are not "
-                        + "elements of the same field F2m");
-            }
-
             if (aF2m.representation != bF2m.representation)
             {
                 // Should never occur
-                throw new IllegalArgumentException(
-                        "One of the field "
-                                + "elements are not elements has incorrect representation");
+                throw new IllegalArgumentException("One of the F2m field elements has incorrect representation");
+            }
+
+            if ((aF2m.m != bF2m.m) || !Arrays.areEqual(aF2m.ks, bF2m.ks))
+            {
+                throw new IllegalArgumentException("Field elements are not elements of the same field F2m");
             }
         }
 
@@ -988,10 +1163,15 @@
             // No check performed here for performance reasons. Instead the
             // elements involved are checked in ECPoint.F2m
             // checkFieldElements(this, b);
-            IntArray iarrClone = (IntArray)this.x.clone();
+            LongArray iarrClone = (LongArray)this.x.clone();
             F2m bF2m = (F2m)b;
-            iarrClone.addShifted(bF2m.x, 0);
-            return new F2m(m, k1, k2, k3, iarrClone);
+            iarrClone.addShiftedByWords(bF2m.x, 0);
+            return new F2m(m, ks, iarrClone);
+        }
+
+        public ECFieldElement addOne()
+        {
+            return new F2m(m, ks, x.addOne());
         }
 
         public ECFieldElement subtract(final ECFieldElement b)
@@ -1002,17 +1182,14 @@
 
         public ECFieldElement multiply(final ECFieldElement b)
         {
-            // Right-to-left comb multiplication in the IntArray
+            // Right-to-left comb multiplication in the LongArray
             // Input: Binary polynomials a(z) and b(z) of degree at most m-1
             // Output: c(z) = a(z) * b(z) mod f(z)
 
             // No check performed here for performance reasons. Instead the
             // elements involved are checked in ECPoint.F2m
             // checkFieldElements(this, b);
-            F2m bF2m = (F2m)b;
-            IntArray mult = x.multiply(bF2m.x, m);
-            mult.reduce(m, new int[]{k1, k2, k3});
-            return new F2m(m, k1, k2, k3, mult);
+            return new F2m(m, ks, x.modMultiply(((F2m)b).x, m, ks));
         }
 
         public ECFieldElement divide(final ECFieldElement b)
@@ -1030,80 +1207,12 @@
 
         public ECFieldElement square()
         {
-            IntArray squared = x.square(m);
-            squared.reduce(m, new int[]{k1, k2, k3});
-            return new F2m(m, k1, k2, k3, squared);
+            return new F2m(m, ks, x.modSquare(m, ks));
         }
 
-
         public ECFieldElement invert()
         {
-            // Inversion in F2m using the extended Euclidean algorithm
-            // Input: A nonzero polynomial a(z) of degree at most m-1
-            // Output: a(z)^(-1) mod f(z)
-
-            // u(z) := a(z)
-            IntArray uz = (IntArray)this.x.clone();
-
-            // v(z) := f(z)
-            IntArray vz = new IntArray(t);
-            vz.setBit(m);
-            vz.setBit(0);
-            vz.setBit(this.k1);
-            if (this.representation == PPB) 
-            {
-                vz.setBit(this.k2);
-                vz.setBit(this.k3);
-            }
-
-            // g1(z) := 1, g2(z) := 0
-            IntArray g1z = new IntArray(t);
-            g1z.setBit(0);
-            IntArray g2z = new IntArray(t);
-
-            // while u != 0
-            while (!uz.isZero())
-//            while (uz.getUsedLength() > 0)
-//            while (uz.bitLength() > 1)
-            {
-                // j := deg(u(z)) - deg(v(z))
-                int j = uz.bitLength() - vz.bitLength();
-
-                // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j
-                if (j < 0) 
-                {
-                    final IntArray uzCopy = uz;
-                    uz = vz;
-                    vz = uzCopy;
-
-                    final IntArray g1zCopy = g1z;
-                    g1z = g2z;
-                    g2z = g1zCopy;
-
-                    j = -j;
-                }
-
-                // u(z) := u(z) + z^j * v(z)
-                // Note, that no reduction modulo f(z) is required, because
-                // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z)))
-                // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z))
-                // = deg(u(z))
-                // uz = uz.xor(vz.shiftLeft(j));
-                // jInt = n / 32
-                int jInt = j >> 5;
-                // jInt = n % 32
-                int jBit = j & 0x1F;
-                IntArray vzShift = vz.shiftLeft(jBit);
-                uz.addShifted(vzShift, jInt);
-
-                // g1(z) := g1(z) + z^j * g2(z)
-//                g1z = g1z.xor(g2z.shiftLeft(j));
-                IntArray g2zShift = g2z.shiftLeft(jBit);
-                g1z.addShifted(g2zShift, jInt);
-                
-            }
-            return new ECFieldElement.F2m(
-                    this.m, this.k1, this.k2, this.k3, g2z);
+            return new ECFieldElement.F2m(this.m, this.ks, this.x.modInverse(m, ks));
         }
 
         public ECFieldElement sqrt()
@@ -1143,7 +1252,7 @@
          */
         public int getK1()
         {
-            return this.k1;
+            return this.ks[0];
         }
 
         /**
@@ -1154,7 +1263,7 @@
          */
         public int getK2()
         {
-            return this.k2;
+            return this.ks.length >= 2 ? this.ks[1] : 0;
         }
 
         /**
@@ -1165,7 +1274,7 @@
          */
         public int getK3()
         {
-            return this.k3;
+            return this.ks.length >= 3 ? this.ks[2] : 0;
         }
 
         public boolean equals(Object anObject)
@@ -1182,15 +1291,15 @@
 
             ECFieldElement.F2m b = (ECFieldElement.F2m)anObject;
             
-            return ((this.m == b.m) && (this.k1 == b.k1) && (this.k2 == b.k2)
-                && (this.k3 == b.k3)
+            return ((this.m == b.m)
                 && (this.representation == b.representation)
+                && Arrays.areEqual(this.ks, b.ks)
                 && (this.x.equals(b.x)));
         }
 
         public int hashCode()
         {
-            return x.hashCode() ^ m ^ k1 ^ k2 ^ k3;
+            return x.hashCode() ^ m ^ Arrays.hashCode(ks);
         }
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java
index 4d72e33..da1013a 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java
@@ -6,14 +6,14 @@
  * Interface for classes encapsulating a point multiplication algorithm
  * for <code>ECPoint</code>s.
  */
-interface ECMultiplier
+public interface ECMultiplier
 {
     /**
      * Multiplies the <code>ECPoint p</code> by <code>k</code>, i.e.
      * <code>p</code> is added <code>k</code> times to itself.
      * @param p The <code>ECPoint</code> to be multiplied.
-     * @param k The factor by which <code>p</code> i multiplied.
+     * @param k The factor by which <code>p</code> is multiplied.
      * @return <code>p</code> multiplied by <code>k</code>.
      */
-    ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo);
+    ECPoint multiply(ECPoint p, BigInteger k);
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java
index cbc5aaf..7f740e4 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java
@@ -2,59 +2,324 @@
 
 import java.math.BigInteger;
 
-import org.bouncycastle.asn1.x9.X9IntegerConverter;
-
 /**
  * base class for points on elliptic curves.
  */
 public abstract class ECPoint
 {
-    ECCurve        curve;
-    ECFieldElement x;
-    ECFieldElement y;
+    protected static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0];
+
+    protected static ECFieldElement[] getInitialZCoords(ECCurve curve)
+    {
+        // Cope with null curve, most commonly used by implicitlyCa
+        int coord = null == curve ? ECCurve.COORD_AFFINE : curve.getCoordinateSystem();
+
+        switch (coord)
+        {
+        case ECCurve.COORD_AFFINE:
+        case ECCurve.COORD_LAMBDA_AFFINE:
+            return EMPTY_ZS;
+        default:
+            break;
+        }
+
+        ECFieldElement one = curve.fromBigInteger(ECConstants.ONE);
+
+        switch (coord)
+        {
+        case ECCurve.COORD_HOMOGENEOUS:
+        case ECCurve.COORD_JACOBIAN:
+        case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            return new ECFieldElement[]{ one };
+        case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+            return new ECFieldElement[]{ one, one, one };
+        case ECCurve.COORD_JACOBIAN_MODIFIED:
+            return new ECFieldElement[]{ one, curve.getA() };
+        default:
+            throw new IllegalArgumentException("unknown coordinate system");
+        }
+    }
+
+    protected ECCurve curve;
+    protected ECFieldElement x;
+    protected ECFieldElement y;
+    protected ECFieldElement[] zs;
 
     protected boolean withCompression;
 
-    protected ECMultiplier multiplier = null;
-
     protected PreCompInfo preCompInfo = null;
 
-    private static X9IntegerConverter converter = new X9IntegerConverter();
-
     protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
     {
+        this(curve, x, y, getInitialZCoords(curve));
+    }
+
+    protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs)
+    {
         this.curve = curve;
         this.x = x;
         this.y = y;
+        this.zs = zs;
     }
-    
+
     public ECCurve getCurve()
     {
         return curve;
     }
-    
+
+    protected int getCurveCoordinateSystem()
+    {
+        // Cope with null curve, most commonly used by implicitlyCa
+        return null == curve ? ECCurve.COORD_AFFINE : curve.getCoordinateSystem();
+    }
+
+    /**
+     * Normalizes this point, and then returns the affine x-coordinate.
+     * 
+     * Note: normalization can be expensive, this method is deprecated in favour
+     * of caller-controlled normalization.
+     * 
+     * @deprecated Use getAffineXCoord, or normalize() and getXCoord(), instead
+     */
     public ECFieldElement getX()
     {
+        return normalize().getXCoord();
+    }
+
+
+    /**
+     * Normalizes this point, and then returns the affine y-coordinate.
+     * 
+     * Note: normalization can be expensive, this method is deprecated in favour
+     * of caller-controlled normalization.
+     * 
+     * @deprecated Use getAffineYCoord, or normalize() and getYCoord(), instead
+     */
+    public ECFieldElement getY()
+    {
+        return normalize().getYCoord();
+    }
+
+    /**
+     * Returns the affine x-coordinate after checking that this point is normalized.
+     * 
+     * @return The affine x-coordinate of this point
+     * @throws IllegalStateException if the point is not normalized
+     */
+    public ECFieldElement getAffineXCoord()
+    {
+        checkNormalized();
+        return getXCoord();
+    }
+
+    /**
+     * Returns the affine y-coordinate after checking that this point is normalized
+     * 
+     * @return The affine y-coordinate of this point
+     * @throws IllegalStateException if the point is not normalized
+     */
+    public ECFieldElement getAffineYCoord()
+    {
+        checkNormalized();
+        return getYCoord();
+    }
+
+    /**
+     * Returns the x-coordinate.
+     * 
+     * Caution: depending on the curve's coordinate system, this may not be the same value as in an
+     * affine coordinate system; use normalize() to get a point where the coordinates have their
+     * affine values, or use getAffineXCoord if you expect the point to already have been
+     * normalized.
+     * 
+     * @return the x-coordinate of this point
+     */
+    public ECFieldElement getXCoord()
+    {
         return x;
     }
 
-    public ECFieldElement getY()
+    /**
+     * Returns the y-coordinate.
+     * 
+     * Caution: depending on the curve's coordinate system, this may not be the same value as in an
+     * affine coordinate system; use normalize() to get a point where the coordinates have their
+     * affine values, or use getAffineYCoord if you expect the point to already have been
+     * normalized.
+     * 
+     * @return the y-coordinate of this point
+     */
+    public ECFieldElement getYCoord()
     {
         return y;
     }
 
+    public ECFieldElement getZCoord(int index)
+    {
+        return (index < 0 || index >= zs.length) ? null : zs[index];
+    }
+
+    public ECFieldElement[] getZCoords()
+    {
+        int zsLen = zs.length;
+        if (zsLen == 0)
+        {
+            return zs;
+        }
+        ECFieldElement[] copy = new ECFieldElement[zsLen];
+        System.arraycopy(zs, 0, copy, 0, zsLen);
+        return copy;
+    }
+
+    protected ECFieldElement getRawXCoord()
+    {
+        return x;
+    }
+
+    protected ECFieldElement getRawYCoord()
+    {
+        return y;
+    }
+
+    protected void checkNormalized()
+    {
+        if (!isNormalized())
+        {
+            throw new IllegalStateException("point not in normal form");
+        }
+    }
+
+    public boolean isNormalized()
+    {
+        int coord = this.getCurveCoordinateSystem();
+
+        return coord == ECCurve.COORD_AFFINE
+            || coord == ECCurve.COORD_LAMBDA_AFFINE
+            || isInfinity()
+            || zs[0].bitLength() == 1;
+    }
+
+    /**
+     * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+     * coordinates reflect those of the equivalent point in an affine coordinate system.
+     * 
+     * @return a new ECPoint instance representing the same point, but with normalized coordinates
+     */
+    public ECPoint normalize()
+    {
+        if (this.isInfinity())
+        {
+            return this;
+        }
+
+        switch (this.getCurveCoordinateSystem())
+        {
+        case ECCurve.COORD_AFFINE:
+        case ECCurve.COORD_LAMBDA_AFFINE:
+        {
+            return this;
+        }
+        default:
+        {
+            ECFieldElement Z1 = getZCoord(0);
+            if (Z1.bitLength() == 1)
+            {
+                return this;
+            }
+
+            return normalize(Z1.invert());
+        }
+        }
+    }
+
+    ECPoint normalize(ECFieldElement zInv)
+    {
+        switch (this.getCurveCoordinateSystem())
+        {
+        case ECCurve.COORD_HOMOGENEOUS:
+        case ECCurve.COORD_LAMBDA_PROJECTIVE:
+        {
+            return createScaledPoint(zInv, zInv);
+        }
+        case ECCurve.COORD_JACOBIAN:
+        case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+        case ECCurve.COORD_JACOBIAN_MODIFIED:
+        {
+            ECFieldElement zInv2 = zInv.square(), zInv3 = zInv2.multiply(zInv);
+            return createScaledPoint(zInv2, zInv3);
+        }
+        default:
+        {
+            throw new IllegalStateException("not a projective coordinate system");
+        }
+        }
+    }
+
+    protected ECPoint createScaledPoint(ECFieldElement sx, ECFieldElement sy)
+    {
+        return this.getCurve().createRawPoint(getRawXCoord().multiply(sx), getRawYCoord().multiply(sy), this.withCompression);
+    }
+
     public boolean isInfinity()
     {
-        return x == null && y == null;
+        return x == null || y == null || (zs.length > 0 && zs[0].isZero());
     }
 
     public boolean isCompressed()
     {
-        return withCompression;
+        return this.withCompression;
     }
 
-    public boolean equals(
-        Object  other)
+    public boolean equals(ECPoint other)
+    {
+        if (null == other)
+        {
+            return false;
+        }
+
+        ECCurve c1 = this.getCurve(), c2 = other.getCurve();
+        boolean n1 = (null == c1), n2 = (null == c2);
+        boolean i1 = isInfinity(), i2 = other.isInfinity();
+
+        if (i1 || i2)
+        {
+            return (i1 && i2) && (n1 || n2 || c1.equals(c2));
+        }
+
+        ECPoint p1 = this, p2 = other;
+        if (n1 && n2)
+        {
+            // Points with null curve are in affine form, so already normalized
+        }
+        else if (n1)
+        {
+            p2 = p2.normalize();
+        }
+        else if (n2)
+        {
+            p1 = p1.normalize();
+        }
+        else if (!c1.equals(c2))
+        {
+            return false;
+        }
+        else
+        {
+            // TODO Consider just requiring already normalized, to avoid silent performance degradation
+
+            ECPoint[] points = new ECPoint[]{ this, c1.importPoint(p2) };
+
+            // TODO This is a little strong, really only requires coZNormalizeAll to get Zs equal
+            c1.normalizeAll(points);
+
+            p1 = points[0];
+            p2 = points[1];
+        }
+
+        return p1.getXCoord().equals(p2.getXCoord()) && p1.getYCoord().equals(p2.getYCoord());
+    }
+
+    public boolean equals(Object other)
     {
         if (other == this)
         {
@@ -66,69 +331,117 @@
             return false;
         }
 
-        ECPoint o = (ECPoint)other;
-
-        if (this.isInfinity())
-        {
-            return o.isInfinity();
-        }
-
-        return x.equals(o.x) && y.equals(o.y);
+        return equals((ECPoint)other);
     }
 
     public int hashCode()
     {
-        if (this.isInfinity())
+        ECCurve c = this.getCurve();
+        int hc = (null == c) ? 0 : ~c.hashCode();
+
+        if (!this.isInfinity())
         {
-            return 0;
+            // TODO Consider just requiring already normalized, to avoid silent performance degradation
+
+            ECPoint p = normalize();
+
+            hc ^= p.getXCoord().hashCode() * 17;
+            hc ^= p.getYCoord().hashCode() * 257;
         }
-        
-        return x.hashCode() ^ y.hashCode();
+
+        return hc;
     }
 
-//    /**
-//     * Mainly for testing. Explicitly set the <code>ECMultiplier</code>.
-//     * @param multiplier The <code>ECMultiplier</code> to be used to multiply
-//     * this <code>ECPoint</code>.
-//     */
-//    public void setECMultiplier(ECMultiplier multiplier)
-//    {
-//        this.multiplier = multiplier;
-//    }
-
-    /**
-     * Sets the <code>PreCompInfo</code>. Used by <code>ECMultiplier</code>s
-     * to save the precomputation for this <code>ECPoint</code> to store the
-     * precomputation result for use by subsequent multiplication.
-     * @param preCompInfo The values precomputed by the
-     * <code>ECMultiplier</code>.
-     */
-    void setPreCompInfo(PreCompInfo preCompInfo)
+    public String toString()
     {
-        this.preCompInfo = preCompInfo;
+        if (this.isInfinity())
+        {
+            return "INF";
+        }
+
+        StringBuffer sb = new StringBuffer();
+        sb.append('(');
+        sb.append(getRawXCoord());
+        sb.append(',');
+        sb.append(getRawYCoord());
+        for (int i = 0; i < zs.length; ++i)
+        {
+            sb.append(',');
+            sb.append(zs[i]);
+        }
+        sb.append(')');
+        return sb.toString();
     }
 
     public byte[] getEncoded()
     {
-        return getEncoded(withCompression);
+        return getEncoded(this.withCompression);
     }
 
-    public abstract byte[] getEncoded(boolean compressed);
+    /**
+     * return the field element encoded with point compression. (S 4.3.6)
+     */
+    public byte[] getEncoded(boolean compressed)
+    {
+        if (this.isInfinity())
+        {
+            return new byte[1];
+        }
+
+        ECPoint normed = normalize();
+
+        byte[] X = normed.getXCoord().getEncoded();
+
+        if (compressed)
+        {
+            byte[] PO = new byte[X.length + 1];
+            PO[0] = (byte)(normed.getCompressionYTilde() ? 0x03 : 0x02);
+            System.arraycopy(X, 0, PO, 1, X.length);
+            return PO;
+        }
+
+        byte[] Y = normed.getYCoord().getEncoded();
+
+        byte[] PO = new byte[X.length + Y.length + 1];
+        PO[0] = 0x04;
+        System.arraycopy(X, 0, PO, 1, X.length);
+        System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
+        return PO;
+    }
+
+    protected abstract boolean getCompressionYTilde();
 
     public abstract ECPoint add(ECPoint b);
-    public abstract ECPoint subtract(ECPoint b);
+
     public abstract ECPoint negate();
+
+    public abstract ECPoint subtract(ECPoint b);
+
+    public ECPoint timesPow2(int e)
+    {
+        if (e < 0)
+        {
+            throw new IllegalArgumentException("'e' cannot be negative");
+        }
+
+        ECPoint p = this;
+        while (--e >= 0)
+        {
+            p = p.twice();
+        }
+        return p;
+    }
+
     public abstract ECPoint twice();
 
-    /**
-     * Sets the default <code>ECMultiplier</code>, unless already set. 
-     */
-    synchronized void assertECMultiplier()
+    public ECPoint twicePlus(ECPoint b)
     {
-        if (this.multiplier == null)
-        {
-            this.multiplier = new FpNafMultiplier();
-        }
+        return twice().add(b);
+    }
+
+    public ECPoint threeTimes()
+    {
+        return twicePlus(this);
     }
 
     /**
@@ -138,23 +451,7 @@
      */
     public ECPoint multiply(BigInteger k)
     {
-        if (k.signum() < 0)
-        {
-            throw new IllegalArgumentException("The multiplicator cannot be negative");
-        }
-
-        if (this.isInfinity())
-        {
-            return this;
-        }
-
-        if (k.signum() == 0)
-        {
-            return this.curve.getInfinity();
-        }
-
-        assertECMultiplier();
-        return this.multiplier.multiply(this, k, preCompInfo);
+        return this.getCurve().getMultiplier().multiply(this, k);
     }
 
     /**
@@ -162,13 +459,14 @@
      */
     public static class Fp extends ECPoint
     {
-        
         /**
          * Create a point which encodes with point compression.
          * 
          * @param curve the curve to use
          * @param x affine x co-ordinate
          * @param y affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
          */
         public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y)
         {
@@ -182,6 +480,8 @@
          * @param x affine x co-ordinate
          * @param y affine y co-ordinate
          * @param withCompression if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)}
          */
         public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
         {
@@ -194,52 +494,27 @@
 
             this.withCompression = withCompression;
         }
-         
-        /**
-         * return the field element encoded with point compression. (S 4.3.6)
-         */
-        public byte[] getEncoded(boolean compressed)
+
+        Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
         {
-            if (this.isInfinity()) 
+            super(curve, x, y, zs);
+
+            this.withCompression = withCompression;
+        }
+
+        protected boolean getCompressionYTilde()
+        {
+            return this.getAffineYCoord().testBitZero();
+        }
+
+        public ECFieldElement getZCoord(int index)
+        {
+            if (index == 1 && ECCurve.COORD_JACOBIAN_MODIFIED == this.getCurveCoordinateSystem())
             {
-                return new byte[1];
+                return getJacobianModifiedW();
             }
 
-            int qLength = converter.getByteLength(x);
-            
-            if (compressed)
-            {
-                byte    PC;
-    
-                if (this.getY().toBigInteger().testBit(0))
-                {
-                    PC = 0x03;
-                }
-                else
-                {
-                    PC = 0x02;
-                }
-    
-                byte[]  X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
-                byte[]  PO = new byte[X.length + 1];
-    
-                PO[0] = PC;
-                System.arraycopy(X, 0, PO, 1, X.length);
-    
-                return PO;
-            }
-            else
-            {
-                byte[]  X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
-                byte[]  Y = converter.integerToBytes(this.getY().toBigInteger(), qLength);
-                byte[]  PO = new byte[X.length + Y.length + 1];
-                
-                PO[0] = 0x04;
-                System.arraycopy(X, 0, PO, 1, X.length);
-                System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
-
-                return PO;
-            }
+            return super.getZCoord(index);
         }
 
         // B.3 pg 62
@@ -249,31 +524,222 @@
             {
                 return b;
             }
-
             if (b.isInfinity())
             {
                 return this;
             }
-
-            // Check if b = this or b = -this
-            if (this.x.equals(b.x))
+            if (this == b)
             {
-                if (this.y.equals(b.y))
-                {
-                    // this = b, i.e. this must be doubled
-                    return this.twice();
-                }
-
-                // this = -b, i.e. the result is the point at infinity
-                return this.curve.getInfinity();
+                return twice();
             }
 
-            ECFieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x));
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
 
-            ECFieldElement x3 = gamma.square().subtract(this.x).subtract(b.x);
-            ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
+            ECFieldElement X1 = this.x, Y1 = this.y;
+            ECFieldElement X2 = b.x, Y2 = b.y;
 
-            return new ECPoint.Fp(curve, x3, y3, withCompression);
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement dx = X2.subtract(X1), dy = Y2.subtract(Y1);
+
+                if (dx.isZero())
+                {
+                    if (dy.isZero())
+                    {
+                        // this == b, i.e. this must be doubled
+                        return twice();
+                    }
+
+                    // this == -b, i.e. the result is the point at infinity
+                    return curve.getInfinity();
+                }
+
+                ECFieldElement gamma = dy.divide(dx);
+                ECFieldElement X3 = gamma.square().subtract(X1).subtract(X2);
+                ECFieldElement Y3 = gamma.multiply(X1.subtract(X3)).subtract(Y1);
+
+                return new ECPoint.Fp(curve, X3, Y3, this.withCompression);
+            }
+
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Z1 = this.zs[0];
+                ECFieldElement Z2 = b.zs[0];
+
+                boolean Z1IsOne = Z1.bitLength() == 1;
+                boolean Z2IsOne = Z2.bitLength() == 1;
+
+                ECFieldElement u1 = Z1IsOne ? Y2 : Y2.multiply(Z1);
+                ECFieldElement u2 = Z2IsOne ? Y1 : Y1.multiply(Z2);
+                ECFieldElement u = u1.subtract(u2);
+                ECFieldElement v1 = Z1IsOne ? X2 : X2.multiply(Z1);
+                ECFieldElement v2 = Z2IsOne ? X1 : X1.multiply(Z2);
+                ECFieldElement v = v1.subtract(v2);
+
+                // Check if b == this or b == -this
+                if (v.isZero())
+                {
+                    if (u.isZero())
+                    {
+                        // this == b, i.e. this must be doubled
+                        return this.twice();
+                    }
+
+                    // this == -b, i.e. the result is the point at infinity
+                    return curve.getInfinity();
+                }
+
+                // TODO Optimize for when w == 1
+                ECFieldElement w = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.multiply(Z2);
+                ECFieldElement vSquared = v.square();
+                ECFieldElement vCubed = vSquared.multiply(v);
+                ECFieldElement vSquaredV2 = vSquared.multiply(v2);
+                ECFieldElement A = u.square().multiply(w).subtract(vCubed).subtract(two(vSquaredV2));
+
+                ECFieldElement X3 = v.multiply(A);
+                ECFieldElement Y3 = vSquaredV2.subtract(A).multiply(u).subtract(vCubed.multiply(u2));
+                ECFieldElement Z3 = vCubed.multiply(w);
+
+                return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+
+            case ECCurve.COORD_JACOBIAN:
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+            {
+                ECFieldElement Z1 = this.zs[0];
+                ECFieldElement Z2 = b.zs[0];
+
+                boolean Z1IsOne = Z1.bitLength() == 1;
+
+                ECFieldElement X3, Y3, Z3, Z3Squared = null;
+
+                if (!Z1IsOne && Z1.equals(Z2))
+                {
+                    // TODO Make this available as public method coZAdd?
+
+                    ECFieldElement dx = X1.subtract(X2), dy = Y1.subtract(Y2);
+                    if (dx.isZero())
+                    {
+                        if (dy.isZero())
+                        {
+                            return twice();
+                        }
+                        return curve.getInfinity();
+                    }
+
+                    ECFieldElement C = dx.square();
+                    ECFieldElement W1 = X1.multiply(C), W2 = X2.multiply(C);
+                    ECFieldElement A1 = W1.subtract(W2).multiply(Y1);
+
+                    X3 = dy.square().subtract(W1).subtract(W2);
+                    Y3 = W1.subtract(X3).multiply(dy).subtract(A1);
+                    Z3 = dx;
+
+                    if (Z1IsOne)
+                    {
+                        Z3Squared = C;
+                    }
+                    else
+                    {
+                        Z3 = Z3.multiply(Z1);
+                    }
+                }
+                else
+                {
+                    ECFieldElement Z1Squared, U2, S2;
+                    if (Z1IsOne)
+                    {
+                        Z1Squared = Z1; U2 = X2; S2 = Y2;
+                    }
+                    else
+                    {
+                        Z1Squared = Z1.square();
+                        U2 = Z1Squared.multiply(X2);
+                        ECFieldElement Z1Cubed = Z1Squared.multiply(Z1);
+                        S2 = Z1Cubed.multiply(Y2);
+                    }
+
+                    boolean Z2IsOne = Z2.bitLength() == 1;
+                    ECFieldElement Z2Squared, U1, S1;
+                    if (Z2IsOne)
+                    {
+                        Z2Squared = Z2; U1 = X1; S1 = Y1;
+                    }
+                    else
+                    {
+                        Z2Squared = Z2.square();
+                        U1 = Z2Squared.multiply(X1); 
+                        ECFieldElement Z2Cubed = Z2Squared.multiply(Z2);
+                        S1 = Z2Cubed.multiply(Y1);
+                    }
+
+                    ECFieldElement H = U1.subtract(U2);
+                    ECFieldElement R = S1.subtract(S2);
+    
+                    // Check if b == this or b == -this
+                    if (H.isZero())
+                    {
+                        if (R.isZero())
+                        {
+                            // this == b, i.e. this must be doubled
+                            return this.twice();
+                        }
+    
+                        // this == -b, i.e. the result is the point at infinity
+                        return curve.getInfinity();
+                    }
+    
+                    ECFieldElement HSquared = H.square();
+                    ECFieldElement G = HSquared.multiply(H);
+                    ECFieldElement V = HSquared.multiply(U1);
+    
+                    X3 = R.square().add(G).subtract(two(V));
+                    Y3 = V.subtract(X3).multiply(R).subtract(S1.multiply(G));
+    
+                    Z3 = H;
+                    if (!Z1IsOne)
+                    {
+                        Z3 = Z3.multiply(Z1);
+                    }
+                    if (!Z2IsOne)
+                    {
+                        Z3 = Z3.multiply(Z2);
+                    }
+    
+                    // Alternative calculation of Z3 using fast square
+    //                X3 = four(X3);
+    //                Y3 = eight(Y3);
+    //                Z3 = doubleProductFromSquares(Z1, Z2, Z1Squared, Z2Squared).multiply(H);
+                    
+                    if (Z3 == H)
+                    {
+                        Z3Squared = HSquared;
+                    }
+                }
+
+                ECFieldElement[] zs;
+                if (coord == ECCurve.COORD_JACOBIAN_MODIFIED)
+                {
+                    // TODO If the result will only be used in a subsequent addition, we don't need W3
+                    ECFieldElement W3 = calculateJacobianModifiedW(Z3, Z3Squared);
+
+                    zs = new ECFieldElement[]{ Z3, W3 };
+                }
+                else
+                {
+                    zs = new ECFieldElement[]{ Z3 };
+                }
+
+                return new ECPoint.Fp(curve, X3, Y3, zs, this.withCompression);
+            }
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
         }
 
         // B.3 pg 62
@@ -281,25 +747,284 @@
         {
             if (this.isInfinity())
             {
-                // Twice identity element (point at infinity) is identity
                 return this;
             }
 
-            if (this.y.toBigInteger().signum() == 0) 
+            ECCurve curve = this.getCurve();
+
+            ECFieldElement Y1 = this.y;
+            if (Y1.isZero()) 
             {
-                // if y1 == 0, then (x1, y1) == (x1, -y1)
-                // and hence this = -this and thus 2(x1, y1) == infinity
-                return this.curve.getInfinity();
+                return curve.getInfinity();
             }
 
-            ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
-            ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
-            ECFieldElement gamma = this.x.square().multiply(THREE).add(curve.a).divide(y.multiply(TWO));
+            int coord = curve.getCoordinateSystem();
 
-            ECFieldElement x3 = gamma.square().subtract(this.x.multiply(TWO));
-            ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
+            ECFieldElement X1 = this.x;
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement X1Squared = X1.square();
+                ECFieldElement gamma = three(X1Squared).add(this.getCurve().getA()).divide(two(Y1));
+                ECFieldElement X3 = gamma.square().subtract(two(X1));
+                ECFieldElement Y3 = gamma.multiply(X1.subtract(X3)).subtract(Y1);
+    
+                return new ECPoint.Fp(curve, X3, Y3, this.withCompression);
+            }
+
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Z1 = this.zs[0];
+
+                boolean Z1IsOne = Z1.bitLength() == 1;
+                ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.square();
+
+                // TODO Optimize for small negative a4 and -3
+                ECFieldElement w = curve.getA();
+                if (!Z1IsOne)
+                {
+                    w = w.multiply(Z1Squared);
+                }
+                w = w.add(three(X1.square()));
                 
-            return new ECPoint.Fp(curve, x3, y3, this.withCompression);
+                ECFieldElement s = Z1IsOne ? Y1 : Y1.multiply(Z1);
+                ECFieldElement t = Z1IsOne ? Y1.square() : s.multiply(Y1);
+                ECFieldElement B = X1.multiply(t);
+                ECFieldElement _4B = four(B);
+                ECFieldElement h = w.square().subtract(two(_4B));
+
+                ECFieldElement X3 = two(h.multiply(s));
+                ECFieldElement Y3 = w.multiply(_4B.subtract(h)).subtract(two(two(t).square()));
+                ECFieldElement _4sSquared = Z1IsOne ? four(t) : two(s).square();
+                ECFieldElement Z3 = two(_4sSquared).multiply(s);
+
+                return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+
+            case ECCurve.COORD_JACOBIAN:
+            {
+                ECFieldElement Z1 = this.zs[0];
+
+                boolean Z1IsOne = Z1.bitLength() == 1;
+                ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.square();
+
+                ECFieldElement Y1Squared = Y1.square();
+                ECFieldElement T = Y1Squared.square();
+
+                ECFieldElement a4 = curve.getA();
+                ECFieldElement a4Neg = a4.negate();
+
+                ECFieldElement M, S;
+                if (a4Neg.toBigInteger().equals(BigInteger.valueOf(3)))
+                {
+                    M = three(X1.add(Z1Squared).multiply(X1.subtract(Z1Squared)));
+                    S = four(Y1Squared.multiply(X1));
+                }
+                else
+                {
+                    ECFieldElement X1Squared = X1.square();
+                    M = three(X1Squared);
+                    if (Z1IsOne)
+                    {
+                        M = M.add(a4);
+                    }
+                    else
+                    {
+                        ECFieldElement Z1Pow4 = Z1Squared.square();
+                        if (a4Neg.bitLength() < a4.bitLength())
+                        {
+                            M = M.subtract(Z1Pow4.multiply(a4Neg));
+                        }
+                        else
+                        {
+                            M = M.add(Z1Pow4.multiply(a4));
+                        }
+                    }
+                    S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T));
+                }
+
+                ECFieldElement X3 = M.square().subtract(two(S));
+                ECFieldElement Y3 = S.subtract(X3).multiply(M).subtract(eight(T));
+
+                ECFieldElement Z3 = two(Y1);
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.multiply(Z1);
+                }
+
+                // Alternative calculation of Z3 using fast square
+//                ECFieldElement Z3 = doubleProductFromSquares(Y1, Z1, Y1Squared, Z1Squared);
+
+                return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+            {
+                return twiceJacobianModified(true);
+            }
+
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
+        }
+
+        public ECPoint twicePlus(ECPoint b)
+        {
+            if (this == b)
+            {
+                return threeTimes();
+            }
+            if (this.isInfinity())
+            {
+                return b;
+            }
+            if (b.isInfinity())
+            {
+                return twice();
+            }
+
+            ECFieldElement Y1 = this.y;
+            if (Y1.isZero()) 
+            {
+                return b;
+            }
+
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement X1 = this.x;
+                ECFieldElement X2 = b.x, Y2 = b.y;
+
+                ECFieldElement dx = X2.subtract(X1), dy = Y2.subtract(Y1);
+
+                if (dx.isZero())
+                {
+                    if (dy.isZero())
+                    {
+                        // this == b i.e. the result is 3P
+                        return threeTimes();
+                    }
+
+                    // this == -b, i.e. the result is P
+                    return this;
+                }
+
+                /*
+                 * Optimized calculation of 2P + Q, as described in "Trading Inversions for
+                 * Multiplications in Elliptic Curve Cryptography", by Ciet, Joye, Lauter, Montgomery.
+                 */
+
+                ECFieldElement X = dx.square(), Y = dy.square();
+                ECFieldElement d = X.multiply(two(X1).add(X2)).subtract(Y);
+                if (d.isZero())
+                {
+                    return curve.getInfinity();
+                }
+
+                ECFieldElement D = d.multiply(dx);
+                ECFieldElement I = D.invert();
+                ECFieldElement L1 = d.multiply(I).multiply(dy);
+                ECFieldElement L2 = two(Y1).multiply(X).multiply(dx).multiply(I).subtract(L1);
+                ECFieldElement X4 = (L2.subtract(L1)).multiply(L1.add(L2)).add(X2);
+                ECFieldElement Y4 = (X1.subtract(X4)).multiply(L2).subtract(Y1);
+
+                return new ECPoint.Fp(curve, X4, Y4, this.withCompression);
+            }
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+            {
+                return twiceJacobianModified(false).add(b);
+            }
+            default:
+            {
+                return twice().add(b);
+            }
+            }
+        }
+
+        public ECPoint threeTimes()
+        {
+            if (this.isInfinity() || this.y.isZero())
+            {
+                return this;
+            }
+
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement X1 = this.x, Y1 = this.y;
+
+                ECFieldElement _2Y1 = two(Y1); 
+                ECFieldElement X = _2Y1.square();
+                ECFieldElement Z = three(X1.square()).add(this.getCurve().getA());
+                ECFieldElement Y = Z.square();
+
+                ECFieldElement d = three(X1).multiply(X).subtract(Y);
+                if (d.isZero())
+                {
+                    return this.getCurve().getInfinity();
+                }
+
+                ECFieldElement D = d.multiply(_2Y1); 
+                ECFieldElement I = D.invert();
+                ECFieldElement L1 = d.multiply(I).multiply(Z);
+                ECFieldElement L2 = X.square().multiply(I).subtract(L1);
+
+                ECFieldElement X4 = (L2.subtract(L1)).multiply(L1.add(L2)).add(X1);
+                ECFieldElement Y4 = (X1.subtract(X4)).multiply(L2).subtract(Y1); 
+                return new ECPoint.Fp(curve, X4, Y4, this.withCompression);
+            }
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+            {
+                return twiceJacobianModified(false).add(this);
+            }
+            default:
+            {
+                // NOTE: Be careful about recursions between twicePlus and threeTimes
+                return twice().add(this);
+            }
+            }
+        }
+
+        protected ECFieldElement two(ECFieldElement x)
+        {
+            return x.add(x);
+        }
+
+        protected ECFieldElement three(ECFieldElement x)
+        {
+            return two(x).add(x);
+        }
+
+        protected ECFieldElement four(ECFieldElement x)
+        {
+            return two(two(x));
+        }
+
+        protected ECFieldElement eight(ECFieldElement x)
+        {
+            return four(two(x));
+        }
+
+        protected ECFieldElement doubleProductFromSquares(ECFieldElement a, ECFieldElement b,
+            ECFieldElement aSquared, ECFieldElement bSquared)
+        {
+            /*
+             * NOTE: If squaring in the field is faster than multiplication, then this is a quicker
+             * way to calculate 2.A.B, if A^2 and B^2 are already known.
+             */
+            return a.add(b).square().subtract(aSquared).subtract(bSquared);
         }
 
         // D.3.2 pg 102 (see Note:)
@@ -316,18 +1041,70 @@
 
         public ECPoint negate()
         {
+            if (this.isInfinity())
+            {
+                return this;
+            }
+
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
+
+            if (ECCurve.COORD_AFFINE != coord)
+            {
+                return new ECPoint.Fp(curve, this.x, this.y.negate(), this.zs, this.withCompression);
+            }
+
             return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);
         }
 
-        /**
-         * Sets the default <code>ECMultiplier</code>, unless already set. 
-         */
-        synchronized void assertECMultiplier()
+        protected ECFieldElement calculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared)
         {
-            if (this.multiplier == null)
+            if (ZSquared == null)
             {
-                this.multiplier = new WNafMultiplier();
+                ZSquared = Z.square();
             }
+
+            ECFieldElement W = ZSquared.square();
+            ECFieldElement a4 = this.getCurve().getA();
+            ECFieldElement a4Neg = a4.negate();
+            if (a4Neg.bitLength() < a4.bitLength())
+            {
+                W = W.multiply(a4Neg).negate();
+            }
+            else
+            {
+                W = W.multiply(a4);
+            }
+            return W;
+        }
+
+        protected ECFieldElement getJacobianModifiedW()
+        {
+            ECFieldElement W = this.zs[1];
+            if (W == null)
+            {
+                // NOTE: Rarely, twicePlus will result in the need for a lazy W1 calculation here
+                this.zs[1] = W = calculateJacobianModifiedW(this.zs[0], null);
+            }
+            return W;
+        }
+
+        protected ECPoint.Fp twiceJacobianModified(boolean calculateW)
+        {
+            ECFieldElement X1 = this.x, Y1 = this.y, Z1 = this.zs[0], W1 = getJacobianModifiedW();
+
+            ECFieldElement X1Squared = X1.square();
+            ECFieldElement M = three(X1Squared).add(W1);
+            ECFieldElement Y1Squared = Y1.square();
+            ECFieldElement T = Y1Squared.square();
+            ECFieldElement S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T));
+            ECFieldElement X3 = M.square().subtract(two(S));
+            ECFieldElement _8T = eight(T);
+            ECFieldElement Y3 = M.multiply(S.subtract(X3)).subtract(_8T);
+            ECFieldElement W3 = calculateW ? two(_8T.multiply(W1)) : null;
+            ECFieldElement Z3 = two(Z1.bitLength() == 1 ? Y1 : Y1.multiply(Z1));
+
+            return new ECPoint.Fp(this.getCurve(), X3, Y3, new ECFieldElement[]{ Z3, W3 }, this.withCompression);
         }
     }
 
@@ -340,6 +1117,8 @@
          * @param curve base curve
          * @param x x point
          * @param y y point
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
          */
         public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y)
         {
@@ -351,6 +1130,8 @@
          * @param x x point
          * @param y y point
          * @param withCompression true if encode with point compression.
+         * 
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)}
          */
         public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
         {
@@ -360,71 +1141,91 @@
             {
                 throw new IllegalArgumentException("Exactly one of the field elements is null");
             }
-            
+
             if (x != null)
             {
                 // Check if x and y are elements of the same field
                 ECFieldElement.F2m.checkFieldElements(this.x, this.y);
-    
+
                 // Check if x and a are elements of the same field
                 if (curve != null)
                 {
                     ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA());
                 }
             }
-            
+
             this.withCompression = withCompression;
+
+//            checkCurveEquation();
         }
 
-        /* (non-Javadoc)
-         * @see org.bouncycastle.math.ec.ECPoint#getEncoded()
-         */
-        public byte[] getEncoded(boolean compressed)
+        F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
         {
-            if (this.isInfinity()) 
+            super(curve, x, y, zs);
+
+            this.withCompression = withCompression;
+
+//            checkCurveEquation();
+        }
+
+        public ECFieldElement getYCoord()
+        {
+            int coord = this.getCurveCoordinateSystem();
+
+            switch (coord)
             {
-                return new byte[1];
-            }
-
-            int byteCount = converter.getByteLength(this.x);
-            byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount);
-            byte[] PO;
-
-            if (compressed)
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
             {
-                // See X9.62 4.3.6 and 4.2.2
-                PO = new byte[byteCount + 1];
-
-                PO[0] = 0x02;
-                // X9.62 4.2.2 and 4.3.6:
-                // if x = 0 then ypTilde := 0, else ypTilde is the rightmost
-                // bit of y * x^(-1)
-                // if ypTilde = 0, then PC := 02, else PC := 03
-                // Note: PC === PO[0]
-                if (!(this.getX().toBigInteger().equals(ECConstants.ZERO)))
+                // TODO The X == 0 stuff needs further thought
+                if (this.isInfinity() || x.isZero())
                 {
-                    if (this.getY().multiply(this.getX().invert())
-                            .toBigInteger().testBit(0))
-                    {
-                        // ypTilde = 1, hence PC = 03
-                        PO[0] = 0x03;
-                    }
+                    return y;
                 }
 
-                System.arraycopy(X, 0, PO, 1, byteCount);
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement X = x, L = y;
+                ECFieldElement Y = L.subtract(X).multiply(X);
+                if (ECCurve.COORD_LAMBDA_PROJECTIVE == coord)
+                {
+                    ECFieldElement Z = zs[0];
+                    if (Z.bitLength() != 1)
+                    {
+                        Y = Y.divide(Z);
+                    }
+                }
+                return Y;
             }
-            else
+            default:
             {
-                byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount);
-    
-                PO = new byte[byteCount + byteCount + 1];
-    
-                PO[0] = 0x04;
-                System.arraycopy(X, 0, PO, 1, byteCount);
-                System.arraycopy(Y, 0, PO, byteCount + 1, byteCount);    
+                return y;
+            }
+            }
+        }
+
+        protected boolean getCompressionYTilde()
+        {
+            ECFieldElement X = this.getRawXCoord();
+            if (X.isZero())
+            {
+                return false;
             }
 
-            return PO;
+            ECFieldElement Y = this.getRawYCoord();
+
+            switch (this.getCurveCoordinateSystem())
+            {
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                // Y is actually Lambda (X + Y/X) here
+                return Y.subtract(X).testBitZero();
+            }
+            default:
+            {
+                return Y.divide(X).testBitZero();
+            }
+            }
         }
 
         /**
@@ -437,7 +1238,7 @@
         private static void checkPoints(ECPoint a, ECPoint b)
         {
             // Check, if points are on the same curve
-            if (!(a.curve.equals(b.curve)))
+            if (a.curve != b.curve)
             {
                 throw new IllegalArgumentException("Only points on the same "
                         + "curve can be added or subtracted");
@@ -466,43 +1267,162 @@
          */
         public ECPoint.F2m addSimple(ECPoint.F2m b)
         {
-            ECPoint.F2m other = b;
             if (this.isInfinity())
             {
-                return other;
+                return b;
             }
-
-            if (other.isInfinity())
+            if (b.isInfinity())
             {
                 return this;
             }
 
-            ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX();
-            ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY();
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
 
-            // Check if other = this or other = -this
-            if (this.x.equals(x2))
+            ECFieldElement X1 = this.x;
+            ECFieldElement X2 = b.x;
+
+            switch (coord)
             {
-                if (this.y.equals(y2))
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement Y1 = this.y;
+                ECFieldElement Y2 = b.y;
+
+                if (X1.equals(X2))
                 {
-                    // this = other, i.e. this must be doubled
-                    return (ECPoint.F2m)this.twice();
+                    if (Y1.equals(Y2))
+                    {
+                        return (ECPoint.F2m)twice();
+                    }
+
+                    return (ECPoint.F2m)curve.getInfinity();
                 }
 
-                // this = -other, i.e. the result is the point at infinity
-                return (ECPoint.F2m)this.curve.getInfinity();
+                ECFieldElement sumX = X1.add(X2);
+                ECFieldElement L = Y1.add(Y2).divide(sumX);
+
+                ECFieldElement X3 = L.square().add(L).add(sumX).add(curve.getA());
+                ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1);
+
+                return new ECPoint.F2m(curve, X3, Y3, this.withCompression);
             }
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Y1 = this.y, Z1 = this.zs[0];
+                ECFieldElement Y2 = b.y, Z2 = b.zs[0];
 
-            ECFieldElement.F2m lambda
-                = (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2));
+                boolean Z2IsOne = Z2.bitLength() == 1;
 
-            ECFieldElement.F2m x3
-                = (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA());
+                ECFieldElement U1 = Z1.multiply(Y2); 
+                ECFieldElement U2 = Z2IsOne ? Y1 : Y1.multiply(Z2);
+                ECFieldElement U = U1.subtract(U2);
+                ECFieldElement V1 = Z1.multiply(X2);
+                ECFieldElement V2 = Z2IsOne ? X1 : X1.multiply(Z2);
+                ECFieldElement V = V1.subtract(V2);
 
-            ECFieldElement.F2m y3
-                = (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y);
+                if (V1.equals(V2))
+                {
+                    if (U1.equals(U2))
+                    {
+                        return (ECPoint.F2m)twice();
+                    }
 
-            return new ECPoint.F2m(curve, x3, y3, withCompression);
+                    return (ECPoint.F2m)curve.getInfinity();
+                }
+
+                ECFieldElement VSq =  V.square();
+                ECFieldElement W = Z2IsOne ? Z1 : Z1.multiply(Z2);
+                ECFieldElement A = U.square().add(U.multiply(V).add(VSq.multiply(curve.getA()))).multiply(W).add(V.multiply(VSq));
+
+                ECFieldElement X3 = V.multiply(A);
+                ECFieldElement VSqZ2 = Z2IsOne ? VSq : VSq.multiply(Z2);
+                ECFieldElement Y3 = VSqZ2.multiply(U.multiply(X1).add(Y1.multiply(V))).add(A.multiply(U.add(V)));
+                ECFieldElement Z3 = VSq.multiply(V).multiply(W);
+
+                return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                if (X1.isZero())
+                {
+                    return b.addSimple(this);
+                }
+
+                ECFieldElement L1 = this.y, Z1 = this.zs[0];
+                ECFieldElement L2 = b.y, Z2 = b.zs[0];
+
+                boolean Z1IsOne = Z1.bitLength() == 1;
+                ECFieldElement U2 = X2, S2 = L2;
+                if (!Z1IsOne)
+                {
+                    U2 = U2.multiply(Z1);
+                    S2 = S2.multiply(Z1);
+                }
+
+                boolean Z2IsOne = Z2.bitLength() == 1;
+                ECFieldElement U1 = X1, S1 = L1;
+                if (!Z2IsOne)
+                {
+                    U1 = U1.multiply(Z2);
+                    S1 = S1.multiply(Z2);
+                }
+
+                ECFieldElement A = S1.add(S2);
+                ECFieldElement B = U1.add(U2);
+
+                if (B.isZero())
+                {
+                    if (A.isZero())
+                    {
+                        return (ECPoint.F2m)twice();
+                    }
+
+                    return (ECPoint.F2m)curve.getInfinity();
+                }
+
+                ECFieldElement X3, L3, Z3;
+                if (X2.isZero())
+                {
+                    // TODO This can probably be optimized quite a bit
+
+                    ECFieldElement Y1 = getYCoord(), Y2 = L2;
+                    ECFieldElement L = Y1.add(Y2).divide(X1);
+
+                    X3 = L.square().add(L).add(X1).add(curve.getA());
+                    ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1);
+                    L3 = X3.isZero() ? Y3 : Y3.divide(X3).add(X3);
+                    Z3 = curve.fromBigInteger(ECConstants.ONE);
+                }
+                else
+                {
+                    B = B.square();
+    
+                    ECFieldElement AU1 = A.multiply(U1);
+                    ECFieldElement AU2 = A.multiply(U2);
+                    ECFieldElement ABZ2 = A.multiply(B);
+                    if (!Z2IsOne)
+                    {
+                        ABZ2 = ABZ2.multiply(Z2);
+                    }
+
+                    X3 = AU1.multiply(AU2);
+                    L3 = AU2.add(B).square().add(ABZ2.multiply(L1.add(Z1)));
+
+                    Z3 = ABZ2;
+                    if (!Z1IsOne)
+                    {
+                        Z3 = Z3.multiply(Z1);
+                    }
+                }
+
+                return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
         }
 
         /* (non-Javadoc)
@@ -534,59 +1454,279 @@
             return addSimple((ECPoint.F2m)b.negate());
         }
 
-        /* (non-Javadoc)
-         * @see org.bouncycastle.math.ec.ECPoint#twice()
-         */
+        public ECPoint.F2m tau()
+        {
+            if (this.isInfinity())
+            {
+                return this;
+            }
+
+            ECCurve curve = this.getCurve();
+            int coord = curve.getCoordinateSystem();
+
+            ECFieldElement X1 = this.x;
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            {
+                ECFieldElement Y1 = this.y;
+                return new ECPoint.F2m(curve, X1.square(), Y1.square(), this.withCompression);
+            }
+            case ECCurve.COORD_HOMOGENEOUS:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                ECFieldElement Y1 = this.y, Z1 = this.zs[0];
+                return new ECPoint.F2m(curve, X1.square(), Y1.square(), new ECFieldElement[]{ Z1.square() }, this.withCompression);
+            }
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
+        }
+
         public ECPoint twice()
         {
             if (this.isInfinity()) 
             {
-                // Twice identity element (point at infinity) is identity
                 return this;
             }
 
-            if (this.x.toBigInteger().signum() == 0) 
+            ECCurve curve = this.getCurve();
+
+            ECFieldElement X1 = this.x;
+            if (X1.isZero()) 
             {
-                // if x1 == 0, then (x1, y1) == (x1, x1 + y1)
-                // and hence this = -this and thus 2(x1, y1) == infinity
-                return this.curve.getInfinity();
+                // A point with X == 0 is it's own additive inverse
+                return curve.getInfinity();
             }
 
-            ECFieldElement.F2m lambda
-                = (ECFieldElement.F2m)this.x.add(this.y.divide(this.x));
+            int coord = curve.getCoordinateSystem();
 
-            ECFieldElement.F2m x3
-                = (ECFieldElement.F2m)lambda.square().add(lambda).
-                    add(this.curve.getA());
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement Y1 = this.y;
 
-            ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE);
-            ECFieldElement.F2m y3
-                = (ECFieldElement.F2m)this.x.square().add(
-                    x3.multiply(lambda.add(ONE)));
+                ECFieldElement L1 = Y1.divide(X1).add(X1);
 
-            return new ECPoint.F2m(this.curve, x3, y3, withCompression);
+                ECFieldElement X3 = L1.square().add(L1).add(curve.getA());
+                ECFieldElement Y3 = X1.square().add(X3.multiply(L1.addOne()));
+
+                return new ECPoint.F2m(curve, X3, Y3, this.withCompression);
+            }
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Y1 = this.y, Z1 = this.zs[0];
+
+                boolean Z1IsOne = Z1.bitLength() == 1;
+                ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1);
+                ECFieldElement Y1Z1 = Z1IsOne ? Y1 : Y1.multiply(Z1);
+
+                ECFieldElement X1Sq = X1.square();
+                ECFieldElement S = X1Sq.add(Y1Z1);
+                ECFieldElement V = X1Z1;
+                ECFieldElement vSquared = V.square();
+                ECFieldElement h = S.square().add(S.multiply(V)).add(curve.getA().multiply(vSquared));
+
+                ECFieldElement X3 = V.multiply(h);
+                ECFieldElement Y3 = h.multiply(S.add(V)).add(X1Sq.square().multiply(V));
+                ECFieldElement Z3 = V.multiply(vSquared);    
+
+                return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                ECFieldElement L1 = this.y, Z1 = this.zs[0];
+
+                boolean Z1IsOne = Z1.bitLength() == 1;
+                ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.multiply(Z1);
+                ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.square();
+                ECFieldElement a = curve.getA();
+                ECFieldElement aZ1Sq = Z1IsOne ? a : a.multiply(Z1Sq);
+                ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq);
+
+                ECFieldElement X3 = T.square();
+                ECFieldElement Z3 = Z1IsOne ? T : T.multiply(Z1Sq);
+
+                ECFieldElement b = curve.getB();
+                ECFieldElement L3;
+                if (b.bitLength() < (curve.getFieldSize() >> 1))
+                {
+                    ECFieldElement t1 = L1.add(X1).square();
+                    ECFieldElement t2 = aZ1Sq.square();
+                    ECFieldElement t3 = curve.getB().multiply(Z1Sq.square());
+                    L3 = t1.add(T).add(Z1Sq).multiply(t1).add(t2.add(t3)).add(X3).add(a.addOne().multiply(Z3));
+                }
+                else
+                {
+                    ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1);
+                    L3 = X1Z1.square().add(X3).add(T.multiply(L1Z1)).add(Z3);
+                }
+
+                return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
+            }
+        }
+
+        public ECPoint twicePlus(ECPoint b)
+        {
+            if (this.isInfinity()) 
+            {
+                return b;
+            }
+            if (b.isInfinity())
+            {
+                return twice();
+            }
+
+            ECCurve curve = this.getCurve();
+
+            ECFieldElement X1 = this.x;
+            if (X1.isZero()) 
+            {
+                // A point with X == 0 is it's own additive inverse
+                return b;
+            }
+
+            int coord = curve.getCoordinateSystem();
+
+            switch (coord)
+            {
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                // NOTE: twicePlus() only optimized for lambda-affine argument
+                ECFieldElement X2 = b.x, Z2 = b.zs[0];
+                if (X2.isZero() || Z2.bitLength() != 1)
+                {
+                    return twice().add(b);
+                }
+
+                ECFieldElement L1 = this.y, Z1 = this.zs[0];
+                ECFieldElement L2 = b.y;
+
+                ECFieldElement X1Sq = X1.square();
+                ECFieldElement L1Sq = L1.square();
+                ECFieldElement Z1Sq = Z1.square();
+                ECFieldElement L1Z1 = L1.multiply(Z1);
+
+                ECFieldElement T = curve.getA().multiply(Z1Sq).add(L1Sq).add(L1Z1);
+                ECFieldElement L2plus1 = L2.addOne();
+                ECFieldElement A = curve.getA().add(L2plus1).multiply(Z1Sq).add(L1Sq).multiply(T).add(X1Sq.multiply(Z1Sq));
+                ECFieldElement X2Z1Sq = X2.multiply(Z1Sq);
+                ECFieldElement B = X2Z1Sq.add(T).square();
+
+                ECFieldElement X3 = A.square().multiply(X2Z1Sq);
+                ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq);
+                ECFieldElement L3 = A.add(B).square().multiply(T).add(L2plus1.multiply(Z3));
+
+                return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression);
+            }
+            default:
+            {
+                return twice().add(b);
+            }
+            }
+        }
+
+        protected void checkCurveEquation()
+        {
+            if (this.isInfinity())
+            {
+                return;
+            }
+
+            ECFieldElement Z;
+            switch (this.getCurveCoordinateSystem())
+            {
+            case ECCurve.COORD_LAMBDA_AFFINE:
+                Z = curve.fromBigInteger(ECConstants.ONE);
+                break;
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                Z = this.zs[0];
+                break;
+            default:
+                return;
+            }
+
+            if (Z.isZero())
+            {
+                throw new IllegalStateException();
+            }
+
+            ECFieldElement X = this.x;
+            if (X.isZero())
+            {
+                // NOTE: For x == 0, we expect the affine-y instead of the lambda-y 
+                ECFieldElement Y = this.y;
+                if (!Y.square().equals(curve.getB().multiply(Z)))
+                {
+                    throw new IllegalStateException();
+                }
+
+                return;
+            }
+
+            ECFieldElement L = this.y;
+            ECFieldElement XSq = X.square();
+            ECFieldElement ZSq = Z.square();
+
+            ECFieldElement lhs = L.square().add(L.multiply(Z)).add(this.getCurve().getA().multiply(ZSq)).multiply(XSq);
+            ECFieldElement rhs = ZSq.square().multiply(this.getCurve().getB()).add(XSq.square());
+            
+            if (!lhs.equals(rhs))
+            {
+                throw new IllegalStateException("F2m Lambda-Projective invariant broken");
+            }
         }
 
         public ECPoint negate()
         {
-            return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression);
-        }
-
-        /**
-         * Sets the appropriate <code>ECMultiplier</code>, unless already set. 
-         */
-        synchronized void assertECMultiplier()
-        {
-            if (this.multiplier == null)
+            if (this.isInfinity())
             {
-                if (((ECCurve.F2m)this.curve).isKoblitz())
-                {
-                    this.multiplier = new WTauNafMultiplier();
-                }
-                else
-                {
-                    this.multiplier = new WNafMultiplier();
-                }
+                return this;
+            }
+
+            ECFieldElement X = this.x;
+            if (X.isZero())
+            {
+                return this;
+            }
+
+            switch (this.getCurveCoordinateSystem())
+            {
+            case ECCurve.COORD_AFFINE:
+            {
+                ECFieldElement Y = this.y;
+                return new ECPoint.F2m(curve, X, Y.add(X), this.withCompression);
+            }
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Y = this.y, Z = this.zs[0];
+                return new ECPoint.F2m(curve, X, Y.add(X), new ECFieldElement[]{ Z }, this.withCompression);
+            }
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            {
+                ECFieldElement L = this.y;
+                return new ECPoint.F2m(curve, X, L.addOne(), this.withCompression);
+            }
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                // L is actually Lambda (X + Y/X) here
+                ECFieldElement L = this.y, Z = this.zs[0];
+                return new ECPoint.F2m(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression);
+            }
+            default:
+            {
+                throw new IllegalStateException("unsupported coordinate system");
+            }
             }
         }
     }
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java
deleted file mode 100644
index 35e601d..0000000
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.bouncycastle.math.ec;
-
-import java.math.BigInteger;
-
-/**
- * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm.
- */
-class FpNafMultiplier implements ECMultiplier
-{
-    /**
-     * D.3.2 pg 101
-     * @see org.bouncycastle.math.ec.ECMultiplier#multiply(org.bouncycastle.math.ec.ECPoint, java.math.BigInteger)
-     */
-    public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
-    {
-        // TODO Probably should try to add this
-        // BigInteger e = k.mod(n); // n == order of p
-        BigInteger e = k;
-        BigInteger h = e.multiply(BigInteger.valueOf(3));
-
-        ECPoint neg = p.negate();
-        ECPoint R = p;
-
-        for (int i = h.bitLength() - 2; i > 0; --i)
-        {             
-            R = R.twice();
-
-            boolean hBit = h.testBit(i);
-            boolean eBit = e.testBit(i);
-
-            if (hBit != eBit)
-            {
-                R = R.add(hBit ? p : neg);
-            }
-        }
-
-        return R;
-    }
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java b/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java
index ead38c4..34395a5 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java
@@ -6,6 +6,60 @@
 
 class IntArray
 {
+//    private static int DEINTERLEAVE_MASK = 0x55555555;
+
+    /*
+     * This expands 8 bit indices into 16 bit contents, by inserting 0s between bits.
+     * In a binary field, this operation is the same as squaring an 8 bit number.
+     */
+    private static final int[] INTERLEAVE_TABLE = new int[] { 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014,
+        0x0015, 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104, 0x0105, 0x0110,
+        0x0111, 0x0114, 0x0115, 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, 0x0400, 0x0401, 0x0404,
+        0x0405, 0x0410, 0x0411, 0x0414, 0x0415, 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, 0x0500,
+        0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554,
+        0x0555, 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, 0x1040, 0x1041, 0x1044, 0x1045, 0x1050,
+        0x1051, 0x1054, 0x1055, 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 0x1140, 0x1141, 0x1144,
+        0x1145, 0x1150, 0x1151, 0x1154, 0x1155, 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, 0x1440,
+        0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514,
+        0x1515, 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, 0x4000, 0x4001, 0x4004, 0x4005, 0x4010,
+        0x4011, 0x4014, 0x4015, 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, 0x4100, 0x4101, 0x4104,
+        0x4105, 0x4110, 0x4111, 0x4114, 0x4115, 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, 0x4400,
+        0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454,
+        0x4455, 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, 0x4540, 0x4541, 0x4544, 0x4545, 0x4550,
+        0x4551, 0x4554, 0x4555, 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, 0x5040, 0x5041, 0x5044,
+        0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 0x5140,
+        0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414,
+        0x5415, 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, 0x5500, 0x5501, 0x5504, 0x5505, 0x5510,
+        0x5511, 0x5514, 0x5515, 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555 };
+
+    // For toString(); must have length 32
+    private static final String ZEROES = "00000000000000000000000000000000";
+
+    private final static byte[] bitLengths =
+    {
+        0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
+    };
+
+    public static int getWordLength(int bits)
+    {
+        return (bits + 31) >>> 5;
+    }
+
     // TODO make m fixed for the IntArray, and hence compute T once and for all
 
     private int[] m_ints;
@@ -22,16 +76,12 @@
 
     public IntArray(BigInteger bigInt)
     {
-        this(bigInt, 0);
-    }
-
-    public IntArray(BigInteger bigInt, int minIntLen)
-    {
-        if (bigInt.signum() == -1)
+        if (bigInt == null || bigInt.signum() < 0)
         {
-            throw new IllegalArgumentException("Only positive Integers allowed");
+            throw new IllegalArgumentException("invalid F2m field value");
         }
-        if (bigInt.equals(ECConstants.ZERO))
+
+        if (bigInt.signum() == 0)
         {
             m_ints = new int[] { 0 };
             return;
@@ -48,14 +98,7 @@
             barrStart = 1;
         }
         int intLen = (barrLen + 3) / 4;
-        if (intLen < minIntLen)
-        {
-            m_ints = new int[minIntLen];
-        }
-        else
-        {
-            m_ints = new int[intLen];
-        }
+        m_ints = new int[intLen];
 
         int iarrJ = intLen - 1;
         int rem = barrLen % 4 + barrStart;
@@ -66,11 +109,7 @@
             for (; barrI < rem; barrI++)
             {
                 temp <<= 8;
-                int barrBarrI = barr[barrI];
-                if (barrBarrI < 0)
-                {
-                    barrBarrI += 256;
-                }
+                int barrBarrI = barr[barrI] & 0xFF;
                 temp |= barrBarrI;
             }
             m_ints[iarrJ--] = temp;
@@ -82,11 +121,7 @@
             for (int i = 0; i < 4; i++)
             {
                 temp <<= 8;
-                int barrBarrI = barr[barrI++];
-                if (barrBarrI < 0)
-                {
-                    barrBarrI += 256;
-                }
+                int barrBarrI = barr[barrI++] & 0xFF;
                 temp |= barrBarrI;
             }
             m_ints[iarrJ] = temp;
@@ -95,88 +130,86 @@
 
     public boolean isZero()
     {
-        return m_ints.length == 0
-            || (m_ints[0] == 0 && getUsedLength() == 0);
+        int[] a = m_ints;
+        for (int i = 0; i < a.length; ++i)
+        {
+            if (a[i] != 0)
+            {
+                return false;
+            }
+        }
+        return true;
     }
 
     public int getUsedLength()
     {
-        int highestIntPos = m_ints.length;
+        return getUsedLengthFrom(m_ints.length);
+    }
 
-        if (highestIntPos < 1)
+    public int getUsedLengthFrom(int from)
+    {
+        int[] a = m_ints;
+        from = Math.min(from, a.length);
+
+        if (from < 1)
         {
             return 0;
         }
 
         // Check if first element will act as sentinel
-        if (m_ints[0] != 0)
+        if (a[0] != 0)
         {
-            while (m_ints[--highestIntPos] == 0)
+            while (a[--from] == 0)
             {
             }
-            return highestIntPos + 1;
+            return from + 1;
         }
 
         do
         {
-            if (m_ints[--highestIntPos] != 0)
+            if (a[--from] != 0)
             {
-                return highestIntPos + 1;
+                return from + 1;
             }
         }
-        while (highestIntPos > 0);
+        while (from > 0);
 
         return 0;
     }
 
-    public int bitLength()
+    public int degree()
     {
-        // JDK 1.5: see Integer.numberOfLeadingZeros()
-        int intLen = getUsedLength();
-        if (intLen == 0)
+        int i = m_ints.length, w;
+        do
         {
-            return 0;
-        }
-
-        int last = intLen - 1;
-        int highest = m_ints[last];
-        int bits = (last << 5) + 1;
-
-        // A couple of binary search steps
-        if ((highest & 0xffff0000) != 0)
-        {
-            if ((highest & 0xff000000) != 0)
+            if (i == 0)
             {
-                bits += 24;
-                highest >>>= 24;
+                return 0;
             }
-            else
-            {
-                bits += 16;
-                highest >>>= 16;
-            }
+            w = m_ints[--i];
         }
-        else if (highest > 0x000000ff)
+        while (w == 0);
+
+        return (i << 5) + bitLength(w);
+    }
+
+    private static int bitLength(int w)
+    {
+        int t = w >>> 16;
+        if (t == 0)
         {
-            bits += 8;
-            highest >>>= 8;
+            t = w >>> 8;
+            return (t == 0) ? bitLengths[w] : 8 + bitLengths[t];
         }
 
-        while (highest != 1)
-        {
-            ++bits;
-            highest >>>= 1;
-        }
-
-        return bits;
+        int u = t >>> 8;
+        return (u == 0) ? 16 + bitLengths[t] : 24 + bitLengths[u];
     }
 
     private int[] resizedInts(int newLen)
     {
         int[] newInts = new int[newLen];
-        int oldLen = m_ints.length;
-        int copyLen = oldLen < newLen ? oldLen : newLen;
-        System.arraycopy(m_ints, 0, newInts, 0, copyLen);
+        System.arraycopy(m_ints, 0, newInts, 0, Math.min(m_ints.length, newLen));
         return newInts;
     }
 
@@ -220,86 +253,128 @@
         return new BigInteger(1, barr);
     }
 
-    public void shiftLeft()
+    private static int shiftLeft(int[] x, int count)
     {
-        int usedLen = getUsedLength();
-        if (usedLen == 0)
+        int prev = 0;
+        for (int i = 0; i < count; ++i)
+        {
+            int next = x[i];
+            x[i] = (next << 1) | prev;
+            prev = next >>> 31;
+        }
+        return prev;
+    }
+
+    public void addOneShifted(int shift)
+    {
+        if (shift >= m_ints.length)
+        {
+            m_ints = resizedInts(shift + 1);
+        }
+
+        m_ints[shift] ^= 1;
+    }
+
+    private void addShiftedByBits(IntArray other, int bits)
+    {
+        int words = bits >>> 5;
+        int shift = bits & 0x1F;
+
+        if (shift == 0)
+        {
+            addShiftedByWords(other, words);
+            return;
+        }
+
+        int otherUsedLen = other.getUsedLength();
+        if (otherUsedLen == 0)
         {
             return;
         }
-        if (m_ints[usedLen - 1] < 0)
+
+        int minLen = otherUsedLen + words + 1;
+        if (minLen > m_ints.length)
         {
-            // highest bit of highest used byte is set, so shifting left will
-            // make the IntArray one byte longer
-            usedLen++;
-            if (usedLen > m_ints.length)
-            {
-                // make the m_ints one byte longer, because we need one more
-                // byte which is not available in m_ints
-                m_ints = resizedInts(m_ints.length + 1);
-            }
+            m_ints = resizedInts(minLen);
         }
 
-        boolean carry = false;
-        for (int i = 0; i < usedLen; i++)
+        int shiftInv = 32 - shift, prev = 0;
+        for (int i = 0; i < otherUsedLen; ++i)
         {
-            // nextCarry is true if highest bit is set
-            boolean nextCarry = m_ints[i] < 0;
-            m_ints[i] <<= 1;
-            if (carry)
-            {
-                // set lowest bit
-                m_ints[i] |= 1;
-            }
-            carry = nextCarry;
+            int next = other.m_ints[i];
+            m_ints[i + words] ^= (next << shift) | prev;
+            prev = next >>> shiftInv;
+        }
+        m_ints[otherUsedLen + words] ^= prev;
+    }
+
+    private static int addShiftedByBits(int[] x, int[] y, int count, int shift)
+    {
+        int shiftInv = 32 - shift, prev = 0;
+        for (int i = 0; i < count; ++i)
+        {
+            int next = y[i];
+            x[i] ^= (next << shift) | prev;
+            prev = next >>> shiftInv;
+        }
+        return prev;
+    }
+
+    private static int addShiftedByBits(int[] x, int xOff, int[] y, int yOff, int count, int shift)
+    {
+        int shiftInv = 32 - shift, prev = 0;
+        for (int i = 0; i < count; ++i)
+        {
+            int next = y[yOff + i];
+            x[xOff + i] ^= (next << shift) | prev;
+            prev = next >>> shiftInv;
+        }
+        return prev;
+    }
+
+    public void addShiftedByWords(IntArray other, int words)
+    {
+        int otherUsedLen = other.getUsedLength();
+        if (otherUsedLen == 0)
+        {
+            return;
+        }
+
+        int minLen = otherUsedLen + words;
+        if (minLen > m_ints.length)
+        {
+            m_ints = resizedInts(minLen);
+        }
+
+        for (int i = 0; i < otherUsedLen; i++)
+        {
+            m_ints[words + i] ^= other.m_ints[i];
         }
     }
 
-    public IntArray shiftLeft(int n)
+    private static void addShiftedByWords(int[] x, int xOff, int[] y, int count)
     {
-        int usedLen = getUsedLength();
-        if (usedLen == 0)
+        for (int i = 0; i < count; ++i)
         {
-            return this;
+            x[xOff + i] ^= y[i];
         }
-
-        if (n == 0)
-        {
-            return this;
-        }
-
-        if (n > 31)
-        {
-            throw new IllegalArgumentException("shiftLeft() for max 31 bits "
-                + ", " + n + "bit shift is not possible");
-        }
-
-        int[] newInts = new int[usedLen + 1];
-
-        int nm32 = 32 - n;
-        newInts[0] = m_ints[0] << n;
-        for (int i = 1; i < usedLen; i++)
-        {
-            newInts[i] = (m_ints[i] << n) | (m_ints[i - 1] >>> nm32);
-        }
-        newInts[usedLen] = m_ints[usedLen - 1] >>> nm32;
-
-        return new IntArray(newInts);
     }
 
-    public void addShifted(IntArray other, int shift)
+    private static void add(int[] x, int[] y, int count)
     {
-        int usedLenOther = other.getUsedLength();
-        int newMinUsedLen = usedLenOther + shift;
-        if (newMinUsedLen > m_ints.length)
+        for (int i = 0; i < count; ++i)
         {
-            m_ints = resizedInts(newMinUsedLen);
-            //System.out.println("Resize required");
+            x[i] ^= y[i];
         }
+    }
 
-        for (int i = 0; i < usedLenOther; i++)
+    private static void distribute(int[] x, int dst1, int dst2, int src, int count)
+    {
+        for (int i = 0; i < count; ++i)
         {
-            m_ints[i + shift] ^= other.m_ints[i];
+            int v = x[src + i];
+            x[dst1 + i] ^= v;
+            x[dst2 + i] ^= v;
         }
     }
 
@@ -308,10 +383,58 @@
         return m_ints.length;
     }
 
+    public void flipWord(int bit, int word)
+    {
+        int len = m_ints.length;
+        int n = bit >>> 5;
+        if (n < len)
+        {
+            int shift = bit & 0x1F;
+            if (shift == 0)
+            {
+                m_ints[n] ^= word;
+            }
+            else
+            {
+                m_ints[n] ^= word << shift;
+                if (++n < len)
+                {
+                    m_ints[n] ^= word >>> (32 - shift);
+                }
+            }
+        }
+    }
+
+    public int getWord(int bit)
+    {
+        int len = m_ints.length;
+        int n = bit >>> 5;
+        if (n >= len)
+        {
+            return 0;
+        }
+        int shift = bit & 0x1F;
+        if (shift == 0)
+        {
+            return m_ints[n];
+        }
+        int result = m_ints[n] >>> shift;
+        if (++n < len)
+        {
+            result |= m_ints[n] << (32 - shift);
+        }
+        return result;
+    }
+
+    public boolean testBitZero()
+    {
+        return m_ints.length > 0 && (m_ints[0] & 1) != 0;
+    }
+
     public boolean testBit(int n)
     {
         // theInt = n / 32
-        int theInt = n >> 5;
+        int theInt = n >>> 5;
         // theBit = n % 32
         int theBit = n & 0x1F;
         int tester = 1 << theBit;
@@ -321,7 +444,7 @@
     public void flipBit(int n)
     {
         // theInt = n / 32
-        int theInt = n >> 5;
+        int theInt = n >>> 5;
         // theBit = n % 32
         int theBit = n & 0x1F;
         int flipper = 1 << theBit;
@@ -331,127 +454,344 @@
     public void setBit(int n)
     {
         // theInt = n / 32
-        int theInt = n >> 5;
+        int theInt = n >>> 5;
         // theBit = n % 32
         int theBit = n & 0x1F;
         int setter = 1 << theBit;
         m_ints[theInt] |= setter;
     }
 
-    public IntArray multiply(IntArray other, int m)
+    public void clearBit(int n)
     {
-        // Lenght of c is 2m bits rounded up to the next int (32 bit)
-        int t = (m + 31) >> 5;
-        if (m_ints.length < t)
-        {
-            m_ints = resizedInts(t);
-        }
-
-        IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
-        IntArray c = new IntArray((m + m + 31) >> 5);
-        // IntArray c = new IntArray(t + t);
-        int testBit = 1;
-        for (int k = 0; k < 32; k++)
-        {
-            for (int j = 0; j < t; j++)
-            {
-                if ((m_ints[j] & testBit) != 0)
-                {
-                    // The kth bit of m_ints[j] is set
-                    c.addShifted(b, j);
-                }
-            }
-            testBit <<= 1;
-            b.shiftLeft();
-        }
-        return c;
+        // theInt = n / 32
+        int theInt = n >>> 5;
+        // theBit = n % 32
+        int theBit = n & 0x1F;
+        int setter = 1 << theBit;
+        m_ints[theInt] &= ~setter;
     }
 
-    // public IntArray multiplyLeftToRight(IntArray other, int m) {
-    // // Lenght of c is 2m bits rounded up to the next int (32 bit)
-    // int t = (m + 31) / 32;
-    // if (m_ints.length < t) {
-    // m_ints = resizedInts(t);
-    // }
-    //
-    // IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
-    // IntArray c = new IntArray((m + m + 31) / 32);
-    // // IntArray c = new IntArray(t + t);
-    // int testBit = 1 << 31;
-    // for (int k = 31; k >= 0; k--) {
-    // for (int j = 0; j < t; j++) {
-    // if ((m_ints[j] & testBit) != 0) {
-    // // The kth bit of m_ints[j] is set
-    // c.addShifted(b, j);
-    // }
-    // }
-    // testBit >>>= 1;
-    // if (k > 0) {
-    // c.shiftLeft();
-    // }
-    // }
-    // return c;
-    // }
-
-    // TODO note, redPol.length must be 3 for TPB and 5 for PPB
-    public void reduce(int m, int[] redPol)
+    public IntArray multiply(IntArray other, int m)
     {
-        for (int i = m + m - 2; i >= m; i--)
+        int aLen = getUsedLength();
+        if (aLen == 0)
+        {
+            return new IntArray(1);
+        }
+
+        int bLen = other.getUsedLength();
+        if (bLen == 0)
+        {
+            return new IntArray(1);
+        }
+
+        IntArray A = this, B = other;
+        if (aLen > bLen)
+        {
+            A = other; B = this;
+            int tmp = aLen; aLen = bLen; bLen = tmp;
+        }
+
+        if (aLen == 1)
+        {
+            int a = A.m_ints[0];
+            int[] b = B.m_ints;
+            int[] c = new int[aLen + bLen];
+            if ((a & 1) != 0)
+            {
+                add(c, b, bLen);
+            }
+            int k = 1;
+            while ((a >>>= 1) != 0)
+            {
+                if ((a & 1) != 0)
+                {
+                    addShiftedByBits(c, b, bLen, k);
+                }
+                ++k;
+            }
+            return new IntArray(c);
+        }
+
+        // TODO It'd be better to be able to tune the width directly (need support for interleaving arbitrary widths)
+        int complexity = aLen <= 8 ? 1 : 2;
+
+        int width = 1 << complexity;
+        int shifts = (32 >>> complexity);
+
+        int bExt = bLen;
+        if ((B.m_ints[bLen - 1] >>> (33 - shifts)) != 0)
+        {
+            ++bExt;
+        }
+
+        int cLen = bExt + aLen;
+
+        int[] c = new int[cLen << width];
+        System.arraycopy(B.m_ints, 0, c, 0, bLen);
+        interleave(A.m_ints, 0, c, bExt, aLen, complexity);
+
+        int[] ci = new int[1 << width];
+        for (int i = 1; i < ci.length; ++i)
+        {
+            ci[i] = ci[i - 1] + cLen;
+        }
+
+        int MASK = (1 << width) - 1;
+
+        int k = 0;
+        for (;;)
+        {
+            for (int aPos = 0; aPos < aLen; ++aPos)
+            {
+                int index = (c[bExt + aPos] >>> k) & MASK;
+                if (index != 0)
+                {
+                    addShiftedByWords(c, aPos + ci[index], c, bExt);
+                }
+            }
+
+            if ((k += width) >= 32)
+            {
+                break;
+            }
+
+            shiftLeft(c, bExt);
+        }
+
+        int ciPos = ci.length, pow2 = ciPos >>> 1, offset = 32;
+        while (--ciPos > 1)
+        {
+            if (ciPos == pow2)
+            {
+                offset -= shifts;
+                addShiftedByBits(c, ci[1], c, ci[pow2], cLen, offset);
+                pow2 >>>= 1;
+            }
+            else
+            {
+                distribute(c, ci[pow2], ci[ciPos - pow2], ci[ciPos], cLen);
+            }
+        }
+
+        // TODO reduce in place to avoid extra copying
+        IntArray p = new IntArray(cLen);
+        System.arraycopy(c, ci[1], p.m_ints, 0, cLen);
+        return p;
+    }
+
+//    private static void deInterleave(int[] x, int xOff, int[] z, int zOff, int count, int rounds)
+//    {
+//        for (int i = 0; i < count; ++i)
+//        {
+//            z[zOff + i] = deInterleave(x[zOff + i], rounds);
+//        }
+//    }
+//
+//    private static int deInterleave(int x, int rounds)
+//    {
+//        while (--rounds >= 0)
+//        {
+//            x = deInterleave16(x & DEINTERLEAVE_MASK) | (deInterleave16((x >>> 1) & DEINTERLEAVE_MASK) << 16);
+//        }
+//        return x;
+//    }
+//
+//    private static int deInterleave16(int x)
+//    {
+//        x = (x | (x >>> 1)) & 0x33333333;
+//        x = (x | (x >>> 2)) & 0x0F0F0F0F;
+//        x = (x | (x >>> 4)) & 0x00FF00FF;
+//        x = (x | (x >>> 8)) & 0x0000FFFF;
+//        return x;
+//    }
+
+    public void reduce(int m, int[] ks)
+    {
+        int len = getUsedLength();
+        int mLen = (m + 31) >>> 5;
+        if (len < mLen)
+        {
+            return;
+        }
+
+        int _2m = m << 1;
+        int pos = Math.min(_2m - 2, (len << 5) - 1);
+
+        int kMax = ks[ks.length - 1];
+        if (kMax < m - 31)
+        {
+            reduceWordWise(pos, m, ks);
+        }
+        else
+        {
+            reduceBitWise(pos, m, ks);
+        }
+
+        // Instead of flipping the high bits in the loop, explicitly clear any partial word above m bits
+        int partial = m & 0x1F;
+        if (partial != 0)
+        {
+            m_ints[mLen - 1] &= (1 << partial) - 1;
+        }
+
+        if (len > mLen)
+        {
+            m_ints = resizedInts(mLen);
+        }
+    }
+
+    private void reduceBitWise(int from, int m, int[] ks)
+    {
+        for (int i = from; i >= m; --i)
         {
             if (testBit(i))
             {
+//                clearBit(i);
                 int bit = i - m;
                 flipBit(bit);
-                flipBit(i);
-                int l = redPol.length;
-                while (--l >= 0)
+                int j = ks.length;
+                while (--j >= 0)
                 {
-                    flipBit(redPol[l] + bit);
+                    flipBit(ks[j] + bit);
                 }
             }
         }
-        m_ints = resizedInts((m + 31) >> 5);
+    }
+
+    private void reduceWordWise(int from, int m, int[] ks)
+    {
+        int pos = m + ((from - m) & ~0x1F);
+        for (int i = pos; i >= m; i -= 32)
+        {
+            int word = getWord(i);
+            if (word != 0)
+            {
+//                flipWord(i);
+                int bit = i - m;
+                flipWord(bit, word);
+                int j = ks.length;
+                while (--j >= 0)
+                {
+                    flipWord(ks[j] + bit, word);
+                }
+            }
+        }
     }
 
     public IntArray square(int m)
     {
-        // TODO make the table static final
-        final int[] table = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40,
-            0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 };
-
-        int t = (m + 31) >> 5;
-        if (m_ints.length < t)
+        int len = getUsedLength();
+        if (len == 0)
         {
-            m_ints = resizedInts(t);
+            return this;
         }
 
-        IntArray c = new IntArray(t + t);
+        int _2len = len << 1;
+        int[] r = new int[_2len];
 
-        // TODO twice the same code, put in separate private method
-        for (int i = 0; i < t; i++)
+        int pos = 0;
+        while (pos < _2len)
         {
-            int v0 = 0;
-            for (int j = 0; j < 4; j++)
-            {
-                v0 = v0 >>> 8;
-                int u = (m_ints[i] >>> (j * 4)) & 0xF;
-                int w = table[u] << 24;
-                v0 |= w;
-            }
-            c.m_ints[i + i] = v0;
-
-            v0 = 0;
-            int upper = m_ints[i] >>> 16;
-            for (int j = 0; j < 4; j++)
-            {
-                v0 = v0 >>> 8;
-                int u = (upper >>> (j * 4)) & 0xF;
-                int w = table[u] << 24;
-                v0 |= w;
-            }
-            c.m_ints[i + i + 1] = v0;
+            int mi = m_ints[pos >>> 1];
+            r[pos++] = interleave16(mi & 0xFFFF);
+            r[pos++] = interleave16(mi >>> 16);
         }
-        return c;
+
+        return new IntArray(r);
+    }
+
+    private static void interleave(int[] x, int xOff, int[] z, int zOff, int count, int rounds)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            z[zOff + i] = interleave(x[xOff + i], rounds);
+        }
+    }
+
+    private static int interleave(int x, int rounds)
+    {
+        while (--rounds >= 0)
+        {
+            x = interleave16(x & 0xFFFF) | (interleave16(x >>> 16) << 1);
+        }
+        return x;
+    }
+
+    private static int interleave16(int n)
+    {
+        return INTERLEAVE_TABLE[n & 0xFF] | INTERLEAVE_TABLE[n >>> 8] << 16;
+    }
+
+    public IntArray modInverse(int m, int[] ks)
+    {
+        // Inversion in F2m using the extended Euclidean algorithm
+        // Input: A nonzero polynomial a(z) of degree at most m-1
+        // Output: a(z)^(-1) mod f(z)
+
+        int uzDegree = degree();
+        if (uzDegree == 1)
+        {
+            return this;
+        }
+
+        // u(z) := a(z)
+        IntArray uz = (IntArray)clone();
+
+        int t = getWordLength(m);
+
+        // v(z) := f(z)
+        IntArray vz = new IntArray(t);
+        vz.setBit(m);
+        vz.setBit(0);
+        vz.setBit(ks[0]);
+        if (ks.length > 1) 
+        {
+            vz.setBit(ks[1]);
+            vz.setBit(ks[2]);
+        }
+
+        // g1(z) := 1, g2(z) := 0
+        IntArray g1z = new IntArray(t);
+        g1z.setBit(0);
+        IntArray g2z = new IntArray(t);
+
+        while (uzDegree != 0)
+        {
+            // j := deg(u(z)) - deg(v(z))
+            int j = uzDegree - vz.degree();
+
+            // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j
+            if (j < 0) 
+            {
+                final IntArray uzCopy = uz;
+                uz = vz;
+                vz = uzCopy;
+
+                final IntArray g1zCopy = g1z;
+                g1z = g2z;
+                g2z = g1zCopy;
+
+                j = -j;
+            }
+
+            // u(z) := u(z) + z^j * v(z)
+            // Note, that no reduction modulo f(z) is required, because
+            // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z)))
+            // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z))
+            // = deg(u(z))
+            // uz = uz.xor(vz.shiftLeft(j));
+            uz.addShiftedByBits(vz, j);
+            uzDegree = uz.degree();
+
+            // g1(z) := g1(z) + z^j * g2(z)
+//            g1z = g1z.xor(g2z.shiftLeft(j));
+            if (uzDegree != 0)
+            {
+                g1z.addShiftedByBits(g2z, j);
+            }
+        }
+        return g2z;
     }
 
     public boolean equals(Object o)
@@ -482,7 +822,8 @@
         int hash = 1;
         for (int i = 0; i < usedLen; i++)
         {
-            hash = hash * 31 + m_ints[i];
+            hash *= 31;
+            hash ^= m_ints[i];
         }
         return hash;
     }
@@ -494,25 +835,26 @@
 
     public String toString()
     {
-        int usedLen = getUsedLength();
-        if (usedLen == 0)
+        int i = getUsedLength();
+        if (i == 0)
         {
             return "0";
         }
 
-        StringBuffer sb = new StringBuffer(Integer
-            .toBinaryString(m_ints[usedLen - 1]));
-        for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+        StringBuffer sb = new StringBuffer(Integer.toBinaryString(m_ints[--i]));
+        while (--i >= 0)
         {
-            String hexString = Integer.toBinaryString(m_ints[iarrJ]);
+            String s = Integer.toBinaryString(m_ints[i]);
 
-            // Add leading zeroes, except for highest significant int
-            for (int i = hexString.length(); i < 8; i++)
+            // Add leading zeroes, except for highest significant word
+            int len = s.length();
+            if (len < 32)
             {
-                hexString = "0" + hexString;
+                sb.append(ZEROES.substring(len));
             }
-            sb.append(hexString);
+
+            sb.append(s);
         }
         return sb.toString();
     }
-}
+}
\ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java b/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java
new file mode 100644
index 0000000..7e8b172
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java
@@ -0,0 +1,1995 @@
+package org.bouncycastle.math.ec;
+
+import org.bouncycastle.util.Arrays;
+
+import java.math.BigInteger;
+
+class LongArray
+{
+//    private static long DEINTERLEAVE_MASK = 0x5555555555555555L;
+
+    /*
+     * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
+     * In a binary field, this operation is the same as squaring an 8 bit number.
+     */
+    private static final int[] INTERLEAVE2_TABLE = new int[]
+    {
+        0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+        0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+        0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+        0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+        0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+        0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+        0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+        0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+        0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+        0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+        0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+        0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+        0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+        0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+        0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+        0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+        0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+        0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+        0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+        0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+        0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+        0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+        0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+        0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+        0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+        0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+        0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+        0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+        0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+        0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+        0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+        0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+    };
+
+    /*
+     * This expands 7 bit indices into 21 bit contents (high bit 18), by inserting 0s between bits.
+     */
+    private static final int[] INTERLEAVE3_TABLE = new  int[]
+    {
+        0x00000, 0x00001, 0x00008, 0x00009, 0x00040, 0x00041, 0x00048, 0x00049,
+        0x00200, 0x00201, 0x00208, 0x00209, 0x00240, 0x00241, 0x00248, 0x00249,
+        0x01000, 0x01001, 0x01008, 0x01009, 0x01040, 0x01041, 0x01048, 0x01049,
+        0x01200, 0x01201, 0x01208, 0x01209, 0x01240, 0x01241, 0x01248, 0x01249,
+        0x08000, 0x08001, 0x08008, 0x08009, 0x08040, 0x08041, 0x08048, 0x08049,
+        0x08200, 0x08201, 0x08208, 0x08209, 0x08240, 0x08241, 0x08248, 0x08249,
+        0x09000, 0x09001, 0x09008, 0x09009, 0x09040, 0x09041, 0x09048, 0x09049,
+        0x09200, 0x09201, 0x09208, 0x09209, 0x09240, 0x09241, 0x09248, 0x09249,
+        0x40000, 0x40001, 0x40008, 0x40009, 0x40040, 0x40041, 0x40048, 0x40049,
+        0x40200, 0x40201, 0x40208, 0x40209, 0x40240, 0x40241, 0x40248, 0x40249,
+        0x41000, 0x41001, 0x41008, 0x41009, 0x41040, 0x41041, 0x41048, 0x41049,
+        0x41200, 0x41201, 0x41208, 0x41209, 0x41240, 0x41241, 0x41248, 0x41249,
+        0x48000, 0x48001, 0x48008, 0x48009, 0x48040, 0x48041, 0x48048, 0x48049,
+        0x48200, 0x48201, 0x48208, 0x48209, 0x48240, 0x48241, 0x48248, 0x48249,
+        0x49000, 0x49001, 0x49008, 0x49009, 0x49040, 0x49041, 0x49048, 0x49049,
+        0x49200, 0x49201, 0x49208, 0x49209, 0x49240, 0x49241, 0x49248, 0x49249
+    };
+
+    /*
+     * This expands 8 bit indices into 32 bit contents (high bit 28), by inserting 0s between bits.
+     */
+    private static final int[] INTERLEAVE4_TABLE = new int[]
+    {
+        0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100, 0x00000101, 0x00000110, 0x00000111,
+        0x00001000, 0x00001001, 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110, 0x00001111,
+        0x00010000, 0x00010001, 0x00010010, 0x00010011, 0x00010100, 0x00010101, 0x00010110, 0x00010111,
+        0x00011000, 0x00011001, 0x00011010, 0x00011011, 0x00011100, 0x00011101, 0x00011110, 0x00011111,
+        0x00100000, 0x00100001, 0x00100010, 0x00100011, 0x00100100, 0x00100101, 0x00100110, 0x00100111,
+        0x00101000, 0x00101001, 0x00101010, 0x00101011, 0x00101100, 0x00101101, 0x00101110, 0x00101111,
+        0x00110000, 0x00110001, 0x00110010, 0x00110011, 0x00110100, 0x00110101, 0x00110110, 0x00110111,
+        0x00111000, 0x00111001, 0x00111010, 0x00111011, 0x00111100, 0x00111101, 0x00111110, 0x00111111,
+        0x01000000, 0x01000001, 0x01000010, 0x01000011, 0x01000100, 0x01000101, 0x01000110, 0x01000111,
+        0x01001000, 0x01001001, 0x01001010, 0x01001011, 0x01001100, 0x01001101, 0x01001110, 0x01001111,
+        0x01010000, 0x01010001, 0x01010010, 0x01010011, 0x01010100, 0x01010101, 0x01010110, 0x01010111,
+        0x01011000, 0x01011001, 0x01011010, 0x01011011, 0x01011100, 0x01011101, 0x01011110, 0x01011111,
+        0x01100000, 0x01100001, 0x01100010, 0x01100011, 0x01100100, 0x01100101, 0x01100110, 0x01100111,
+        0x01101000, 0x01101001, 0x01101010, 0x01101011, 0x01101100, 0x01101101, 0x01101110, 0x01101111,
+        0x01110000, 0x01110001, 0x01110010, 0x01110011, 0x01110100, 0x01110101, 0x01110110, 0x01110111,
+        0x01111000, 0x01111001, 0x01111010, 0x01111011, 0x01111100, 0x01111101, 0x01111110, 0x01111111,
+        0x10000000, 0x10000001, 0x10000010, 0x10000011, 0x10000100, 0x10000101, 0x10000110, 0x10000111,
+        0x10001000, 0x10001001, 0x10001010, 0x10001011, 0x10001100, 0x10001101, 0x10001110, 0x10001111,
+        0x10010000, 0x10010001, 0x10010010, 0x10010011, 0x10010100, 0x10010101, 0x10010110, 0x10010111,
+        0x10011000, 0x10011001, 0x10011010, 0x10011011, 0x10011100, 0x10011101, 0x10011110, 0x10011111,
+        0x10100000, 0x10100001, 0x10100010, 0x10100011, 0x10100100, 0x10100101, 0x10100110, 0x10100111,
+        0x10101000, 0x10101001, 0x10101010, 0x10101011, 0x10101100, 0x10101101, 0x10101110, 0x10101111,
+        0x10110000, 0x10110001, 0x10110010, 0x10110011, 0x10110100, 0x10110101, 0x10110110, 0x10110111,
+        0x10111000, 0x10111001, 0x10111010, 0x10111011, 0x10111100, 0x10111101, 0x10111110, 0x10111111,
+        0x11000000, 0x11000001, 0x11000010, 0x11000011, 0x11000100, 0x11000101, 0x11000110, 0x11000111,
+        0x11001000, 0x11001001, 0x11001010, 0x11001011, 0x11001100, 0x11001101, 0x11001110, 0x11001111,
+        0x11010000, 0x11010001, 0x11010010, 0x11010011, 0x11010100, 0x11010101, 0x11010110, 0x11010111,
+        0x11011000, 0x11011001, 0x11011010, 0x11011011, 0x11011100, 0x11011101, 0x11011110, 0x11011111,
+        0x11100000, 0x11100001, 0x11100010, 0x11100011, 0x11100100, 0x11100101, 0x11100110, 0x11100111,
+        0x11101000, 0x11101001, 0x11101010, 0x11101011, 0x11101100, 0x11101101, 0x11101110, 0x11101111,
+        0x11110000, 0x11110001, 0x11110010, 0x11110011, 0x11110100, 0x11110101, 0x11110110, 0x11110111,
+        0x11111000, 0x11111001, 0x11111010, 0x11111011, 0x11111100, 0x11111101, 0x11111110, 0x11111111
+    };
+
+    /*
+     * This expands 7 bit indices into 35 bit contents (high bit 30), by inserting 0s between bits.
+     */
+    private static final int[] INTERLEAVE5_TABLE = new int[] {
+        0x00000000, 0x00000001, 0x00000020, 0x00000021, 0x00000400, 0x00000401, 0x00000420, 0x00000421,
+        0x00008000, 0x00008001, 0x00008020, 0x00008021, 0x00008400, 0x00008401, 0x00008420, 0x00008421,
+        0x00100000, 0x00100001, 0x00100020, 0x00100021, 0x00100400, 0x00100401, 0x00100420, 0x00100421,
+        0x00108000, 0x00108001, 0x00108020, 0x00108021, 0x00108400, 0x00108401, 0x00108420, 0x00108421,
+        0x02000000, 0x02000001, 0x02000020, 0x02000021, 0x02000400, 0x02000401, 0x02000420, 0x02000421,
+        0x02008000, 0x02008001, 0x02008020, 0x02008021, 0x02008400, 0x02008401, 0x02008420, 0x02008421,
+        0x02100000, 0x02100001, 0x02100020, 0x02100021, 0x02100400, 0x02100401, 0x02100420, 0x02100421,
+        0x02108000, 0x02108001, 0x02108020, 0x02108021, 0x02108400, 0x02108401, 0x02108420, 0x02108421,
+        0x40000000, 0x40000001, 0x40000020, 0x40000021, 0x40000400, 0x40000401, 0x40000420, 0x40000421,
+        0x40008000, 0x40008001, 0x40008020, 0x40008021, 0x40008400, 0x40008401, 0x40008420, 0x40008421,
+        0x40100000, 0x40100001, 0x40100020, 0x40100021, 0x40100400, 0x40100401, 0x40100420, 0x40100421,
+        0x40108000, 0x40108001, 0x40108020, 0x40108021, 0x40108400, 0x40108401, 0x40108420, 0x40108421,
+        0x42000000, 0x42000001, 0x42000020, 0x42000021, 0x42000400, 0x42000401, 0x42000420, 0x42000421,
+        0x42008000, 0x42008001, 0x42008020, 0x42008021, 0x42008400, 0x42008401, 0x42008420, 0x42008421,
+        0x42100000, 0x42100001, 0x42100020, 0x42100021, 0x42100400, 0x42100401, 0x42100420, 0x42100421,
+        0x42108000, 0x42108001, 0x42108020, 0x42108021, 0x42108400, 0x42108401, 0x42108420, 0x42108421
+    };
+
+    /*
+     * This expands 9 bit indices into 63 bit (long) contents (high bit 56), by inserting 0s between bits.
+     */
+    private static final long[] INTERLEAVE7_TABLE = new long[]
+    {
+        0x0000000000000000L, 0x0000000000000001L, 0x0000000000000080L, 0x0000000000000081L,
+        0x0000000000004000L, 0x0000000000004001L, 0x0000000000004080L, 0x0000000000004081L,
+        0x0000000000200000L, 0x0000000000200001L, 0x0000000000200080L, 0x0000000000200081L,
+        0x0000000000204000L, 0x0000000000204001L, 0x0000000000204080L, 0x0000000000204081L,
+        0x0000000010000000L, 0x0000000010000001L, 0x0000000010000080L, 0x0000000010000081L,
+        0x0000000010004000L, 0x0000000010004001L, 0x0000000010004080L, 0x0000000010004081L,
+        0x0000000010200000L, 0x0000000010200001L, 0x0000000010200080L, 0x0000000010200081L,
+        0x0000000010204000L, 0x0000000010204001L, 0x0000000010204080L, 0x0000000010204081L,
+        0x0000000800000000L, 0x0000000800000001L, 0x0000000800000080L, 0x0000000800000081L,
+        0x0000000800004000L, 0x0000000800004001L, 0x0000000800004080L, 0x0000000800004081L,
+        0x0000000800200000L, 0x0000000800200001L, 0x0000000800200080L, 0x0000000800200081L,
+        0x0000000800204000L, 0x0000000800204001L, 0x0000000800204080L, 0x0000000800204081L,
+        0x0000000810000000L, 0x0000000810000001L, 0x0000000810000080L, 0x0000000810000081L,
+        0x0000000810004000L, 0x0000000810004001L, 0x0000000810004080L, 0x0000000810004081L,
+        0x0000000810200000L, 0x0000000810200001L, 0x0000000810200080L, 0x0000000810200081L,
+        0x0000000810204000L, 0x0000000810204001L, 0x0000000810204080L, 0x0000000810204081L,
+        0x0000040000000000L, 0x0000040000000001L, 0x0000040000000080L, 0x0000040000000081L,
+        0x0000040000004000L, 0x0000040000004001L, 0x0000040000004080L, 0x0000040000004081L,
+        0x0000040000200000L, 0x0000040000200001L, 0x0000040000200080L, 0x0000040000200081L,
+        0x0000040000204000L, 0x0000040000204001L, 0x0000040000204080L, 0x0000040000204081L,
+        0x0000040010000000L, 0x0000040010000001L, 0x0000040010000080L, 0x0000040010000081L,
+        0x0000040010004000L, 0x0000040010004001L, 0x0000040010004080L, 0x0000040010004081L,
+        0x0000040010200000L, 0x0000040010200001L, 0x0000040010200080L, 0x0000040010200081L,
+        0x0000040010204000L, 0x0000040010204001L, 0x0000040010204080L, 0x0000040010204081L,
+        0x0000040800000000L, 0x0000040800000001L, 0x0000040800000080L, 0x0000040800000081L,
+        0x0000040800004000L, 0x0000040800004001L, 0x0000040800004080L, 0x0000040800004081L,
+        0x0000040800200000L, 0x0000040800200001L, 0x0000040800200080L, 0x0000040800200081L,
+        0x0000040800204000L, 0x0000040800204001L, 0x0000040800204080L, 0x0000040800204081L,
+        0x0000040810000000L, 0x0000040810000001L, 0x0000040810000080L, 0x0000040810000081L,
+        0x0000040810004000L, 0x0000040810004001L, 0x0000040810004080L, 0x0000040810004081L,
+        0x0000040810200000L, 0x0000040810200001L, 0x0000040810200080L, 0x0000040810200081L,
+        0x0000040810204000L, 0x0000040810204001L, 0x0000040810204080L, 0x0000040810204081L,
+        0x0002000000000000L, 0x0002000000000001L, 0x0002000000000080L, 0x0002000000000081L,
+        0x0002000000004000L, 0x0002000000004001L, 0x0002000000004080L, 0x0002000000004081L,
+        0x0002000000200000L, 0x0002000000200001L, 0x0002000000200080L, 0x0002000000200081L,
+        0x0002000000204000L, 0x0002000000204001L, 0x0002000000204080L, 0x0002000000204081L,
+        0x0002000010000000L, 0x0002000010000001L, 0x0002000010000080L, 0x0002000010000081L,
+        0x0002000010004000L, 0x0002000010004001L, 0x0002000010004080L, 0x0002000010004081L,
+        0x0002000010200000L, 0x0002000010200001L, 0x0002000010200080L, 0x0002000010200081L,
+        0x0002000010204000L, 0x0002000010204001L, 0x0002000010204080L, 0x0002000010204081L,
+        0x0002000800000000L, 0x0002000800000001L, 0x0002000800000080L, 0x0002000800000081L,
+        0x0002000800004000L, 0x0002000800004001L, 0x0002000800004080L, 0x0002000800004081L,
+        0x0002000800200000L, 0x0002000800200001L, 0x0002000800200080L, 0x0002000800200081L,
+        0x0002000800204000L, 0x0002000800204001L, 0x0002000800204080L, 0x0002000800204081L,
+        0x0002000810000000L, 0x0002000810000001L, 0x0002000810000080L, 0x0002000810000081L,
+        0x0002000810004000L, 0x0002000810004001L, 0x0002000810004080L, 0x0002000810004081L,
+        0x0002000810200000L, 0x0002000810200001L, 0x0002000810200080L, 0x0002000810200081L,
+        0x0002000810204000L, 0x0002000810204001L, 0x0002000810204080L, 0x0002000810204081L,
+        0x0002040000000000L, 0x0002040000000001L, 0x0002040000000080L, 0x0002040000000081L,
+        0x0002040000004000L, 0x0002040000004001L, 0x0002040000004080L, 0x0002040000004081L,
+        0x0002040000200000L, 0x0002040000200001L, 0x0002040000200080L, 0x0002040000200081L,
+        0x0002040000204000L, 0x0002040000204001L, 0x0002040000204080L, 0x0002040000204081L,
+        0x0002040010000000L, 0x0002040010000001L, 0x0002040010000080L, 0x0002040010000081L,
+        0x0002040010004000L, 0x0002040010004001L, 0x0002040010004080L, 0x0002040010004081L,
+        0x0002040010200000L, 0x0002040010200001L, 0x0002040010200080L, 0x0002040010200081L,
+        0x0002040010204000L, 0x0002040010204001L, 0x0002040010204080L, 0x0002040010204081L,
+        0x0002040800000000L, 0x0002040800000001L, 0x0002040800000080L, 0x0002040800000081L,
+        0x0002040800004000L, 0x0002040800004001L, 0x0002040800004080L, 0x0002040800004081L,
+        0x0002040800200000L, 0x0002040800200001L, 0x0002040800200080L, 0x0002040800200081L,
+        0x0002040800204000L, 0x0002040800204001L, 0x0002040800204080L, 0x0002040800204081L,
+        0x0002040810000000L, 0x0002040810000001L, 0x0002040810000080L, 0x0002040810000081L,
+        0x0002040810004000L, 0x0002040810004001L, 0x0002040810004080L, 0x0002040810004081L,
+        0x0002040810200000L, 0x0002040810200001L, 0x0002040810200080L, 0x0002040810200081L,
+        0x0002040810204000L, 0x0002040810204001L, 0x0002040810204080L, 0x0002040810204081L,
+        0x0100000000000000L, 0x0100000000000001L, 0x0100000000000080L, 0x0100000000000081L,
+        0x0100000000004000L, 0x0100000000004001L, 0x0100000000004080L, 0x0100000000004081L,
+        0x0100000000200000L, 0x0100000000200001L, 0x0100000000200080L, 0x0100000000200081L,
+        0x0100000000204000L, 0x0100000000204001L, 0x0100000000204080L, 0x0100000000204081L,
+        0x0100000010000000L, 0x0100000010000001L, 0x0100000010000080L, 0x0100000010000081L,
+        0x0100000010004000L, 0x0100000010004001L, 0x0100000010004080L, 0x0100000010004081L,
+        0x0100000010200000L, 0x0100000010200001L, 0x0100000010200080L, 0x0100000010200081L,
+        0x0100000010204000L, 0x0100000010204001L, 0x0100000010204080L, 0x0100000010204081L,
+        0x0100000800000000L, 0x0100000800000001L, 0x0100000800000080L, 0x0100000800000081L,
+        0x0100000800004000L, 0x0100000800004001L, 0x0100000800004080L, 0x0100000800004081L,
+        0x0100000800200000L, 0x0100000800200001L, 0x0100000800200080L, 0x0100000800200081L,
+        0x0100000800204000L, 0x0100000800204001L, 0x0100000800204080L, 0x0100000800204081L,
+        0x0100000810000000L, 0x0100000810000001L, 0x0100000810000080L, 0x0100000810000081L,
+        0x0100000810004000L, 0x0100000810004001L, 0x0100000810004080L, 0x0100000810004081L,
+        0x0100000810200000L, 0x0100000810200001L, 0x0100000810200080L, 0x0100000810200081L,
+        0x0100000810204000L, 0x0100000810204001L, 0x0100000810204080L, 0x0100000810204081L,
+        0x0100040000000000L, 0x0100040000000001L, 0x0100040000000080L, 0x0100040000000081L,
+        0x0100040000004000L, 0x0100040000004001L, 0x0100040000004080L, 0x0100040000004081L,
+        0x0100040000200000L, 0x0100040000200001L, 0x0100040000200080L, 0x0100040000200081L,
+        0x0100040000204000L, 0x0100040000204001L, 0x0100040000204080L, 0x0100040000204081L,
+        0x0100040010000000L, 0x0100040010000001L, 0x0100040010000080L, 0x0100040010000081L,
+        0x0100040010004000L, 0x0100040010004001L, 0x0100040010004080L, 0x0100040010004081L,
+        0x0100040010200000L, 0x0100040010200001L, 0x0100040010200080L, 0x0100040010200081L,
+        0x0100040010204000L, 0x0100040010204001L, 0x0100040010204080L, 0x0100040010204081L,
+        0x0100040800000000L, 0x0100040800000001L, 0x0100040800000080L, 0x0100040800000081L,
+        0x0100040800004000L, 0x0100040800004001L, 0x0100040800004080L, 0x0100040800004081L,
+        0x0100040800200000L, 0x0100040800200001L, 0x0100040800200080L, 0x0100040800200081L,
+        0x0100040800204000L, 0x0100040800204001L, 0x0100040800204080L, 0x0100040800204081L,
+        0x0100040810000000L, 0x0100040810000001L, 0x0100040810000080L, 0x0100040810000081L,
+        0x0100040810004000L, 0x0100040810004001L, 0x0100040810004080L, 0x0100040810004081L,
+        0x0100040810200000L, 0x0100040810200001L, 0x0100040810200080L, 0x0100040810200081L,
+        0x0100040810204000L, 0x0100040810204001L, 0x0100040810204080L, 0x0100040810204081L,
+        0x0102000000000000L, 0x0102000000000001L, 0x0102000000000080L, 0x0102000000000081L,
+        0x0102000000004000L, 0x0102000000004001L, 0x0102000000004080L, 0x0102000000004081L,
+        0x0102000000200000L, 0x0102000000200001L, 0x0102000000200080L, 0x0102000000200081L,
+        0x0102000000204000L, 0x0102000000204001L, 0x0102000000204080L, 0x0102000000204081L,
+        0x0102000010000000L, 0x0102000010000001L, 0x0102000010000080L, 0x0102000010000081L,
+        0x0102000010004000L, 0x0102000010004001L, 0x0102000010004080L, 0x0102000010004081L,
+        0x0102000010200000L, 0x0102000010200001L, 0x0102000010200080L, 0x0102000010200081L,
+        0x0102000010204000L, 0x0102000010204001L, 0x0102000010204080L, 0x0102000010204081L,
+        0x0102000800000000L, 0x0102000800000001L, 0x0102000800000080L, 0x0102000800000081L,
+        0x0102000800004000L, 0x0102000800004001L, 0x0102000800004080L, 0x0102000800004081L,
+        0x0102000800200000L, 0x0102000800200001L, 0x0102000800200080L, 0x0102000800200081L,
+        0x0102000800204000L, 0x0102000800204001L, 0x0102000800204080L, 0x0102000800204081L,
+        0x0102000810000000L, 0x0102000810000001L, 0x0102000810000080L, 0x0102000810000081L,
+        0x0102000810004000L, 0x0102000810004001L, 0x0102000810004080L, 0x0102000810004081L,
+        0x0102000810200000L, 0x0102000810200001L, 0x0102000810200080L, 0x0102000810200081L,
+        0x0102000810204000L, 0x0102000810204001L, 0x0102000810204080L, 0x0102000810204081L,
+        0x0102040000000000L, 0x0102040000000001L, 0x0102040000000080L, 0x0102040000000081L,
+        0x0102040000004000L, 0x0102040000004001L, 0x0102040000004080L, 0x0102040000004081L,
+        0x0102040000200000L, 0x0102040000200001L, 0x0102040000200080L, 0x0102040000200081L,
+        0x0102040000204000L, 0x0102040000204001L, 0x0102040000204080L, 0x0102040000204081L,
+        0x0102040010000000L, 0x0102040010000001L, 0x0102040010000080L, 0x0102040010000081L,
+        0x0102040010004000L, 0x0102040010004001L, 0x0102040010004080L, 0x0102040010004081L,
+        0x0102040010200000L, 0x0102040010200001L, 0x0102040010200080L, 0x0102040010200081L,
+        0x0102040010204000L, 0x0102040010204001L, 0x0102040010204080L, 0x0102040010204081L,
+        0x0102040800000000L, 0x0102040800000001L, 0x0102040800000080L, 0x0102040800000081L,
+        0x0102040800004000L, 0x0102040800004001L, 0x0102040800004080L, 0x0102040800004081L,
+        0x0102040800200000L, 0x0102040800200001L, 0x0102040800200080L, 0x0102040800200081L,
+        0x0102040800204000L, 0x0102040800204001L, 0x0102040800204080L, 0x0102040800204081L,
+        0x0102040810000000L, 0x0102040810000001L, 0x0102040810000080L, 0x0102040810000081L,
+        0x0102040810004000L, 0x0102040810004001L, 0x0102040810004080L, 0x0102040810004081L,
+        0x0102040810200000L, 0x0102040810200001L, 0x0102040810200080L, 0x0102040810200081L,
+        0x0102040810204000L, 0x0102040810204001L, 0x0102040810204080L, 0x0102040810204081L
+    };
+
+    // For toString(); must have length 64
+    private static final String ZEROES = "0000000000000000000000000000000000000000000000000000000000000000";
+
+    final static byte[] bitLengths =
+    {
+        0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
+    };
+
+    // TODO make m fixed for the LongArray, and hence compute T once and for all
+
+    private long[] m_ints;
+
+    public LongArray(int intLen)
+    {
+        m_ints = new long[intLen];
+    }
+
+    public LongArray(long[] ints)
+    {
+        m_ints = ints;
+    }
+
+    public LongArray(long[] ints, int off, int len)
+    {
+        if (off == 0 && len == ints.length)
+        {
+            m_ints = ints;
+        }
+        else
+        {
+            m_ints = new long[len];
+            System.arraycopy(ints, off, m_ints, 0, len);
+        }
+    }
+
+    public LongArray(BigInteger bigInt)
+    {
+        if (bigInt == null || bigInt.signum() < 0)
+        {
+            throw new IllegalArgumentException("invalid F2m field value");
+        }
+
+        if (bigInt.signum() == 0)
+        {
+            m_ints = new long[] { 0L };
+            return;
+        }
+
+        byte[] barr = bigInt.toByteArray();
+        int barrLen = barr.length;
+        int barrStart = 0;
+        if (barr[0] == 0)
+        {
+            // First byte is 0 to enforce highest (=sign) bit is zero.
+            // In this case ignore barr[0].
+            barrLen--;
+            barrStart = 1;
+        }
+        int intLen = (barrLen + 7) / 8;
+        m_ints = new long[intLen];
+
+        int iarrJ = intLen - 1;
+        int rem = barrLen % 8 + barrStart;
+        long temp = 0;
+        int barrI = barrStart;
+        if (barrStart < rem)
+        {
+            for (; barrI < rem; barrI++)
+            {
+                temp <<= 8;
+                int barrBarrI = barr[barrI] & 0xFF;
+                temp |= barrBarrI;
+            }
+            m_ints[iarrJ--] = temp;
+        }
+
+        for (; iarrJ >= 0; iarrJ--)
+        {
+            temp = 0;
+            for (int i = 0; i < 8; i++)
+            {
+                temp <<= 8;
+                int barrBarrI = barr[barrI++] & 0xFF;
+                temp |= barrBarrI;
+            }
+            m_ints[iarrJ] = temp;
+        }
+    }
+
+    public boolean isZero()
+    {
+        long[] a = m_ints;
+        for (int i = 0; i < a.length; ++i)
+        {
+            if (a[i] != 0L)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public int getUsedLength()
+    {
+        return getUsedLengthFrom(m_ints.length);
+    }
+
+    public int getUsedLengthFrom(int from)
+    {
+        long[] a = m_ints;
+        from = Math.min(from, a.length);
+
+        if (from < 1)
+        {
+            return 0;
+        }
+
+        // Check if first element will act as sentinel
+        if (a[0] != 0)
+        {
+            while (a[--from] == 0)
+            {
+            }
+            return from + 1;
+        }
+
+        do
+        {
+            if (a[--from] != 0)
+            {
+                return from + 1;
+            }
+        }
+        while (from > 0);
+
+        return 0;
+    }
+
+    public int degree()
+    {
+        int i = m_ints.length;
+        long w;
+        do
+        {
+            if (i == 0)
+            {
+                return 0;
+            }
+            w = m_ints[--i];
+        }
+        while (w == 0);
+
+        return (i << 6) + bitLength(w);
+    }
+
+    private int degreeFrom(int limit)
+    {
+        int i = (limit + 62) >>> 6;
+        long w;
+        do
+        {
+            if (i == 0)
+            {
+                return 0;
+            }
+            w = m_ints[--i];
+        }
+        while (w == 0);
+
+        return (i << 6) + bitLength(w);
+    }
+
+//    private int lowestCoefficient()
+//    {
+//        for (int i = 0; i < m_ints.length; ++i)
+//        {
+//            long mi = m_ints[i];
+//            if (mi != 0)
+//            {
+//                int j = 0;
+//                while ((mi & 0xFFL) == 0)
+//                {
+//                    j += 8;
+//                    mi >>>= 8;
+//                }
+//                while ((mi & 1L) == 0)
+//                {
+//                    ++j;
+//                    mi >>>= 1;
+//                }
+//                return (i << 6) + j;
+//            }
+//        }
+//        return -1;
+//    }
+
+    private static int bitLength(long w)
+    {
+        int u = (int)(w >>> 32), b;
+        if (u == 0)
+        {
+            u = (int)w;
+            b = 0;
+        }
+        else
+        {
+            b = 32;
+        }
+
+        int t = u >>> 16, k;
+        if (t == 0)
+        {
+            t = u >>> 8;
+            k = (t == 0) ? bitLengths[u] : 8 + bitLengths[t];
+        }
+        else
+        {
+            int v = t >>> 8;
+            k = (v == 0) ? 16 + bitLengths[t] : 24 + bitLengths[v];
+        }
+
+        return b + k;
+    }
+
+    private long[] resizedInts(int newLen)
+    {
+        long[] newInts = new long[newLen];
+        System.arraycopy(m_ints, 0, newInts, 0, Math.min(m_ints.length, newLen));
+        return newInts;
+    }
+
+    public BigInteger toBigInteger()
+    {
+        int usedLen = getUsedLength();
+        if (usedLen == 0)
+        {
+            return ECConstants.ZERO;
+        }
+
+        long highestInt = m_ints[usedLen - 1];
+        byte[] temp = new byte[8];
+        int barrI = 0;
+        boolean trailingZeroBytesDone = false;
+        for (int j = 7; j >= 0; j--)
+        {
+            byte thisByte = (byte)(highestInt >>> (8 * j));
+            if (trailingZeroBytesDone || (thisByte != 0))
+            {
+                trailingZeroBytesDone = true;
+                temp[barrI++] = thisByte;
+            }
+        }
+
+        int barrLen = 8 * (usedLen - 1) + barrI;
+        byte[] barr = new byte[barrLen];
+        for (int j = 0; j < barrI; j++)
+        {
+            barr[j] = temp[j];
+        }
+        // Highest value int is done now
+
+        for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+        {
+            long mi = m_ints[iarrJ];
+            for (int j = 7; j >= 0; j--)
+            {
+                barr[barrI++] = (byte)(mi >>> (8 * j));
+            }
+        }
+        return new BigInteger(1, barr);
+    }
+
+//    private static long shiftUp(long[] x, int xOff, int count)
+//    {
+//        long prev = 0;
+//        for (int i = 0; i < count; ++i)
+//        {
+//            long next = x[xOff + i];
+//            x[xOff + i] = (next << 1) | prev;
+//            prev = next >>> 63;
+//        }
+//        return prev;
+//    }
+
+    private static long shiftUp(long[] x, int xOff, int count, int shift)
+    {
+        int shiftInv = 64 - shift;
+        long prev = 0;
+        for (int i = 0; i < count; ++i)
+        {
+            long next = x[xOff + i];
+            x[xOff + i] = (next << shift) | prev;
+            prev = next >>> shiftInv;
+        }
+        return prev;
+    }
+
+    private static long shiftUp(long[] x, int xOff, long[] z, int zOff, int count, int shift)
+    {
+        int shiftInv = 64 - shift;
+        long prev = 0;
+        for (int i = 0; i < count; ++i)
+        {
+            long next = x[xOff + i];
+            z[zOff + i] = (next << shift) | prev;
+            prev = next >>> shiftInv;
+        }
+        return prev;
+    }
+
+    public LongArray addOne()
+    {
+        if (m_ints.length == 0)
+        {
+            return new LongArray(new long[]{ 1L });
+        }
+
+        int resultLen = Math.max(1, getUsedLength());
+        long[] ints = resizedInts(resultLen);
+        ints[0] ^= 1L;
+        return new LongArray(ints);
+    }
+
+//    private void addShiftedByBits(LongArray other, int bits)
+//    {
+//        int words = bits >>> 6;
+//        int shift = bits & 0x3F;
+//
+//        if (shift == 0)
+//        {
+//            addShiftedByWords(other, words);
+//            return;
+//        }
+//
+//        int otherUsedLen = other.getUsedLength();
+//        if (otherUsedLen == 0)
+//        {
+//            return;
+//        }
+//
+//        int minLen = otherUsedLen + words + 1;
+//        if (minLen > m_ints.length)
+//        {
+//            m_ints = resizedInts(minLen);
+//        }
+//
+//        long carry = addShiftedByBits(m_ints, words, other.m_ints, 0, otherUsedLen, shift);
+//        m_ints[otherUsedLen + words] ^= carry;
+//    }
+
+    private void addShiftedByBitsSafe(LongArray other, int otherDegree, int bits)
+    {
+        int otherLen = (otherDegree + 63) >>> 6;
+
+        int words = bits >>> 6;
+        int shift = bits & 0x3F;
+
+        if (shift == 0)
+        {
+            add(m_ints, words, other.m_ints, 0, otherLen);
+            return;
+        }
+
+        long carry = addShiftedUp(m_ints, words, other.m_ints, 0, otherLen, shift);
+        if (carry != 0L)
+        {
+            m_ints[otherLen + words] ^= carry;
+        }
+    }
+
+    private static long addShiftedUp(long[] x, int xOff, long[] y, int yOff, int count, int shift)
+    {
+        int shiftInv = 64 - shift;
+        long prev = 0;
+        for (int i = 0; i < count; ++i)
+        {
+            long next = y[yOff + i];
+            x[xOff + i] ^= (next << shift) | prev;
+            prev = next >>> shiftInv;
+        }
+        return prev;
+    }
+
+    private static long addShiftedDown(long[] x, int xOff, long[] y, int yOff, int count, int shift)
+    {
+        int shiftInv = 64 - shift;
+        long prev = 0;
+        int i = count;
+        while (--i >= 0)
+        {
+            long next = y[yOff + i];
+            x[xOff + i] ^= (next >>> shift) | prev;
+            prev = next << shiftInv;
+        }
+        return prev;
+    }
+
+    public void addShiftedByWords(LongArray other, int words)
+    {
+        int otherUsedLen = other.getUsedLength();
+        if (otherUsedLen == 0)
+        {
+            return;
+        }
+
+        int minLen = otherUsedLen + words;
+        if (minLen > m_ints.length)
+        {
+            m_ints = resizedInts(minLen);
+        }
+
+        add(m_ints, words, other.m_ints, 0, otherUsedLen);
+    }
+
+    private static void add(long[] x, int xOff, long[] y, int yOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            x[xOff + i] ^= y[yOff + i];
+        }
+    }
+
+    private static void add(long[] x, int xOff, long[] y, int yOff, long[] z, int zOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            z[zOff + i] = x[xOff + i] ^ y[yOff + i];
+        }
+    }
+
+    private static void addBoth(long[] x, int xOff, long[] y1, int y1Off, long[] y2, int y2Off, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            x[xOff + i] ^= y1[y1Off + i] ^ y2[y2Off + i];
+        }
+    }
+
+    private static void distribute(long[] x, int src, int dst1, int dst2, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            long v = x[src + i];
+            x[dst1 + i] ^= v;
+            x[dst2 + i] ^= v;
+        }
+    }
+
+    public int getLength()
+    {
+        return m_ints.length;
+    }
+
+    private static void flipWord(long[] buf, int off, int bit, long word)
+    {
+        int n = off + (bit >>> 6);
+        int shift = bit & 0x3F;
+        if (shift == 0)
+        {
+            buf[n] ^= word;
+        }
+        else
+        {
+            buf[n] ^= word << shift;
+            word >>>= (64 - shift);
+            if (word != 0)
+            {
+                buf[++n] ^= word;
+            }
+        }
+    }
+
+//    private static long getWord(long[] buf, int off, int len, int bit)
+//    {
+//        int n = off + (bit >>> 6);
+//        int shift = bit & 0x3F;
+//        if (shift == 0)
+//        {
+//            return buf[n];
+//        }
+//        long result = buf[n] >>> shift;
+//        if (++n < len)
+//        {
+//            result |= buf[n] << (64 - shift);
+//        }
+//        return result;
+//    }
+
+    public boolean testBitZero()
+    {
+        return m_ints.length > 0 && (m_ints[0] & 1L) != 0;
+    }
+
+    private static boolean testBit(long[] buf, int off, int n)
+    {
+        // theInt = n / 64
+        int theInt = n >>> 6;
+        // theBit = n % 64
+        int theBit = n & 0x3F;
+        long tester = 1L << theBit;
+        return (buf[off + theInt] & tester) != 0;
+    }
+
+    private static void flipBit(long[] buf, int off, int n)
+    {
+        // theInt = n / 64
+        int theInt = n >>> 6;
+        // theBit = n % 64
+        int theBit = n & 0x3F;
+        long flipper = 1L << theBit;
+        buf[off + theInt] ^= flipper;
+    }
+
+//    private static void setBit(long[] buf, int off, int n)
+//    {
+//        // theInt = n / 64
+//        int theInt = n >>> 6;
+//        // theBit = n % 64
+//        int theBit = n & 0x3F;
+//        long setter = 1L << theBit;
+//        buf[off + theInt] |= setter;
+//    }
+//
+//    private static void clearBit(long[] buf, int off, int n)
+//    {
+//        // theInt = n / 64
+//        int theInt = n >>> 6;
+//        // theBit = n % 64
+//        int theBit = n & 0x3F;
+//        long setter = 1L << theBit;
+//        buf[off + theInt] &= ~setter;
+//    }
+
+    private static void multiplyWord(long a, long[] b, int bLen, long[] c, int cOff)
+    {
+        if ((a & 1L) != 0L)
+        {
+            add(c, cOff, b, 0, bLen);
+        }
+        int k = 1;
+        while ((a >>>= 1) != 0)
+        {
+            if ((a & 1L) != 0L)
+            {
+                long carry = addShiftedUp(c, cOff, b, 0, bLen, k);
+                if (carry != 0)
+                {
+                    c[cOff + bLen] ^= carry;
+                }
+            }
+            ++k;
+        }
+    }
+
+    public LongArray modMultiplyLD(LongArray other, int m, int[] ks)
+    {
+        /*
+         * Find out the degree of each argument and handle the zero cases
+         */
+        int aDeg = degree();
+        if (aDeg == 0)
+        {
+            return this;
+        }
+        int bDeg = other.degree();
+        if (bDeg == 0)
+        {
+            return other;
+        }
+
+        /*
+         * Swap if necessary so that A is the smaller argument
+         */
+        LongArray A = this, B = other;
+        if (aDeg > bDeg)
+        {
+            A = other; B = this;
+            int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+        }
+
+        /*
+         * Establish the word lengths of the arguments and result
+         */
+        int aLen = (aDeg + 63) >>> 6;
+        int bLen = (bDeg + 63) >>> 6;
+        int cLen = (aDeg + bDeg + 62) >>> 6;
+
+        if (aLen == 1)
+        {
+            long a = A.m_ints[0];
+            if (a == 1L)
+            {
+                return B;
+            }
+
+            /*
+             * Fast path for small A, with performance dependent only on the number of set bits
+             */
+            long[] c = new long[cLen];
+            multiplyWord(a, B.m_ints, bLen, c, 0);
+
+            /*
+             * Reduce the raw answer against the reduction coefficients
+             */
+            return reduceResult(c, 0, cLen, m, ks);
+        }
+
+        /*
+         * Determine if B will get bigger during shifting
+         */
+        int bMax = (bDeg + 7 + 63) >>> 6;
+
+        /*
+         * Lookup table for the offset of each B in the tables
+         */
+        int[] ti = new int[16];
+
+        /*
+         * Precompute table of all 4-bit products of B
+         */
+        long[] T0 = new long[bMax << 4];
+        int tOff = bMax;
+        ti[1] = tOff;
+        System.arraycopy(B.m_ints, 0, T0, tOff, bLen);
+        for (int i = 2; i < 16; ++i)
+        {
+            ti[i] = (tOff += bMax);
+            if ((i & 1) == 0)
+            {
+                shiftUp(T0, tOff >>> 1, T0, tOff, bMax, 1);
+            }
+            else
+            {
+                add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
+            }
+        }
+
+        /*
+         * Second table with all 4-bit products of B shifted 4 bits
+         */
+        long[] T1 = new long[T0.length];
+        shiftUp(T0, 0, T1, 0, T0.length, 4);
+//        shiftUp(T0, bMax, T1, bMax, tOff, 4);
+
+        long[] a = A.m_ints;
+        long[] c = new long[cLen];
+
+        int MASK = 0xF;
+
+        /*
+         * Lopez-Dahab algorithm
+         */
+
+        for (int k = 56; k >= 0; k -= 8)
+        {
+            for (int j = 1; j < aLen; j += 2)
+            {
+                int aVal = (int)(a[j] >>> k);
+                int u = aVal & MASK;
+                int v = (aVal >>> 4) & MASK;
+                addBoth(c, j - 1, T0, ti[u], T1, ti[v], bMax);
+            }
+            shiftUp(c, 0, cLen, 8);
+        }
+
+        for (int k = 56; k >= 0; k -= 8)
+        {
+            for (int j = 0; j < aLen; j += 2)
+            {
+                int aVal = (int)(a[j] >>> k);
+                int u = aVal & MASK;
+                int v = (aVal >>> 4) & MASK;
+                addBoth(c, j, T0, ti[u], T1, ti[v], bMax);
+            }
+            if (k > 0)
+            {
+                shiftUp(c, 0, cLen, 8);
+            }
+        }
+
+        /*
+         * Finally the raw answer is collected, reduce it against the reduction coefficients
+         */
+        return reduceResult(c, 0, cLen, m, ks);
+    }
+
+    public LongArray modMultiply(LongArray other, int m, int[] ks)
+    {
+        /*
+         * Find out the degree of each argument and handle the zero cases
+         */
+        int aDeg = degree();
+        if (aDeg == 0)
+        {
+            return this;
+        }
+        int bDeg = other.degree();
+        if (bDeg == 0)
+        {
+            return other;
+        }
+
+        /*
+         * Swap if necessary so that A is the smaller argument
+         */
+        LongArray A = this, B = other;
+        if (aDeg > bDeg)
+        {
+            A = other; B = this;
+            int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+        }
+
+        /*
+         * Establish the word lengths of the arguments and result
+         */
+        int aLen = (aDeg + 63) >>> 6;
+        int bLen = (bDeg + 63) >>> 6;
+        int cLen = (aDeg + bDeg + 62) >>> 6;
+
+        if (aLen == 1)
+        {
+            long a = A.m_ints[0];
+            if (a == 1L)
+            {
+                return B;
+            }
+
+            /*
+             * Fast path for small A, with performance dependent only on the number of set bits
+             */
+            long[] c = new long[cLen];
+            multiplyWord(a, B.m_ints, bLen, c, 0);
+
+            /*
+             * Reduce the raw answer against the reduction coefficients
+             */
+            return reduceResult(c, 0, cLen, m, ks);
+        }
+
+        /*
+         * Determine if B will get bigger during shifting
+         */
+        int bMax = (bDeg + 7 + 63) >>> 6;
+
+        /*
+         * Lookup table for the offset of each B in the tables
+         */
+        int[] ti = new int[16];
+
+        /*
+         * Precompute table of all 4-bit products of B
+         */
+        long[] T0 = new long[bMax << 4];
+        int tOff = bMax;
+        ti[1] = tOff;
+        System.arraycopy(B.m_ints, 0, T0, tOff, bLen);
+        for (int i = 2; i < 16; ++i)
+        {
+            ti[i] = (tOff += bMax);
+            if ((i & 1) == 0)
+            {
+                shiftUp(T0, tOff >>> 1, T0, tOff, bMax, 1);
+            }
+            else
+            {
+                add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
+            }
+        }
+
+        /*
+         * Second table with all 4-bit products of B shifted 4 bits
+         */
+        long[] T1 = new long[T0.length];
+        shiftUp(T0, 0, T1, 0, T0.length, 4);
+//        shiftUp(T0, bMax, T1, bMax, tOff, 4);
+
+        long[] a = A.m_ints;
+        long[] c = new long[cLen << 3];
+
+        int MASK = 0xF;
+
+        /*
+         * Lopez-Dahab (Modified) algorithm
+         */
+
+        for (int aPos = 0; aPos < aLen; ++aPos)
+        {
+            long aVal = a[aPos];
+            int cOff = aPos;
+            for (;;)
+            {
+                int u = (int)aVal & MASK;
+                aVal >>>= 4;
+                int v = (int)aVal & MASK;
+                addBoth(c, cOff, T0, ti[u], T1, ti[v], bMax);
+                if ((aVal >>>= 4) == 0L)
+                {
+                    break;
+                }
+                cOff += cLen;
+            }
+        }
+
+        int cOff = c.length;
+        while ((cOff -= cLen) != 0)
+        {
+            addShiftedUp(c, cOff - cLen, c, cOff, cLen, 8);
+        }
+
+        /*
+         * Finally the raw answer is collected, reduce it against the reduction coefficients
+         */
+        return reduceResult(c, 0, cLen, m, ks);
+    }
+
+    public LongArray modMultiplyAlt(LongArray other, int m, int[] ks)
+    {
+        /*
+         * Find out the degree of each argument and handle the zero cases
+         */
+        int aDeg = degree();
+        if (aDeg == 0)
+        {
+            return this;
+        }
+        int bDeg = other.degree();
+        if (bDeg == 0)
+        {
+            return other;
+        }
+
+        /*
+         * Swap if necessary so that A is the smaller argument
+         */
+        LongArray A = this, B = other;
+        if (aDeg > bDeg)
+        {
+            A = other; B = this;
+            int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+        }
+
+        /*
+         * Establish the word lengths of the arguments and result
+         */
+        int aLen = (aDeg + 63) >>> 6;
+        int bLen = (bDeg + 63) >>> 6;
+        int cLen = (aDeg + bDeg + 62) >>> 6;
+
+        if (aLen == 1)
+        {
+            long a = A.m_ints[0];
+            if (a == 1L)
+            {
+                return B;
+            }
+
+            /*
+             * Fast path for small A, with performance dependent only on the number of set bits
+             */
+            long[] c = new long[cLen];
+            multiplyWord(a, B.m_ints, bLen, c, 0);
+
+            /*
+             * Reduce the raw answer against the reduction coefficients
+             */
+            return reduceResult(c, 0, cLen, m, ks);
+        }
+
+        // NOTE: This works, but is slower than width 4 processing
+//        if (aLen == 2)
+//        {
+//            /*
+//             * Use common-multiplicand optimization to save ~1/4 of the adds
+//             */
+//            long a1 = A.m_ints[0], a2 = A.m_ints[1];
+//            long aa = a1 & a2; a1 ^= aa; a2 ^= aa;
+//
+//            long[] b = B.m_ints;
+//            long[] c = new long[cLen];
+//            multiplyWord(aa, b, bLen, c, 1);
+//            add(c, 0, c, 1, cLen - 1);
+//            multiplyWord(a1, b, bLen, c, 0);
+//            multiplyWord(a2, b, bLen, c, 1);
+//
+//            /*
+//             * Reduce the raw answer against the reduction coefficients
+//             */
+//            return reduceResult(c, 0, cLen, m, ks);
+//        }
+
+        /*
+         * Determine the parameters of the interleaved window algorithm: the 'width' in bits to
+         * process together, the number of evaluation 'positions' implied by that width, and the
+         * 'top' position at which the regular window algorithm stops.
+         */
+        int width, positions, top, banks;
+
+        // NOTE: width 4 is the fastest over the entire range of sizes used in current crypto 
+//        width = 1; positions = 64; top = 64; banks = 4;
+//        width = 2; positions = 32; top = 64; banks = 4;
+//        width = 3; positions = 21; top = 63; banks = 3;
+        width = 4; positions = 16; top = 64; banks = 8;
+//        width = 5; positions = 13; top = 65; banks = 7;
+//        width = 7; positions = 9; top = 63; banks = 9;
+//        width = 8; positions = 8; top = 64; banks = 8;
+
+        /*
+         * Determine if B will get bigger during shifting
+         */
+        int shifts = top < 64 ? positions : positions - 1;
+        int bMax = (bDeg + shifts + 63) >>> 6;
+
+        int bTotal = bMax * banks, stride = width * banks;
+
+        /*
+         * Create a single temporary buffer, with an offset table to find the positions of things in it 
+         */
+        int[] ci = new int[1 << width];
+        int cTotal = aLen;
+        {
+            ci[0] = cTotal;
+            cTotal += bTotal;
+            ci[1] = cTotal;
+            for (int i = 2; i < ci.length; ++i)
+            {
+                cTotal += cLen;
+                ci[i] = cTotal;
+            }
+            cTotal += cLen;
+        }
+        // NOTE: Provide a safe dump for "high zeroes" since we are adding 'bMax' and not 'bLen'
+        ++cTotal;
+
+        long[] c = new long[cTotal];
+
+        // Prepare A in interleaved form, according to the chosen width
+        interleave(A.m_ints, 0, c, 0, aLen, width);
+
+        // Make a working copy of B, since we will be shifting it
+        {
+            int bOff = aLen;
+            System.arraycopy(B.m_ints, 0, c, bOff, bLen);
+            for (int bank = 1; bank < banks; ++bank)
+            {
+                shiftUp(c, aLen, c, bOff += bMax, bMax, bank);
+            }
+        }
+
+        /*
+         * The main loop analyzes the interleaved windows in A, and for each non-zero window
+         * a single word-array XOR is performed to a carefully selected slice of 'c'. The loop is
+         * breadth-first, checking the lowest window in each word, then looping again for the
+         * next higher window position.
+         */
+        int MASK = (1 << width) - 1;
+
+        int k = 0;
+        for (;;)
+        {
+            int aPos = 0;
+            do
+            {
+                long aVal = c[aPos] >>> k;
+                int bank = 0, bOff = aLen;
+                for (;;)
+                {
+                    int index = (int)(aVal) & MASK;
+                    if (index != 0)
+                    {
+                        /*
+                         * Add to a 'c' buffer based on the bit-pattern of 'index'. Since A is in
+                         * interleaved form, the bits represent the current B shifted by 0, 'positions',
+                         * 'positions' * 2, ..., 'positions' * ('width' - 1)
+                         */
+                        add(c, aPos + ci[index], c, bOff, bMax);
+                    }
+                    if (++bank == banks)
+                    {
+                        break;
+                    }
+                    bOff += bMax;
+                    aVal >>>= width;
+                }
+            }
+            while (++aPos < aLen);
+
+            if ((k += stride) >= top)
+            {
+                if (k >= 64)
+                {
+                    break;
+                }
+
+                /*
+                 * Adjustment for window setups with top == 63, the final bit (if any) is processed
+                 * as the top-bit of a window
+                 */
+                k = 64 - width;
+                MASK &= MASK << (top - k);
+            }
+
+            /*
+             * After each position has been checked for all words of A, B is shifted up 1 place
+             */
+            shiftUp(c, aLen, bTotal, banks);
+        }
+
+        int ciPos = ci.length;
+        while (--ciPos > 1)
+        {
+            if ((ciPos & 1L) == 0L)
+            {
+                /*
+                 * For even numbers, shift contents and add to the half-position
+                 */
+                addShiftedUp(c, ci[ciPos >>> 1], c, ci[ciPos], cLen, positions);
+            }
+            else
+            {
+                /*
+                 * For odd numbers, 'distribute' contents to the result and the next-lowest position
+                 */
+                distribute(c, ci[ciPos], ci[ciPos - 1], ci[1], cLen);
+            }
+        }
+
+        /*
+         * Finally the raw answer is collected, reduce it against the reduction coefficients
+         */
+        return reduceResult(c, ci[1], cLen, m, ks);
+    }
+
+    private static LongArray reduceResult(long[] buf, int off, int len, int m, int[] ks)
+    {
+        int rLen = reduceInPlace(buf, off, len, m, ks);
+        return new LongArray(buf, off, rLen);
+    }
+
+//    private static void deInterleave(long[] x, int xOff, long[] z, int zOff, int count, int rounds)
+//    {
+//        for (int i = 0; i < count; ++i)
+//        {
+//            z[zOff + i] = deInterleave(x[zOff + i], rounds);
+//        }
+//    }
+//
+//    private static long deInterleave(long x, int rounds)
+//    {
+//        while (--rounds >= 0)
+//        {
+//            x = deInterleave32(x & DEINTERLEAVE_MASK) | (deInterleave32((x >>> 1) & DEINTERLEAVE_MASK) << 32);
+//        }
+//        return x;
+//    }
+//
+//    private static long deInterleave32(long x)
+//    {
+//        x = (x | (x >>> 1)) & 0x3333333333333333L;
+//        x = (x | (x >>> 2)) & 0x0F0F0F0F0F0F0F0FL;
+//        x = (x | (x >>> 4)) & 0x00FF00FF00FF00FFL;
+//        x = (x | (x >>> 8)) & 0x0000FFFF0000FFFFL;
+//        x = (x | (x >>> 16)) & 0x00000000FFFFFFFFL;
+//        return x;
+//    }
+
+    private static int reduceInPlace(long[] buf, int off, int len, int m, int[] ks)
+    {
+        int mLen = (m + 63) >>> 6;
+        if (len < mLen)
+        {
+            return len;
+        }
+
+        int numBits = Math.min(len << 6, (m << 1) - 1); // TODO use actual degree?
+        int excessBits = (len << 6) - numBits;
+        while (excessBits >= 64)
+        {
+            --len;
+            excessBits -= 64;
+        }
+
+        int kLen = ks.length, kMax = ks[kLen - 1], kNext = kLen > 1 ? ks[kLen - 2] : 0;
+        int wordWiseLimit = Math.max(m, kMax + 64);
+        int vectorableWords = (excessBits + Math.min(numBits - wordWiseLimit, m - kNext)) >> 6;
+        if (vectorableWords > 1)
+        {
+            int vectorWiseWords = len - vectorableWords;
+            reduceVectorWise(buf, off, len, vectorWiseWords, m, ks);
+            while (len > vectorWiseWords)
+            {
+                buf[off + --len] = 0L;
+            }
+            numBits = vectorWiseWords << 6;
+        }
+
+        if (numBits > wordWiseLimit)
+        {
+            reduceWordWise(buf, off, len, wordWiseLimit, m, ks);
+            numBits = wordWiseLimit;
+        }
+
+        if (numBits > m)
+        {
+            reduceBitWise(buf, off, numBits, m, ks);
+        }
+
+        return mLen;
+    }
+
+    private static void reduceBitWise(long[] buf, int off, int bitlength, int m, int[] ks)
+    {
+        while (--bitlength >= m)
+        {
+            if (testBit(buf, off, bitlength))
+            {
+                reduceBit(buf, off, bitlength, m, ks);
+            }
+        }
+    }
+
+    private static void reduceBit(long[] buf, int off, int bit, int m, int[] ks)
+    {
+        flipBit(buf, off, bit);
+        int base = bit - m;
+        int j = ks.length;
+        while (--j >= 0)
+        {
+            flipBit(buf, off, ks[j] + base);
+        }
+        flipBit(buf, off, base);
+    }
+
+    private static void reduceWordWise(long[] buf, int off, int len, int toBit, int m, int[] ks)
+    {
+        int toPos = toBit >>> 6;
+
+        while (--len > toPos)
+        {
+            long word = buf[off + len];
+            if (word != 0)
+            {
+                buf[off + len] = 0;
+                reduceWord(buf, off, (len << 6), word, m, ks);
+            }
+        }
+
+        int partial = toBit & 0x3F;
+        long word = buf[off + toPos] >>> partial;
+        if (word != 0)
+        {
+            buf[off + toPos] ^= word << partial;
+            reduceWord(buf, off, toBit, word, m, ks);
+        }
+    }
+
+    private static void reduceWord(long[] buf, int off, int bit, long word, int m, int[] ks)
+    {
+        int offset = bit - m;
+        int j = ks.length;
+        while (--j >= 0)
+        {
+            flipWord(buf, off, offset + ks[j], word);
+        }
+        flipWord(buf, off, offset, word);
+    }
+
+    private static void reduceVectorWise(long[] buf, int off, int len, int words, int m, int[] ks)
+    {
+        /*
+         * NOTE: It's important we go from highest coefficient to lowest, because for the highest
+         * one (only) we allow the ranges to partially overlap, and therefore any changes must take
+         * effect for the subsequent lower coefficients.
+         */
+        int baseBit = (words << 6) - m;
+        int j = ks.length;
+        while (--j >= 0)
+        {
+            flipVector(buf, off, buf, off + words, len - words, baseBit + ks[j]);
+        }
+        flipVector(buf, off, buf, off + words, len - words, baseBit);
+    }
+
+    private static void flipVector(long[] x, int xOff, long[] y, int yOff, int yLen, int bits)
+    {
+        xOff += bits >>> 6;
+        bits &= 0x3F;
+
+        if (bits == 0)
+        {
+            add(x, xOff, y, yOff, yLen);
+        }
+        else
+        {
+            long carry = addShiftedDown(x, xOff + 1, y, yOff, yLen, 64 - bits);
+            x[xOff] ^= carry;
+        }
+    }
+
+    public LongArray modSquare(int m, int[] ks)
+    {
+        int len = getUsedLength();
+        if (len == 0)
+        {
+            return this;
+        }
+
+        int _2len = len << 1;
+        long[] r = new long[_2len];
+
+        int pos = 0;
+        while (pos < _2len)
+        {
+            long mi = m_ints[pos >>> 1];
+            r[pos++] = interleave2_32to64((int)mi);
+            r[pos++] = interleave2_32to64((int)(mi >>> 32));
+        }
+
+        return new LongArray(r, 0, reduceInPlace(r, 0, r.length, m, ks));
+    }
+
+//    private LongArray modSquareN(int n, int m, int[] ks)
+//    {
+//        int len = getUsedLength();
+//        if (len == 0)
+//        {
+//            return this;
+//        }
+//
+//        int mLen = (m + 63) >>> 6;
+//        long[] r = new long[mLen << 1];
+//        System.arraycopy(m_ints, 0, r, 0, len);
+//
+//        while (--n >= 0)
+//        {
+//            squareInPlace(r, len, m, ks);
+//            len = reduceInPlace(r, 0, r.length, m, ks);
+//        }
+//
+//        return new LongArray(r, 0, len);
+//    }
+//
+//    private static void squareInPlace(long[] x, int xLen, int m, int[] ks)
+//    {
+//        int pos = xLen << 1;
+//        while (--xLen >= 0)
+//        {
+//            long xVal = x[xLen];
+//            x[--pos] = interleave2_32to64((int)(xVal >>> 32));
+//            x[--pos] = interleave2_32to64((int)xVal);
+//        }
+//    }
+
+    private static void interleave(long[] x, int xOff, long[] z, int zOff, int count, int width)
+    {
+        switch (width)
+        {
+        case 3:
+            interleave3(x, xOff, z, zOff, count);
+            break;
+        case 5:
+            interleave5(x, xOff, z, zOff, count);
+            break;
+        case 7:
+            interleave7(x, xOff, z, zOff, count);
+            break;
+        default:
+            interleave2_n(x, xOff, z, zOff, count, bitLengths[width] - 1);
+            break;
+        }
+    }
+
+    private static void interleave3(long[] x, int xOff, long[] z, int zOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            z[zOff + i] = interleave3(x[xOff + i]);
+        }
+    }
+
+    private static long interleave3(long x)
+    {
+        long z = x & (1L << 63);
+        return z
+            | interleave3_21to63((int)x & 0x1FFFFF)
+            | interleave3_21to63((int)(x >>> 21) & 0x1FFFFF) << 1
+            | interleave3_21to63((int)(x >>> 42) & 0x1FFFFF) << 2;
+
+//        int zPos = 0, wPos = 0, xPos = 0;
+//        for (;;)
+//        {
+//            z |= ((x >>> xPos) & 1L) << zPos;
+//            if (++zPos == 63)
+//            {
+//                String sz2 = Long.toBinaryString(z);
+//                return z;
+//            }
+//            if ((xPos += 21) >= 63)
+//            {
+//                xPos = ++wPos;
+//            }
+//        }
+    }
+
+    private static long interleave3_21to63(int x)
+    {
+        int r00 = INTERLEAVE3_TABLE[x & 0x7F];
+        int r21 = INTERLEAVE3_TABLE[(x >>> 7) & 0x7F];
+        int r42 = INTERLEAVE3_TABLE[x >>> 14];
+        return (r42 & 0xFFFFFFFFL) << 42 | (r21 & 0xFFFFFFFFL) << 21 | (r00 & 0xFFFFFFFFL);
+    }
+
+    private static void interleave5(long[] x, int xOff, long[] z, int zOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            z[zOff + i] = interleave5(x[xOff + i]);
+        }
+    }
+
+    private static long interleave5(long x)
+    {
+        return interleave3_13to65((int)x & 0x1FFF)
+            | interleave3_13to65((int)(x >>> 13) & 0x1FFF) << 1
+            | interleave3_13to65((int)(x >>> 26) & 0x1FFF) << 2
+            | interleave3_13to65((int)(x >>> 39) & 0x1FFF) << 3
+            | interleave3_13to65((int)(x >>> 52) & 0x1FFF) << 4;
+
+//        long z = 0;
+//        int zPos = 0, wPos = 0, xPos = 0;
+//        for (;;)
+//        {
+//            z |= ((x >>> xPos) & 1L) << zPos;
+//            if (++zPos == 64)
+//            {
+//                return z;
+//            }
+//            if ((xPos += 13) >= 64)
+//            {
+//                xPos = ++wPos;
+//            }
+//        }
+    }
+
+    private static long interleave3_13to65(int x)
+    {
+        int r00 = INTERLEAVE5_TABLE[x & 0x7F];
+        int r35 = INTERLEAVE5_TABLE[x >>> 7];
+        return (r35 & 0xFFFFFFFFL) << 35 | (r00 & 0xFFFFFFFFL);
+    }
+
+    private static void interleave7(long[] x, int xOff, long[] z, int zOff, int count)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            z[zOff + i] = interleave7(x[xOff + i]);
+        }
+    }
+
+    private static long interleave7(long x)
+    {
+        long z = x & (1L << 63);
+        return z
+            | INTERLEAVE7_TABLE[(int)x & 0x1FF]
+            | INTERLEAVE7_TABLE[(int)(x >>> 9) & 0x1FF] << 1
+            | INTERLEAVE7_TABLE[(int)(x >>> 18) & 0x1FF] << 2
+            | INTERLEAVE7_TABLE[(int)(x >>> 27) & 0x1FF] << 3
+            | INTERLEAVE7_TABLE[(int)(x >>> 36) & 0x1FF] << 4
+            | INTERLEAVE7_TABLE[(int)(x >>> 45) & 0x1FF] << 5
+            | INTERLEAVE7_TABLE[(int)(x >>> 54) & 0x1FF] << 6;
+
+//        int zPos = 0, wPos = 0, xPos = 0;
+//        for (;;)
+//        {
+//            z |= ((x >>> xPos) & 1L) << zPos;
+//            if (++zPos == 63)
+//            {
+//                return z;
+//            }
+//            if ((xPos += 9) >= 63)
+//            {
+//                xPos = ++wPos;
+//            }
+//        }
+    }
+
+    private static void interleave2_n(long[] x, int xOff, long[] z, int zOff, int count, int rounds)
+    {
+        for (int i = 0; i < count; ++i)
+        {
+            z[zOff + i] = interleave2_n(x[xOff + i], rounds);
+        }
+    }
+
+    private static long interleave2_n(long x, int rounds)
+    {
+        while (rounds > 1)
+        {
+            rounds -= 2;
+            x = interleave4_16to64((int)x & 0xFFFF)
+                | interleave4_16to64((int)(x >>> 16) & 0xFFFF) << 1
+                | interleave4_16to64((int)(x >>> 32) & 0xFFFF) << 2
+                | interleave4_16to64((int)(x >>> 48) & 0xFFFF) << 3;
+        }
+        if (rounds > 0)
+        {
+            x = interleave2_32to64((int)x) | interleave2_32to64((int)(x >>> 32)) << 1;
+        }
+        return x;
+    }
+
+    private static long interleave4_16to64(int x)
+    {
+        int r00 = INTERLEAVE4_TABLE[x & 0xFF];
+        int r32 = INTERLEAVE4_TABLE[x >>> 8];
+        return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL);
+    }
+
+    private static long interleave2_32to64(int x)
+    {
+        int r00 = INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >>> 8) & 0xFF] << 16;
+        int r32 = INTERLEAVE2_TABLE[(x >>> 16) & 0xFF] | INTERLEAVE2_TABLE[x >>> 24] << 16;
+        return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL);
+    }
+
+//    private static LongArray expItohTsujii2(LongArray B, int n, int m, int[] ks)
+//    {
+//        LongArray t1 = B, t3 = new LongArray(new long[]{ 1L });
+//        int scale = 1;
+//
+//        int numTerms = n;
+//        while (numTerms > 1)
+//        {
+//            if ((numTerms & 1) != 0)
+//            {
+//                t3 = t3.modMultiply(t1, m, ks);
+//                t1 = t1.modSquareN(scale, m, ks);
+//            }
+//
+//            LongArray t2 = t1.modSquareN(scale, m, ks);
+//            t1 = t1.modMultiply(t2, m, ks);
+//            numTerms >>>= 1; scale <<= 1;
+//        }
+//
+//        return t3.modMultiply(t1, m, ks);
+//    }
+//
+//    private static LongArray expItohTsujii23(LongArray B, int n, int m, int[] ks)
+//    {
+//        LongArray t1 = B, t3 = new LongArray(new long[]{ 1L });
+//        int scale = 1;
+//
+//        int numTerms = n;
+//        while (numTerms > 1)
+//        {
+//            boolean m03 = numTerms % 3 == 0;
+//            boolean m14 = !m03 && (numTerms & 1) != 0;
+//
+//            if (m14)
+//            {
+//                t3 = t3.modMultiply(t1, m, ks);
+//                t1 = t1.modSquareN(scale, m, ks);
+//            }
+//
+//            LongArray t2 = t1.modSquareN(scale, m, ks);
+//            t1 = t1.modMultiply(t2, m, ks);
+//
+//            if (m03)
+//            {
+//                t2 = t2.modSquareN(scale, m, ks);
+//                t1 = t1.modMultiply(t2, m, ks);
+//                numTerms /= 3; scale *= 3;
+//            }
+//            else
+//            {
+//                numTerms >>>= 1; scale <<= 1;
+//            }
+//        }
+//
+//        return t3.modMultiply(t1, m, ks);
+//    }
+//
+//    private static LongArray expItohTsujii235(LongArray B, int n, int m, int[] ks)
+//    {
+//        LongArray t1 = B, t4 = new LongArray(new long[]{ 1L });
+//        int scale = 1;
+//
+//        int numTerms = n;
+//        while (numTerms > 1)
+//        {
+//            if (numTerms % 5 == 0)
+//            {
+////                t1 = expItohTsujii23(t1, 5, m, ks);
+//
+//                LongArray t3 = t1;
+//                t1 = t1.modSquareN(scale, m, ks);
+//
+//                LongArray t2 = t1.modSquareN(scale, m, ks);
+//                t1 = t1.modMultiply(t2, m, ks);
+//                t2 = t1.modSquareN(scale << 1, m, ks);
+//                t1 = t1.modMultiply(t2, m, ks);
+//
+//                t1 = t1.modMultiply(t3, m, ks);
+//
+//                numTerms /= 5; scale *= 5;
+//                continue;
+//            }
+//
+//            boolean m03 = numTerms % 3 == 0;
+//            boolean m14 = !m03 && (numTerms & 1) != 0;
+//
+//            if (m14)
+//            {
+//                t4 = t4.modMultiply(t1, m, ks);
+//                t1 = t1.modSquareN(scale, m, ks);
+//            }
+//
+//            LongArray t2 = t1.modSquareN(scale, m, ks);
+//            t1 = t1.modMultiply(t2, m, ks);
+//
+//            if (m03)
+//            {
+//                t2 = t2.modSquareN(scale, m, ks);
+//                t1 = t1.modMultiply(t2, m, ks);
+//                numTerms /= 3; scale *= 3;
+//            }
+//            else
+//            {
+//                numTerms >>>= 1; scale <<= 1;
+//            }
+//        }
+//
+//        return t4.modMultiply(t1, m, ks);
+//    }
+
+    public LongArray modInverse(int m, int[] ks)
+    {
+        /*
+         * Fermat's Little Theorem
+         */
+//        LongArray A = this;
+//        LongArray B = A.modSquare(m, ks);
+//        LongArray R0 = B, R1 = B;
+//        for (int i = 2; i < m; ++i)
+//        {
+//            R1 = R1.modSquare(m, ks);
+//            R0 = R0.modMultiply(R1, m, ks);
+//        }
+//
+//        return R0;
+
+        /*
+         * Itoh-Tsujii
+         */
+//        LongArray B = modSquare(m, ks);
+//        switch (m)
+//        {
+//        case 409:
+//            return expItohTsujii23(B, m - 1, m, ks);
+//        case 571:
+//            return expItohTsujii235(B, m - 1, m, ks);
+//        case 163:
+//        case 233:
+//        case 283:
+//        default:
+//            return expItohTsujii2(B, m - 1, m, ks);
+//        }
+
+        /*
+         * Inversion in F2m using the extended Euclidean algorithm
+         * 
+         * Input: A nonzero polynomial a(z) of degree at most m-1
+         * Output: a(z)^(-1) mod f(z)
+         */
+        int uzDegree = degree();
+        if (uzDegree == 1)
+        {
+            return this;
+        }
+
+        // u(z) := a(z)
+        LongArray uz = (LongArray)clone();
+
+        int t = (m + 63) >>> 6;
+
+        // v(z) := f(z)
+        LongArray vz = new LongArray(t);
+        reduceBit(vz.m_ints, 0, m, m, ks);
+
+        // g1(z) := 1, g2(z) := 0
+        LongArray g1z = new LongArray(t);
+        g1z.m_ints[0] = 1L;
+        LongArray g2z = new LongArray(t);
+
+        int[] uvDeg = new int[]{ uzDegree, m + 1 };
+        LongArray[] uv = new LongArray[]{ uz, vz };
+
+        int[] ggDeg = new int[]{ 1, 0 };
+        LongArray[] gg = new LongArray[]{ g1z, g2z };
+
+        int b = 1;
+        int duv1 = uvDeg[b];
+        int dgg1 = ggDeg[b];
+        int j = duv1 - uvDeg[1 - b];
+
+        for (;;)
+        {
+            if (j < 0)
+            {
+                j = -j;
+                uvDeg[b] = duv1;
+                ggDeg[b] = dgg1;
+                b = 1 - b;
+                duv1 = uvDeg[b];
+                dgg1 = ggDeg[b];
+            }
+
+            uv[b].addShiftedByBitsSafe(uv[1 - b], uvDeg[1 - b], j);
+
+            int duv2 = uv[b].degreeFrom(duv1);
+            if (duv2 == 0)
+            {
+                return gg[1 - b];
+            }
+
+            {
+                int dgg2 = ggDeg[1 - b];
+                gg[b].addShiftedByBitsSafe(gg[1 - b], dgg2, j);
+                dgg2 += j;
+
+                if (dgg2 > dgg1)
+                {
+                    dgg1 = dgg2;
+                }
+                else if (dgg2 == dgg1)
+                {
+                    dgg1 = gg[b].degreeFrom(dgg1);
+                }
+            }
+
+            j += (duv2 - duv1);
+            duv1 = duv2;
+        }
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof LongArray))
+        {
+            return false;
+        }
+        LongArray other = (LongArray) o;
+        int usedLen = getUsedLength();
+        if (other.getUsedLength() != usedLen)
+        {
+            return false;
+        }
+        for (int i = 0; i < usedLen; i++)
+        {
+            if (m_ints[i] != other.m_ints[i])
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public int hashCode()
+    {
+        int usedLen = getUsedLength();
+        int hash = 1;
+        for (int i = 0; i < usedLen; i++)
+        {
+            long mi = m_ints[i];
+            hash *= 31;
+            hash ^= (int)mi;
+            hash *= 31;
+            hash ^= (int)(mi >>> 32);
+        }
+        return hash;
+    }
+
+    public Object clone()
+    {
+        return new LongArray(Arrays.clone(m_ints));
+    }
+
+    public String toString()
+    {
+        int i = getUsedLength();
+        if (i == 0)
+        {
+            return "0";
+        }
+
+        StringBuffer sb = new StringBuffer(Long.toBinaryString(m_ints[--i]));
+        while (--i >= 0)
+        {
+            String s = Long.toBinaryString(m_ints[i]);
+
+            // Add leading zeroes, except for highest significant word
+            int len = s.length();
+            if (len < 64)
+            {
+                sb.append(ZEROES.substring(len));
+            }
+
+            sb.append(s);
+        }
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java b/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java
index 804dcf7..3849858 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java
@@ -2,9 +2,9 @@
 
 /**
  * Interface for classes storing precomputation data for multiplication
- * algorithms. Used as a Memento (see GOF patterns) for
- * <code>WNafMultiplier</code>.
+ * algorithms. Used as a Memento (see GOF patterns) by e.g. 
+ * <code>WNafL2RMultiplier</code>.
  */
-interface PreCompInfo
+public interface PreCompInfo
 {
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java b/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java
index af4355f..42d6738 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java
@@ -392,15 +392,7 @@
      */
     public static ECPoint.F2m tau(ECPoint.F2m p)
     {
-        if (p.isInfinity())
-        {
-            return p;
-        }
-
-        ECFieldElement x = p.getX();
-        ECFieldElement y = p.getY();
-
-        return new ECPoint.F2m(p.getCurve(), x.square(), y.square(), p.isCompressed());
+        return p.tau();
     }
 
     /**
@@ -415,23 +407,17 @@
      */
     public static byte getMu(ECCurve.F2m curve)
     {
-        BigInteger a = curve.getA().toBigInteger();
-        byte mu;
+        if (!curve.isKoblitz())
+        {
+            throw new IllegalArgumentException("No Koblitz curve (ABC), TNAF multiplication not possible");
+        }
 
-        if (a.equals(ECConstants.ZERO))
+        if (curve.getA().isZero())
         {
-            mu = -1;
+            return -1;
         }
-        else if (a.equals(ECConstants.ONE))
-        {
-            mu = 1;
-        }
-        else
-        {
-            throw new IllegalArgumentException("No Koblitz curve (ABC), " +
-                    "TNAF multiplication not possible");
-        }
-        return mu;
+
+        return 1;
     }
 
     /**
@@ -838,7 +824,9 @@
         {
             pu[i] = Tnaf.multiplyFromTnaf(p, alphaTnaf[i]);
         }
-        
+
+        p.getCurve().normalizeAll(pu);
+
         return pu;
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafL2RMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafL2RMultiplier.java
new file mode 100644
index 0000000..59a9313
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafL2RMultiplier.java
@@ -0,0 +1,101 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the WNAF (Window Non-Adjacent Form) multiplication
+ * algorithm.
+ */
+public class WNafL2RMultiplier extends AbstractECMultiplier
+{
+    /**
+     * Multiplies <code>this</code> by an integer <code>k</code> using the
+     * Window NAF method.
+     * @param k The integer by which <code>this</code> is multiplied.
+     * @return A new <code>ECPoint</code> which equals <code>this</code>
+     * multiplied by <code>k</code>.
+     */
+    protected ECPoint multiplyPositive(ECPoint p, BigInteger k)
+    {
+        // Clamp the window width in the range [2, 16]
+        int width = Math.max(2, Math.min(16, getWindowSize(k.bitLength())));
+
+        WNafPreCompInfo wnafPreCompInfo = WNafUtil.precompute(p, width, true);
+        ECPoint[] preComp = wnafPreCompInfo.getPreComp();
+        ECPoint[] preCompNeg = wnafPreCompInfo.getPreCompNeg();
+
+        int[] wnaf = WNafUtil.generateCompactWindowNaf(width, k);
+
+        ECPoint R = p.getCurve().getInfinity();
+
+        int i = wnaf.length;
+
+        /*
+         * NOTE This code optimizes the first window using the precomputed points to substitute an
+         * addition for 2 or more doublings.
+         */
+        if (i > 1)
+        {
+            int wi = wnaf[--i];
+            int digit = wi >> 16, zeroes = wi & 0xFFFF;
+
+            int n = Math.abs(digit);
+            ECPoint[] table = digit < 0 ? preCompNeg : preComp;
+
+            /*
+             * NOTE: We use this optimization conservatively, since some coordinate systems have
+             * significantly cheaper doubling relative to addition.
+             * 
+             * (n << 2) selects precomputed values in the lower half of the table
+             * (n << 3) selects precomputed values in the lower quarter of the table
+             */
+            //if ((n << 2) < (1 << width))
+            if ((n << 3) < (1 << width))
+            {
+                int highest = LongArray.bitLengths[n];
+                int lowBits =  n ^ (1 << (highest - 1));
+                int scale = width - highest;
+
+                int i1 = ((1 << (width - 1)) - 1);
+                int i2 = (lowBits << scale) + 1;
+                R = table[i1 >>> 1].add(table[i2 >>> 1]);
+
+                zeroes -= scale;
+
+//              System.out.println("Optimized: 2^" + scale + " * " + n + " = " + i1 + " + " + i2);
+            }
+            else
+            {
+                R = table[n >>> 1];
+            }
+
+            R = R.timesPow2(zeroes);
+        }
+
+        while (i > 0)
+        {
+            int wi = wnaf[--i];
+            int digit = wi >> 16, zeroes = wi & 0xFFFF;
+
+            int n = Math.abs(digit);
+            ECPoint[] table = digit < 0 ? preCompNeg : preComp;
+            ECPoint r = table[n >>> 1];
+
+            R = R.twicePlus(r);
+            R = R.timesPow2(zeroes);
+        }
+
+        return R;
+    }
+
+    /**
+     * Determine window width to use for a scalar multiplication of the given size.
+     * 
+     * @param bits the bit-length of the scalar to multiply by
+     * @return the window size to use
+     */
+    protected int getWindowSize(int bits)
+    {
+        return WNafUtil.getWindowSize(bits);
+    }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java
deleted file mode 100644
index 10c8ed2..0000000
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java
+++ /dev/null
@@ -1,240 +0,0 @@
-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/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java
index fc0d5fe..d142ab7 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java
@@ -4,21 +4,23 @@
  * Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
  * algorithm.
  */
-class WNafPreCompInfo implements PreCompInfo
+public 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>.
+     * Array holding the precomputed <code>ECPoint</code>s used for a Window
+     * NAF multiplication.
      */
     private ECPoint[] preComp = null;
 
     /**
+     * Array holding the negations of the precomputed <code>ECPoint</code>s used
+     * for a Window NAF multiplication.
+     */
+    private ECPoint[] preCompNeg = 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>.
+     * Window NAF multiplication to create or extend the precomputed values.
      */
     private ECPoint twiceP = null;
 
@@ -27,18 +29,28 @@
         return preComp;
     }
 
+    protected ECPoint[] getPreCompNeg()
+    {
+        return preCompNeg;
+    }
+
     protected void setPreComp(ECPoint[] preComp)
     {
         this.preComp = preComp;
     }
 
+    protected void setPreCompNeg(ECPoint[] preCompNeg)
+    {
+        this.preCompNeg = preCompNeg;
+    }
+
     protected ECPoint getTwiceP()
     {
         return twiceP;
     }
 
-    protected void setTwiceP(ECPoint twiceThis)
+    protected void setTwiceP(ECPoint twiceP)
     {
-        this.twiceP = twiceThis;
+        this.twiceP = twiceP;
     }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java
new file mode 100644
index 0000000..6465d66
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java
@@ -0,0 +1,393 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+public abstract class WNafUtil
+{
+    private static int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 };
+
+    public static int[] generateCompactNaf(BigInteger k)
+    {
+        if ((k.bitLength() >>> 16) != 0)
+        {
+            throw new IllegalArgumentException("'k' must have bitlength < 2^16");
+        }
+
+        BigInteger _3k = k.shiftLeft(1).add(k);
+
+        int digits = _3k.bitLength() - 1;
+        int[] naf = new int[(digits + 1) >> 1];
+
+        int length = 0, zeroes = 0;
+        for (int i = 1; i <= digits; ++i)
+        {
+            boolean _3kBit = _3k.testBit(i);
+            boolean kBit = k.testBit(i);
+
+            if (_3kBit == kBit)
+            {
+                ++zeroes;
+            }
+            else
+            {
+                int digit  = kBit ? -1 : 1;
+                naf[length++] = (digit << 16) | zeroes;
+                zeroes = 0;
+            }
+        }
+
+        if (naf.length > length)
+        {
+            naf = trim(naf, length);
+        }
+
+        return naf;
+    }
+
+    public static int[] generateCompactWindowNaf(int width, BigInteger k)
+    {
+        if (width == 2)
+        {
+            return generateCompactNaf(k);
+        }
+
+        if (width < 2 || width > 16)
+        {
+            throw new IllegalArgumentException("'width' must be in the range [2, 16]");
+        }
+        if ((k.bitLength() >>> 16) != 0)
+        {
+            throw new IllegalArgumentException("'k' must have bitlength < 2^16");
+        }
+
+        int[] wnaf = new int[k.bitLength() / width + 1];
+
+        // 2^width and a mask and sign bit set accordingly
+        int pow2 = 1 << width;
+        int mask = pow2 - 1;
+        int sign = pow2 >>> 1;
+
+        boolean carry = false;
+        int length = 0, pos = 0;
+
+        while (pos <= k.bitLength())
+        {
+            if (k.testBit(pos) == carry)
+            {
+                ++pos;
+                continue;
+            }
+
+            k = k.shiftRight(pos);
+
+            int digit = k.intValue() & mask;
+            if (carry)
+            {
+                ++digit;
+            }
+
+            carry = (digit & sign) != 0;
+            if (carry)
+            {
+                digit -= pow2;
+            }
+
+            int zeroes = length > 0 ? pos - 1 : pos;
+            wnaf[length++] = (digit << 16) | zeroes;
+            pos = width;
+        }
+
+        // Reduce the WNAF array to its actual length
+        if (wnaf.length > length)
+        {
+            wnaf = trim(wnaf, length);
+        }
+
+        return wnaf;
+    }
+
+    public static byte[] generateJSF(BigInteger g, BigInteger h)
+    {
+        int digits = Math.max(g.bitLength(), h.bitLength()) + 1;
+        byte[] jsf = new byte[digits];
+
+        BigInteger k0 = g, k1 = h;
+        int j = 0, d0 = 0, d1 = 0;
+
+        while (k0.signum() > 0 || k1.signum() > 0 || d0 > 0 || d1 > 0)
+        {
+            int n0 = (k0.intValue() + d0) & 7, n1 = (k1.intValue() + d1) & 7;
+
+            int u0 = n0 & 1;
+            if (u0 != 0)
+            {
+                u0 -= (n0 & 2);
+                if ((n0 + u0) == 4 && (n1 & 3) == 2)
+                {
+                    u0 = -u0;
+                }
+            }
+
+            int u1 = n1 & 1;
+            if (u1 != 0)
+            {
+                u1 -= (n1 & 2);
+                if ((n1 + u1) == 4 && (n0 & 3) == 2)
+                {
+                    u1 = -u1;
+                }
+            }
+
+            if ((d0 << 1) == 1 + u0)
+            {
+                d0 = 1 - d0;
+            }
+            if ((d1 << 1) == 1 + u1)
+            {
+                d1 = 1 - d1;
+            }
+
+            k0 = k0.shiftRight(1);
+            k1 = k1.shiftRight(1);
+
+            jsf[j++] = (byte)((u0 << 4) | (u1 & 0xF));
+        }
+
+        // Reduce the JSF array to its actual length
+        if (jsf.length > j)
+        {
+            jsf = trim(jsf, j);
+        }
+
+        return jsf;
+    }
+
+    public static byte[] generateNaf(BigInteger k)
+    {
+        BigInteger _3k = k.shiftLeft(1).add(k);
+
+        int digits = _3k.bitLength() - 1;
+        byte[] naf = new byte[digits];
+
+        for (int i = 1; i <= digits; ++i)
+        {
+            boolean _3kBit = _3k.testBit(i);
+            boolean kBit = k.testBit(i);
+
+            naf[i - 1] = (byte)(_3kBit == kBit ? 0 : kBit ? -1 : 1);
+        }
+
+        return naf;
+    }
+
+    /**
+     * Computes the Window NAF (non-adjacent Form) of an integer.
+     * @param width The width <code>w</code> of the Window NAF. The width is
+     * defined as the minimal number <code>w</code>, such that for any
+     * <code>w</code> consecutive digits in the resulting representation, at
+     * most one is non-zero.
+     * @param k The integer of which the Window NAF is computed.
+     * @return The Window NAF of the given width, such that the following holds:
+     * <code>k = &sum;<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup>
+     * </code>, where the <code>k<sub>i</sub></code> denote the elements of the
+     * returned <code>byte[]</code>.
+     */
+    public static byte[] generateWindowNaf(int width, BigInteger k)
+    {
+        if (width == 2)
+        {
+            return generateNaf(k);
+        }
+
+        if (width < 2 || width > 8)
+        {
+            throw new IllegalArgumentException("'width' must be in the range [2, 8]");
+        }
+
+        byte[] wnaf = new byte[k.bitLength() + 1];
+
+        // 2^width and a mask and sign bit set accordingly
+        int pow2 = 1 << width;
+        int mask = pow2 - 1;
+        int sign = pow2 >>> 1;
+
+        boolean carry = false;
+        int length = 0, pos = 0;
+
+        while (pos <= k.bitLength())
+        {
+            if (k.testBit(pos) == carry)
+            {
+                ++pos;
+                continue;
+            }
+
+            k = k.shiftRight(pos);
+
+            int digit = k.intValue() & mask;
+            if (carry)
+            {
+                ++digit;
+            }
+
+            carry = (digit & sign) != 0;
+            if (carry)
+            {
+                digit -= pow2;
+            }
+
+            length += (length > 0) ? pos - 1 : pos;
+            wnaf[length++] = (byte)digit;
+            pos = width;
+        }
+
+        // Reduce the WNAF array to its actual length
+        if (wnaf.length > length)
+        {
+            wnaf = trim(wnaf, length);
+        }
+        
+        return wnaf;
+    }
+
+    public static WNafPreCompInfo getWNafPreCompInfo(PreCompInfo preCompInfo)
+    {
+        if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo))
+        {
+            return (WNafPreCompInfo)preCompInfo;
+        }
+
+        return new WNafPreCompInfo();
+    }
+
+    /**
+     * Determine window width to use for a scalar multiplication of the given size.
+     * 
+     * @param bits the bit-length of the scalar to multiply by
+     * @return the window size to use
+     */
+    public static int getWindowSize(int bits)
+    {
+        return getWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS);
+    }
+
+    /**
+     * Determine window width to use for a scalar multiplication of the given size.
+     * 
+     * @param bits the bit-length of the scalar to multiply by
+     * @param windowSizeCutoffs a monotonically increasing list of bit sizes at which to increment the window width
+     * @return the window size to use
+     */
+    public static int getWindowSize(int bits, int[] windowSizeCutoffs)
+    {
+        int w = 0;
+        for (; w < windowSizeCutoffs.length; ++w)
+        {
+            if (bits < windowSizeCutoffs[w])
+            {
+                break;
+            }
+        }
+        return w + 2;
+    }
+
+    public static WNafPreCompInfo precompute(ECPoint p, int width, boolean includeNegated)
+    {
+        ECCurve c = p.getCurve();
+        WNafPreCompInfo wnafPreCompInfo = getWNafPreCompInfo(c.getPreCompInfo(p));
+
+        ECPoint[] preComp = wnafPreCompInfo.getPreComp();
+        if (preComp == null)
+        {
+            preComp = new ECPoint[]{ p };
+        }
+
+        int preCompLen = preComp.length;
+        int reqPreCompLen = 1 << Math.max(0, width - 2);
+
+        if (preCompLen < reqPreCompLen)
+        {
+            ECPoint twiceP = wnafPreCompInfo.getTwiceP();
+            if (twiceP == null)
+            {
+                twiceP = preComp[0].twice().normalize();
+                wnafPreCompInfo.setTwiceP(twiceP);
+            }
+
+            preComp = resizeTable(preComp, reqPreCompLen);
+
+            /*
+             * TODO Okeya/Sakurai paper has precomputation trick and  "Montgomery's Trick" to speed this up.
+             * Also, co-Z arithmetic could avoid the subsequent normalization too.
+             */
+            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]);
+            }
+
+            /*
+             * Having oft-used operands in affine form makes operations faster.
+             */
+            c.normalizeAll(preComp);
+        }
+
+        wnafPreCompInfo.setPreComp(preComp);
+
+        if (includeNegated)
+        {
+            ECPoint[] preCompNeg = wnafPreCompInfo.getPreCompNeg();
+            
+            int pos;
+            if (preCompNeg == null)
+            {
+                pos = 0;
+                preCompNeg = new ECPoint[reqPreCompLen]; 
+            }
+            else
+            {
+                pos = preCompNeg.length;
+                if (pos < reqPreCompLen)
+                {
+                    preCompNeg = resizeTable(preCompNeg, reqPreCompLen);
+                }
+            }
+
+            while (pos < reqPreCompLen)
+            {
+                preCompNeg[pos] = preComp[pos].negate();
+                ++pos;
+            }
+
+            wnafPreCompInfo.setPreCompNeg(preCompNeg);
+        }
+
+        c.setPreCompInfo(p, wnafPreCompInfo);
+
+        return wnafPreCompInfo;
+    }
+
+    private static byte[] trim(byte[] a, int length)
+    {
+        byte[] result = new byte[length];
+        System.arraycopy(a, 0, result, 0, result.length);
+        return result;
+    }
+
+    private static int[] trim(int[] a, int length)
+    {
+        int[] result = new int[length];
+        System.arraycopy(a, 0, result, 0, result.length);
+        return result;
+    }
+
+    private static ECPoint[] resizeTable(ECPoint[] a, int length)
+    {
+        ECPoint[] result = new ECPoint[length];
+        System.arraycopy(a, 0, result, 0, a.length);
+        return result;
+    }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java
index 2353979..7bd30ec 100644
--- a/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java
@@ -6,7 +6,7 @@
  * Class implementing the WTNAF (Window
  * <code>&tau;</code>-adic Non-Adjacent Form) algorithm.
  */
-class WTauNafMultiplier implements ECMultiplier
+public class WTauNafMultiplier extends AbstractECMultiplier
 {
     /**
      * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
@@ -16,7 +16,7 @@
      * @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)
+    protected ECPoint multiplyPositive(ECPoint point, BigInteger k)
     {
         if (!(point instanceof ECPoint.F2m))
         {
@@ -25,8 +25,7 @@
         }
 
         ECPoint.F2m p = (ECPoint.F2m)point;
-
-        ECCurve.F2m curve = (ECCurve.F2m) p.getCurve();
+        ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
         int m = curve.getM();
         byte a = curve.getA().toBigInteger().byteValue();
         byte mu = curve.getMu();
@@ -34,7 +33,7 @@
 
         ZTauElement rho = Tnaf.partModReduction(k, m, a, s, mu, (byte)10);
 
-        return multiplyWTnaf(p, rho, preCompInfo, a, mu);
+        return multiplyWTnaf(p, rho, curve.getPreCompInfo(p), a, mu);
     }
 
     /**
@@ -88,7 +87,7 @@
         if ((preCompInfo == null) || !(preCompInfo instanceof WTauNafPreCompInfo))
         {
             pu = Tnaf.getPreComp(p, a);
-            p.setPreCompInfo(new WTauNafPreCompInfo(pu));
+            curve.setPreCompInfo(p, new WTauNafPreCompInfo(pu));
         }
         else
         {
diff --git a/bcprov/src/main/java/org/bouncycastle/util/Arrays.java b/bcprov/src/main/java/org/bouncycastle/util/Arrays.java
index 457320e..3f7677c 100644
--- a/bcprov/src/main/java/org/bouncycastle/util/Arrays.java
+++ b/bcprov/src/main/java/org/bouncycastle/util/Arrays.java
@@ -11,7 +11,7 @@
     {
         // static class, hide constructor
     }
-    
+
     public static boolean areEqual(
         boolean[]  a,
         boolean[]  b)
@@ -199,36 +199,62 @@
         return true;
     }
 
-    public static boolean areEqual(
-        BigInteger[]  a,
-        BigInteger[]  b)
+    public static boolean areEqual(Object[] a, Object[] b)
     {
         if (a == b)
         {
             return true;
         }
-
         if (a == null || b == null)
         {
             return false;
         }
-
         if (a.length != b.length)
         {
             return false;
         }
-
         for (int i = 0; i != a.length; i++)
         {
-            if (!a[i].equals(b[i]))
+            Object objA = a[i], objB = b[i];
+            if (objA == null)
+            {
+                if (objB != null)
+                {
+                    return false;
+                }
+            }
+            else if (!objA.equals(objB))
             {
                 return false;
             }
         }
-
         return true;
     }
 
+    public static boolean contains(short[] a, short n)
+    {
+        for (int i = 0; i < a.length; ++i)
+        {
+            if (a[i] == n)
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean contains(int[] a, int n)
+    {
+        for (int i = 0; i < a.length; ++i)
+        {
+            if (a[i] == n)
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public static void fill(
         byte[] array,
         byte value)
@@ -391,7 +417,7 @@
         return hc;
     }
 
-    public static int hashCode(BigInteger[] data)
+    public static int hashCode(Object[] data)
     {
         if (data == null)
         {
@@ -423,6 +449,20 @@
         return copy;
     }
 
+    public static byte[] clone(byte[] data, byte[] existing)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        if ((existing == null) || (existing.length != data.length))
+        {
+            return clone(data);
+        }
+        System.arraycopy(data, 0, existing, 0, existing.length);
+        return existing;
+    }
+
     public static byte[][] clone(byte[][] data)
     {
         if (data == null)
@@ -470,6 +510,33 @@
         return copy;
     }
 
+    public static long[] clone(long[] data)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        long[] copy = new long[data.length];
+        
+        System.arraycopy(data, 0, copy, 0, data.length);
+        
+        return copy;
+    }
+
+    public static long[] clone(long[] data, long[] existing)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+        if ((existing == null) || (existing.length != data.length))
+        {
+            return clone(data);
+        }
+        System.arraycopy(data, 0, existing, 0, existing.length);
+        return existing;
+    }
+
     public static short[] clone(short[] data)
     {
         if (data == null)
@@ -576,6 +643,17 @@
         return tmp;
     }
 
+    /**
+     * Make a copy of a range of bytes from the passed in data array. The range can
+     * extend beyond the end of the input array, in which case the return array will
+     * be padded with zeroes.
+     *
+     * @param data the array from which the data is to be copied.
+     * @param from the start index at which the copying should take place.
+     * @param to the final index of the range (exclusive).
+     *
+     * @return a new byte array containing the range given.
+     */
     public static byte[] copyOfRange(byte[] data, int from, int to)
     {
         int newLength = getLength(from, to);
@@ -660,6 +738,34 @@
         return newLength;
     }
 
+    public static byte[] append(byte[] a, byte b)
+    {
+        if (a == null)
+        {
+            return new byte[]{ b };
+        }
+
+        int length = a.length;
+        byte[] result = new byte[length + 1];
+        System.arraycopy(a, 0, result, 0, length);
+        result[length] = b;
+        return result;
+    }
+
+    public static int[] append(int[] a, int b)
+    {
+        if (a == null)
+        {
+            return new int[]{ b };
+        }
+
+        int length = a.length;
+        int[] result = new int[length + 1];
+        System.arraycopy(a, 0, result, 0, length);
+        result[length] = b;
+        return result;
+    }
+
     public static byte[] concatenate(byte[] a, byte[] b)
     {
         if (a != null && b != null)
@@ -733,4 +839,18 @@
             return concatenate(b, c, d);
         }
     }
+
+    public static byte[] prepend(byte[] a, byte b)
+    {
+        if (a == null)
+        {
+            return new byte[]{ b };
+        }
+
+        int length = a.length;
+        byte[] result = new byte[length + 1];
+        System.arraycopy(a, 0, result, 1, length);
+        result[0] = b;
+        return result;
+    }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java b/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java
index e2fe590..f7f7e68 100644
--- a/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java
+++ b/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java
@@ -40,43 +40,25 @@
      * @param value value to be converted.
      * @return a byte array without a leading zero byte if present in the signed encoding.
      */
-    public static byte[] asUnsignedByteArray(
-        int        length,
-        BigInteger value)
+    public static byte[] asUnsignedByteArray(int length, BigInteger value)
     {
         byte[] bytes = value.toByteArray();
-
-        if (bytes[0] == 0)
+        if (bytes.length == length)
         {
-            if (bytes.length - 1 > length)
-            {
-                throw new IllegalArgumentException("standard length exceeded for value");
-            }
-
-            byte[] tmp = new byte[length];
-
-            System.arraycopy(bytes, 1, tmp, tmp.length - (bytes.length - 1), bytes.length - 1);
-
-            return tmp;
+            return bytes;
         }
-        else
+
+        int start = bytes[0] == 0 ? 1 : 0;
+        int count = bytes.length - start;
+
+        if (count > length)
         {
-            if (bytes.length == length)
-            {
-                return bytes;
-            }
-
-            if (bytes.length > length)
-            {
-                throw new IllegalArgumentException("standard length exceeded for value");
-            }
-
-            byte[] tmp = new byte[length];
-
-            System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length);
-
-            return tmp;
+            throw new IllegalArgumentException("standard length exceeded for value");
         }
+
+        byte[] tmp = new byte[length];
+        System.arraycopy(bytes, start, tmp, tmp.length - count, count);
+        return tmp;
     }
 
     /**
@@ -120,4 +102,20 @@
         // fall back to a faster (restricted) method
         return new BigInteger(max.subtract(min).bitLength() - 1, random).add(min);
     }
+
+    public static BigInteger fromUnsignedByteArray(byte[] buf)
+    {
+        return new BigInteger(1, buf);
+    }
+
+    public static BigInteger fromUnsignedByteArray(byte[] buf, int off, int length)
+    {
+        byte[] mag = buf;
+        if (off != 0 || length != buf.length)
+        {
+            mag = new byte[length];
+            System.arraycopy(buf, off, mag, 0, length);
+        }
+        return new BigInteger(1, mag);
+    }
 }
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509Store.java b/bcprov/src/main/java/org/bouncycastle/x509/X509Store.java
deleted file mode 100644
index 1bfc00f..0000000
--- a/bcprov/src/main/java/org/bouncycastle/x509/X509Store.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.bouncycastle.x509;
-
-import org.bouncycastle.util.Selector;
-import org.bouncycastle.util.Store;
-
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.Provider;
-import java.util.Collection;
-
-public class X509Store
-    implements Store
-{
-    public static X509Store getInstance(String type, X509StoreParameters parameters)
-        throws NoSuchStoreException
-    {
-        try
-        {
-            X509Util.Implementation impl = X509Util.getImplementation("X509Store", type);
-
-            return createStore(impl, parameters);
-        }
-        catch (NoSuchAlgorithmException e)
-        {
-            throw new NoSuchStoreException(e.getMessage());
-        }
-    }
-
-    public static X509Store getInstance(String type, X509StoreParameters parameters, String provider)
-        throws NoSuchStoreException, NoSuchProviderException
-    {
-        return getInstance(type, parameters, X509Util.getProvider(provider));
-    }
-
-    public static X509Store getInstance(String type, X509StoreParameters parameters, Provider provider)
-        throws NoSuchStoreException
-    {
-        try
-        {
-            X509Util.Implementation impl = X509Util.getImplementation("X509Store", type, provider);
-
-            return createStore(impl, parameters);
-        }
-        catch (NoSuchAlgorithmException e)
-        {
-            throw new NoSuchStoreException(e.getMessage());
-        }
-    }
-
-    private static X509Store createStore(X509Util.Implementation impl, X509StoreParameters parameters)
-    {
-        X509StoreSpi spi = (X509StoreSpi)impl.getEngine();
-
-        spi.engineInit(parameters);
-
-        return new X509Store(impl.getProvider(), spi);
-    }
-
-    private Provider     _provider;
-    private X509StoreSpi _spi;
-
-    private X509Store(
-        Provider provider,
-        X509StoreSpi spi)
-    {
-        _provider = provider;
-        _spi = spi;
-    }
-
-    public Provider getProvider()
-    {
-       return _provider;
-    }
-
-    public Collection getMatches(Selector selector)
-    {
-        return _spi.engineGetMatches(selector);
-    }
-}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509Util.java b/bcprov/src/main/java/org/bouncycastle/x509/X509Util.java
index 53b21af..7cf2e9d 100644
--- a/bcprov/src/main/java/org/bouncycastle/x509/X509Util.java
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509Util.java
@@ -56,10 +56,8 @@
         algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
         algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
         algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-        // algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-        // END android-removed
+        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
         algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
         algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
         algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
@@ -67,9 +65,7 @@
         algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
         algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
         algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
-        // END android-removed
+        algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
         algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
         algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
         algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
@@ -83,17 +79,13 @@
         // END android-removed
         algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
         algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
-        // END android-removed
+        algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
         algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
         algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
         algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
         algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
         algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
-        // BEGIN android-removed
-        // algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
-        // END android-removed
+        algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
         algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
         algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
         algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
@@ -110,16 +102,12 @@
         // The parameters field SHALL be NULL for RSA based signature algorithms.
         //
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
-        // BEGIN android-removed
-        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
-        // END android-removed
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
         noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
-        // BEGIN android-removed
-        // noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
-        // END android-removed
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
         noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
         noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
         noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
@@ -138,10 +126,8 @@
         AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
         params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
 
-        // BEGIN android-removed
-        // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
-        // params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
-        // END android-removed
+        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+        params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
 
         AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
         params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
diff --git a/bouncycastle.config b/bouncycastle.config
index 338b572..51521c8 100644
--- a/bouncycastle.config
+++ b/bouncycastle.config
@@ -1,5 +1,6 @@
 # directories
 UNNEEDED_BCPROV_SOURCES=" \
+org/bouncycastle/apache \
 org/bouncycastle/asn1/cmp \
 org/bouncycastle/asn1/cms/ecc \
 org/bouncycastle/asn1/crmf \
@@ -16,8 +17,8 @@
 org/bouncycastle/asn1/tsp \
 org/bouncycastle/asn1/x509/qualified \
 org/bouncycastle/asn1/x509/sigi \
-org/bouncycastle/crypto/agreement/kdf \
 org/bouncycastle/crypto/agreement/jpake \
+org/bouncycastle/crypto/agreement/kdf \
 org/bouncycastle/crypto/agreement/srp \
 org/bouncycastle/crypto/commitments \
 org/bouncycastle/crypto/ec \
@@ -26,9 +27,10 @@
 org/bouncycastle/crypto/prng \
 org/bouncycastle/crypto/tls/ \
 org/bouncycastle/i18n/ \
+org/bouncycastle/jcajce/io \
+org/bouncycastle/jcajce/provider/asymmetric/dstu \
 org/bouncycastle/jcajce/provider/asymmetric/ecgost \
 org/bouncycastle/jcajce/provider/asymmetric/elgamal \
-org/bouncycastle/jcajce/provider/asymmetric/dstu \
 org/bouncycastle/jcajce/provider/asymmetric/gost \
 org/bouncycastle/jcajce/provider/asymmetric/ies \
 org/bouncycastle/jce/examples \
@@ -50,6 +52,7 @@
 org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java \
 org/bouncycastle/asn1/cms/AuthenticatedData.java \
 org/bouncycastle/asn1/cms/AuthenticatedDataParser.java \
+org/bouncycastle/asn1/cms/CCMParameters.java \
 org/bouncycastle/asn1/cms/CompressedData.java \
 org/bouncycastle/asn1/cms/CompressedDataParser.java \
 org/bouncycastle/asn1/cms/ContentInfoParser.java \
@@ -83,7 +86,6 @@
 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/eac/BidirectionalMap.java \
 org/bouncycastle/asn1/eac/CVCertificate.java \
 org/bouncycastle/asn1/eac/CVCertificateRequest.java \
@@ -111,18 +113,11 @@
 org/bouncycastle/asn1/isismtt/x509/Restriction.java \
 org/bouncycastle/asn1/misc/CAST5CBCParameters.java \
 org/bouncycastle/asn1/misc/IDEACBCPar.java \
-org/bouncycastle/asn1/misc/package.html \
-org/bouncycastle/asn1/nist/package.html \
 org/bouncycastle/asn1/oiw/ElGamalParameter.java \
-org/bouncycastle/asn1/oiw/package.html \
-org/bouncycastle/asn1/package.html \
 org/bouncycastle/asn1/pkcs/Attribute.java \
 org/bouncycastle/asn1/pkcs/RC2CBCParameter.java \
 org/bouncycastle/asn1/pkcs/SignerInfo.java \
-org/bouncycastle/asn1/pkcs/package.html \
-org/bouncycastle/asn1/sec/package.html \
 org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java \
-org/bouncycastle/asn1/teletrust/package.html \
 org/bouncycastle/asn1/ua/DSTU4145BinaryField.java \
 org/bouncycastle/asn1/ua/DSTU4145ECBinary.java \
 org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java \
@@ -132,7 +127,6 @@
 org/bouncycastle/asn1/ua/UAObjectIdentifiers.java \
 org/bouncycastle/asn1/util/DERDump.java \
 org/bouncycastle/asn1/util/Dump.java \
-org/bouncycastle/asn1/util/package.html \
 org/bouncycastle/asn1/x509/AccessDescription.java \
 org/bouncycastle/asn1/x509/AuthorityInformationAccess.java \
 org/bouncycastle/asn1/x509/CertPolicyId.java \
@@ -155,24 +149,22 @@
 org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java \
 org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java \
 org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java \
-org/bouncycastle/asn1/x509/package.html \
-org/bouncycastle/asn1/x9/ECNamedCurveTable.java \
 org/bouncycastle/asn1/x9/KeySpecificInfo.java \
 org/bouncycastle/asn1/x9/OtherInfo.java \
-org/bouncycastle/asn1/x9/package.html \
 org/bouncycastle/crypto/BufferedAsymmetricBlockCipher.java \
 org/bouncycastle/crypto/Commitment.java \
 org/bouncycastle/crypto/Committer.java \
+org/bouncycastle/crypto/DigestDerivationFunction.java \
 org/bouncycastle/crypto/EphemeralKeyPair.java \
 org/bouncycastle/crypto/KeyEncapsulation.java \
 org/bouncycastle/crypto/KeyEncoder.java \
 org/bouncycastle/crypto/KeyParser.java \
+org/bouncycastle/crypto/MacDerivationFunction.java \
 org/bouncycastle/crypto/MaxBytesExceededException.java \
 org/bouncycastle/crypto/agreement/DHAgreement.java \
 org/bouncycastle/crypto/agreement/DHStandardGroups.java \
 org/bouncycastle/crypto/agreement/ECDHCBasicAgreement.java \
 org/bouncycastle/crypto/agreement/ECMQVBasicAgreement.java \
-org/bouncycastle/crypto/agreement/package.html \
 org/bouncycastle/crypto/digests/GOST3411Digest.java \
 org/bouncycastle/crypto/digests/MD2Digest.java \
 org/bouncycastle/crypto/digests/MD4Digest.java \
@@ -181,21 +173,22 @@
 org/bouncycastle/crypto/digests/RIPEMD160Digest.java \
 org/bouncycastle/crypto/digests/RIPEMD256Digest.java \
 org/bouncycastle/crypto/digests/RIPEMD320Digest.java \
-org/bouncycastle/crypto/digests/SHA224Digest.java \
 org/bouncycastle/crypto/digests/SHA3Digest.java \
 org/bouncycastle/crypto/digests/SHA512tDigest.java \
+org/bouncycastle/crypto/digests/SM3Digest.java \
 org/bouncycastle/crypto/digests/ShortenedDigest.java \
+org/bouncycastle/crypto/digests/SkeinDigest.java \
+org/bouncycastle/crypto/digests/SkeinEngine.java \
 org/bouncycastle/crypto/digests/TigerDigest.java \
 org/bouncycastle/crypto/digests/WhirlpoolDigest.java \
-org/bouncycastle/crypto/digests/package.html \
 org/bouncycastle/crypto/encodings/ISO9796d1Encoding.java \
-org/bouncycastle/crypto/encodings/package.html \
 org/bouncycastle/crypto/engines/AESLightEngine.java \
 org/bouncycastle/crypto/engines/CAST5Engine.java \
 org/bouncycastle/crypto/engines/CAST6Engine.java \
 org/bouncycastle/crypto/engines/CamelliaEngine.java \
 org/bouncycastle/crypto/engines/CamelliaLightEngine.java \
 org/bouncycastle/crypto/engines/CamelliaWrapEngine.java \
+org/bouncycastle/crypto/engines/ChaChaEngine.java \
 org/bouncycastle/crypto/engines/ElGamalEngine.java \
 org/bouncycastle/crypto/engines/GOST28147Engine.java \
 org/bouncycastle/crypto/engines/Grain128Engine.java \
@@ -220,12 +213,14 @@
 org/bouncycastle/crypto/engines/SEEDWrapEngine.java \
 org/bouncycastle/crypto/engines/Salsa20Engine.java \
 org/bouncycastle/crypto/engines/SerpentEngine.java \
+org/bouncycastle/crypto/engines/Shacal2Engine.java \
 org/bouncycastle/crypto/engines/SkipjackEngine.java \
 org/bouncycastle/crypto/engines/TEAEngine.java \
+org/bouncycastle/crypto/engines/ThreefishEngine.java \
 org/bouncycastle/crypto/engines/VMPCEngine.java \
 org/bouncycastle/crypto/engines/VMPCKSA3Engine.java \
+org/bouncycastle/crypto/engines/XSalsa20Engine.java \
 org/bouncycastle/crypto/engines/XTEAEngine.java \
-org/bouncycastle/crypto/engines/package.html \
 org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java \
 org/bouncycastle/crypto/generators/DHKeyPairGenerator.java \
 org/bouncycastle/crypto/generators/DSTU4145KeyPairGenerator.java \
@@ -237,14 +232,19 @@
 org/bouncycastle/crypto/generators/HKDFBytesGenerator.java \
 org/bouncycastle/crypto/generators/KDF1BytesGenerator.java \
 org/bouncycastle/crypto/generators/KDF2BytesGenerator.java \
+org/bouncycastle/crypto/generators/KDFCounterBytesGenerator.java \
+org/bouncycastle/crypto/generators/KDFDoublePipelineIterationBytesGenerator.java \
+org/bouncycastle/crypto/generators/KDFFeedbackBytesGenerator.java \
 org/bouncycastle/crypto/generators/MGF1BytesGenerator.java \
 org/bouncycastle/crypto/generators/NaccacheSternKeyPairGenerator.java \
+org/bouncycastle/crypto/generators/Poly1305KeyGenerator.java \
 org/bouncycastle/crypto/generators/RSABlindingFactorGenerator.java \
 org/bouncycastle/crypto/generators/SCrypt.java \
-org/bouncycastle/crypto/generators/package.html \
+org/bouncycastle/crypto/io/CipherInputStream.java \
+org/bouncycastle/crypto/io/CipherOutputStream.java \
+org/bouncycastle/crypto/io/InvalidCipherTextIOException.java \
 org/bouncycastle/crypto/io/SignerInputStream.java \
 org/bouncycastle/crypto/io/SignerOutputStream.java \
-org/bouncycastle/crypto/io/package.html \
 org/bouncycastle/crypto/macs/BlockCipherMac.java \
 org/bouncycastle/crypto/macs/CFBBlockCipherMac.java \
 org/bouncycastle/crypto/macs/CMac.java \
@@ -252,21 +252,21 @@
 org/bouncycastle/crypto/macs/GOST28147Mac.java \
 org/bouncycastle/crypto/macs/ISO9797Alg3Mac.java \
 org/bouncycastle/crypto/macs/OldHMac.java \
+org/bouncycastle/crypto/macs/Poly1305.java \
 org/bouncycastle/crypto/macs/SipHash.java \
+org/bouncycastle/crypto/macs/SkeinMac.java \
 org/bouncycastle/crypto/macs/VMPCMac.java \
-org/bouncycastle/crypto/macs/package.html \
 org/bouncycastle/crypto/modes/EAXBlockCipher.java \
+org/bouncycastle/crypto/modes/GCFBBlockCipher.java \
 org/bouncycastle/crypto/modes/GOFBBlockCipher.java \
 org/bouncycastle/crypto/modes/OCBBlockCipher.java \
+org/bouncycastle/crypto/modes/OldCTSBlockCipher.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/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/crypto/params/ElGamalKeyGenerationParameters.java \
 org/bouncycastle/crypto/params/ElGamalKeyParameters.java \
@@ -283,6 +283,9 @@
 org/bouncycastle/crypto/params/IESParameters.java \
 org/bouncycastle/crypto/params/IESWithCipherParameters.java \
 org/bouncycastle/crypto/params/ISO18033KDFParameters.java \
+org/bouncycastle/crypto/params/KDFCounterParameters.java \
+org/bouncycastle/crypto/params/KDFDoublePipelineIterationParameters.java \
+org/bouncycastle/crypto/params/KDFFeedbackParameters.java \
 org/bouncycastle/crypto/params/KDFParameters.java \
 org/bouncycastle/crypto/params/MGFParameters.java \
 org/bouncycastle/crypto/params/MQVPrivateParameters.java \
@@ -294,7 +297,8 @@
 org/bouncycastle/crypto/params/ParametersWithSalt.java \
 org/bouncycastle/crypto/params/RC5Parameters.java \
 org/bouncycastle/crypto/params/RSABlindingParameters.java \
-org/bouncycastle/crypto/params/package.html \
+org/bouncycastle/crypto/params/SkeinParameters.java \
+org/bouncycastle/crypto/params/TweakableBlockCipherParameters.java \
 org/bouncycastle/crypto/parsers/DHIESPublicKeyParser.java \
 org/bouncycastle/crypto/parsers/ECIESPublicKeyParser.java \
 org/bouncycastle/crypto/signers/DSADigestSigner.java \
@@ -303,13 +307,12 @@
 org/bouncycastle/crypto/signers/ECNRSigner.java \
 org/bouncycastle/crypto/signers/GOST3410Signer.java \
 org/bouncycastle/crypto/signers/GenericSigner.java \
+org/bouncycastle/crypto/signers/HMacDSAKCalculator.java \
 org/bouncycastle/crypto/signers/ISO9796d2PSSSigner.java \
 org/bouncycastle/crypto/signers/ISO9796d2Signer.java \
 org/bouncycastle/crypto/signers/PSSSigner.java \
-org/bouncycastle/crypto/signers/package.html \
 org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java \
 org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java \
-org/bouncycastle/crypto/util/package.html \
 org/bouncycastle/jcajce/provider/asymmetric/DSTU4145.java \
 org/bouncycastle/jcajce/provider/asymmetric/ECGOST.java \
 org/bouncycastle/jcajce/provider/asymmetric/ElGamal.java \
@@ -328,13 +331,15 @@
 org/bouncycastle/jcajce/provider/digest/RIPEMD160.java \
 org/bouncycastle/jcajce/provider/digest/RIPEMD256.java \
 org/bouncycastle/jcajce/provider/digest/RIPEMD320.java \
-org/bouncycastle/jcajce/provider/digest/SHA224.java \
 org/bouncycastle/jcajce/provider/digest/SHA3.java \
+org/bouncycastle/jcajce/provider/digest/SM3.java \
+org/bouncycastle/jcajce/provider/digest/Skein.java \
 org/bouncycastle/jcajce/provider/digest/Tiger.java \
 org/bouncycastle/jcajce/provider/digest/Whirlpool.java \
 org/bouncycastle/jcajce/provider/symmetric/CAST5.java \
 org/bouncycastle/jcajce/provider/symmetric/CAST6.java \
 org/bouncycastle/jcajce/provider/symmetric/Camellia.java \
+org/bouncycastle/jcajce/provider/symmetric/ChaCha.java \
 org/bouncycastle/jcajce/provider/symmetric/GOST28147.java \
 org/bouncycastle/jcajce/provider/symmetric/Grain128.java \
 org/bouncycastle/jcajce/provider/symmetric/Grainv1.java \
@@ -349,15 +354,20 @@
 org/bouncycastle/jcajce/provider/symmetric/SEED.java \
 org/bouncycastle/jcajce/provider/symmetric/Salsa20.java \
 org/bouncycastle/jcajce/provider/symmetric/Serpent.java \
+org/bouncycastle/jcajce/provider/symmetric/Shacal2.java \
 org/bouncycastle/jcajce/provider/symmetric/SipHash.java \
 org/bouncycastle/jcajce/provider/symmetric/Skipjack.java \
 org/bouncycastle/jcajce/provider/symmetric/TEA.java \
+org/bouncycastle/jcajce/provider/symmetric/Threefish.java \
 org/bouncycastle/jcajce/provider/symmetric/VMPC.java \
 org/bouncycastle/jcajce/provider/symmetric/VMPCKSA3.java \
+org/bouncycastle/jcajce/provider/symmetric/XSalsa20.java \
 org/bouncycastle/jcajce/provider/symmetric/XTEA.java \
+org/bouncycastle/jcajce/spec/GOST28147ParameterSpec.java \
+org/bouncycastle/jcajce/spec/RepeatedSecretKeySpec.java \
+org/bouncycastle/jcajce/spec/SkeinParameterSpec.java \
 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/PKCS12Util.java \
@@ -375,8 +385,6 @@
 org/bouncycastle/jce/interfaces/IESKey.java \
 org/bouncycastle/jce/interfaces/MQVPrivateKey.java \
 org/bouncycastle/jce/interfaces/MQVPublicKey.java \
-org/bouncycastle/jce/interfaces/package.html \
-org/bouncycastle/jce/package.html \
 org/bouncycastle/jce/provider/BrokenJCEBlockCipher.java \
 org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java \
 org/bouncycastle/jce/provider/BrokenPBE.java \
@@ -413,10 +421,17 @@
 org/bouncycastle/jce/spec/IESParameterSpec.java \
 org/bouncycastle/jce/spec/MQVPrivateKeySpec.java \
 org/bouncycastle/jce/spec/MQVPublicKeySpec.java \
-org/bouncycastle/jce/spec/package.html \
+org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java \
+org/bouncycastle/math/ec/DoubleAddMultiplier.java \
+org/bouncycastle/math/ec/MixedNafR2LMultiplier.java \
+org/bouncycastle/math/ec/MontgomeryLadderMultiplier.java \
+org/bouncycastle/math/ec/NafL2RMultiplier.java \
+org/bouncycastle/math/ec/NafR2LMultiplier.java \
 org/bouncycastle/math/ec/ReferenceMultiplier.java \
-org/bouncycastle/math/ec/package.html \
+org/bouncycastle/math/ec/ZSignedDigitL2RMultiplier.java \
+org/bouncycastle/math/ec/ZSignedDigitR2LMultiplier.java \
 org/bouncycastle/util/MemoableResetException.java \
+org/bouncycastle/util/Shorts.java \
 org/bouncycastle/util/StreamParser.java \
 org/bouncycastle/util/StreamParsingException.java \
 org/bouncycastle/util/encoders/BufferedDecoder.java \
@@ -425,7 +440,7 @@
 org/bouncycastle/util/encoders/Translator.java \
 org/bouncycastle/util/encoders/UrlBase64.java \
 org/bouncycastle/util/encoders/UrlBase64Encoder.java \
-org/bouncycastle/util/encoders/package.html \
+org/bouncycastle/util/io/BufferingOutputStream.java \
 org/bouncycastle/x509/CertPathReviewerException.java \
 org/bouncycastle/x509/CertPathReviewerMessages_de.properties \
 org/bouncycastle/x509/NoSuchParserException.java \
@@ -433,12 +448,11 @@
 org/bouncycastle/x509/X509AttributeCertStoreSelector.java \
 org/bouncycastle/x509/X509CertPairStoreSelector.java \
 org/bouncycastle/x509/X509CertificatePair.java \
+org/bouncycastle/x509/X509Store.java \
 org/bouncycastle/x509/X509StreamParser.java \
 org/bouncycastle/x509/X509StreamParserSpi.java \
 org/bouncycastle/x509/X509V2AttributeCertificateGenerator.java \
 org/bouncycastle/x509/X509V2CRLGenerator.java \
-org/bouncycastle/x509/extension/package.html \
-org/bouncycastle/x509/package.html \
 org/bouncycastle/x509/util/LDAPStoreHelper.java \
 org/bouncycastle/x509/util/StreamParser.java \
 org/bouncycastle/x509/util/StreamParsingException.java \
@@ -451,6 +465,7 @@
 org/bouncycastle/cert/cmp \
 org/bouncycastle/cert/crmf \
 org/bouncycastle/cert/ocsp \
+org/bouncycastle/cert/path \
 org/bouncycastle/cert/selector/jcajce \
 org/bouncycastle/cert/test \
 org/bouncycastle/cms/bc \
@@ -467,6 +482,7 @@
 # files
 UNNEEDED_BCPKIX_SOURCES+=" \
 org/bouncycastle/cert/CertRuntimeException.java \
+org/bouncycastle/cert/X509ContentVerifierProviderBuilder.java \
 org/bouncycastle/cert/X509ExtensionUtils.java \
 org/bouncycastle/cert/X509v1CertificateBuilder.java \
 org/bouncycastle/cert/X509v2AttributeCertificateBuilder.java \
@@ -482,17 +498,15 @@
 org/bouncycastle/cert/jcajce/JcaX509CRLConverter.java \
 org/bouncycastle/cert/jcajce/JcaX509CRLHolder.java \
 org/bouncycastle/cert/jcajce/JcaX509CertificateConverter.java \
+org/bouncycastle/cert/jcajce/JcaX509ContentVerifierProviderBuilder.java \
 org/bouncycastle/cert/jcajce/JcaX509ExtensionUtils.java \
 org/bouncycastle/cert/jcajce/JcaX509v1CertificateBuilder.java \
 org/bouncycastle/cert/jcajce/JcaX509v2CRLBuilder.java \
 org/bouncycastle/cert/jcajce/JcaX509v3CertificateBuilder.java \
 org/bouncycastle/cert/jcajce/NamedCertHelper.java \
 org/bouncycastle/cert/jcajce/ProviderCertHelper.java \
-org/bouncycastle/cert/jcajce/package.html \
-org/bouncycastle/cert/package.html \
 org/bouncycastle/cert/selector/X509AttributeCertificateHolderSelector.java \
 org/bouncycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java \
-org/bouncycastle/cert/selector/package.html \
 org/bouncycastle/cms/AuthAttributesProvider.java \
 org/bouncycastle/cms/CMSAlgorithm.java \
 org/bouncycastle/cms/CMSAuthEnvelopedData.java \
@@ -518,7 +532,6 @@
 org/bouncycastle/cms/CMSEnvelopedDataStreamGenerator.java \
 org/bouncycastle/cms/CMSEnvelopedGenerator.java \
 org/bouncycastle/cms/CMSEnvelopedHelper.java \
-org/bouncycastle/cms/CMSPBEKey.java \
 org/bouncycastle/cms/CMSProcessableFile.java \
 org/bouncycastle/cms/CMSProcessableInputStream.java \
 org/bouncycastle/cms/CMSSecureReadable.java \
@@ -542,8 +555,6 @@
 org/bouncycastle/cms/OriginatorId.java \
 org/bouncycastle/cms/OriginatorInfoGenerator.java \
 org/bouncycastle/cms/OriginatorInformation.java \
-org/bouncycastle/cms/PKCS5Scheme2PBEKey.java \
-org/bouncycastle/cms/PKCS5Scheme2UTF8PBEKey.java \
 org/bouncycastle/cms/PasswordRecipient.java \
 org/bouncycastle/cms/PasswordRecipientId.java \
 org/bouncycastle/cms/PasswordRecipientInfoGenerator.java \
@@ -588,10 +599,10 @@
 org/bouncycastle/cms/jcajce/ProviderJcaJceExtHelper.java \
 org/bouncycastle/cms/jcajce/ZlibCompressor.java \
 org/bouncycastle/cms/jcajce/ZlibExpanderProvider.java \
-org/bouncycastle/cms/package.html \
 org/bouncycastle/operator/AsymmetricKeyUnwrapper.java \
 org/bouncycastle/operator/AsymmetricKeyWrapper.java \
-org/bouncycastle/operator/DefaultSecretKeyProvider.java \
+org/bouncycastle/operator/BufferingContentSigner.java \
+org/bouncycastle/operator/DefaultSecretKeySizeProvider.java \
 org/bouncycastle/operator/GenericKey.java \
 org/bouncycastle/operator/InputDecryptor.java \
 org/bouncycastle/operator/InputDecryptorProvider.java \
@@ -625,13 +636,13 @@
 org/bouncycastle/operator/bc/CamelliaUtil.java \
 org/bouncycastle/operator/bc/OperatorUtils.java \
 org/bouncycastle/operator/bc/SEEDUtil.java \
+org/bouncycastle/operator/jcajce/JcaAlgorithmParametersConverter.java \
 org/bouncycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java \
 org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java \
 org/bouncycastle/operator/jcajce/JceGenericKey.java \
 org/bouncycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java \
 org/bouncycastle/operator/jcajce/JceSymmetricKeyWrapper.java \
 org/bouncycastle/operator/jcajce/OperatorUtils.java \
-org/bouncycastle/operator/package.html \
 "
 
 # needed sources to copy in
diff --git a/bouncycastle.version b/bouncycastle.version
index 89e1ea4..45c0f80 100644
--- a/bouncycastle.version
+++ b/bouncycastle.version
@@ -1,2 +1,2 @@
 BOUNCYCASTLE_JDK=15on
-BOUNCYCASTLE_VERSION=149
+BOUNCYCASTLE_VERSION=150
diff --git a/import_bouncycastle.sh b/import_bouncycastle.sh
index ed278d8..0dfe484 100755
--- a/import_bouncycastle.sh
+++ b/import_bouncycastle.sh
@@ -28,6 +28,8 @@
 set -e
 trap  "echo WARNING: Exiting on non-zero subprocess exit code" ERR;
 
+cd $(dirname $0)
+
 function die() {
   declare -r message=$1
 
@@ -57,7 +59,7 @@
     die "bouncycastle.version not found"
   fi
 
-  source bouncycastle.version
+  source ./bouncycastle.version
   if [ "$BOUNCYCASTLE_JDK" == "" -o "$BOUNCYCASTLE_VERSION" == "" ]; then
     die "Invalid bouncycastle.version; see README.android for more information"
   fi
@@ -72,7 +74,7 @@
     die "bouncycastle.config not found"
   fi
 
-  source bouncycastle.config
+  source ./bouncycastle.config
   if [ "$UNNEEDED_BCPROV_SOURCES" == "" -o "$NEEDED_BCPROV_SOURCES" == "" \
     -o "$UNNEEDED_BCPKIX_SOURCES" == "" -o "$NEEDED_BCPKIX_SOURCES" == "" ]; then
     die "Invalid bouncycastle.config; see README.android for more information"
diff --git a/patches/bcpkix.patch b/patches/bcpkix.patch
index 78354bd..b18c53c 100644
--- a/patches/bcpkix.patch
+++ b/patches/bcpkix.patch
@@ -1,309 +1,7 @@
-diff -Naur bcpkix-jdk15on-149.orig/org/bouncycastle/cms/CMSSignedData.java bcpkix-jdk15on-149/org/bouncycastle/cms/CMSSignedData.java
---- bcpkix-jdk15on-149.orig/org/bouncycastle/cms/CMSSignedData.java	2013-05-31 21:17:22.000000000 +0000
-+++ bcpkix-jdk15on-149/org/bouncycastle/cms/CMSSignedData.java	2013-05-25 02:14:15.000000000 +0000
-@@ -25,7 +25,9 @@
- import org.bouncycastle.asn1.cms.ContentInfo;
- import org.bouncycastle.asn1.cms.SignedData;
- import org.bouncycastle.asn1.cms.SignerInfo;
--import org.bouncycastle.cert.jcajce.JcaCertStoreBuilder;
-+// BEGIN android-removed
-+// import org.bouncycastle.cert.jcajce.JcaCertStoreBuilder;
-+// END android-removed
- import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
- import org.bouncycastle.operator.OperatorCreationException;
- import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder;
-@@ -309,147 +311,149 @@
-         return attributeStore;
-     }
- 
--    /**
--     * return a X509Store containing the public key certificates, if any, contained
--     * in this message.
--     *
--     * @param type type of store to create
--     * @param provider name of provider to use
--     * @return a store of public key certificates
--     * @exception NoSuchProviderException if the provider requested isn't available.
--     * @exception NoSuchStoreException if the store type isn't available.
--     * @exception CMSException if a general exception prevents creation of the X509Store
--     * @deprecated use base Store returning method
--     */
--    public X509Store getCertificates(
--        String type,
--        String provider)
--        throws NoSuchStoreException, NoSuchProviderException, CMSException
--    {
--        return getCertificates(type, CMSUtils.getProvider(provider));
--    }
--
--    /**
--     * return a X509Store containing the public key certificates, if any, contained
--     * in this message.
--     *
--     * @param type type of store to create
--     * @param provider provider to use
--     * @return a store of public key certificates
--     * @exception NoSuchStoreException if the store type isn't available.
--     * @exception CMSException if a general exception prevents creation of the X509Store
--     * @deprecated use base Store returning method
--     */
--    public X509Store getCertificates(
--        String type,
--        Provider provider)
--        throws NoSuchStoreException, CMSException
--    {
--        if (certificateStore == null)
--        {
--            certificateStore = HELPER.createCertificateStore(type, provider, this.getCertificates());
--        }
--
--        return certificateStore;
--    }
--
--    /**
--     * return a X509Store containing CRLs, if any, contained
--     * in this message.
--     *
--     * @param type type of store to create
--     * @param provider name of provider to use
--     * @return a store of CRLs
--     * @exception NoSuchProviderException if the provider requested isn't available.
--     * @exception NoSuchStoreException if the store type isn't available.
--     * @exception CMSException if a general exception prevents creation of the X509Store
--     * @deprecated use base Store returning method
--     */
--    public X509Store getCRLs(
--        String type,
--        String provider)
--        throws NoSuchStoreException, NoSuchProviderException, CMSException
--    {
--        return getCRLs(type, CMSUtils.getProvider(provider));
--    }
--
--    /**
--     * return a X509Store containing CRLs, if any, contained
--     * in this message.
--     *
--     * @param type type of store to create
--     * @param provider provider to use
--     * @return a store of CRLs
--     * @exception NoSuchStoreException if the store type isn't available.
--     * @exception CMSException if a general exception prevents creation of the X509Store
--     * @deprecated use base Store returning method
--     */
--    public X509Store getCRLs(
--        String type,
--        Provider provider)
--        throws NoSuchStoreException, CMSException
--    {
--        if (crlStore == null)
--        {
--            crlStore = HELPER.createCRLsStore(type, provider, getCRLs());
--        }
--
--        return crlStore;
--    }
--  
--    /**
--     * return a CertStore containing the certificates and CRLs associated with
--     * this message.
--     *
--     * @exception NoSuchProviderException if the provider requested isn't available.
--     * @exception NoSuchAlgorithmException if the cert store isn't available.
--     * @exception CMSException if a general exception prevents creation of the CertStore
--     * @deprecated use base Store returning method and org.bouncycastle.cert.jcajce.JcaCertStoreBuilder
--     */
--    public CertStore getCertificatesAndCRLs(
--        String  type,
--        String  provider)
--        throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
--    {
--        return getCertificatesAndCRLs(type, CMSUtils.getProvider(provider));
--    }
--
--    /**
--     * return a CertStore containing the certificates and CRLs associated with
--     * this message.
--     *
--     * @exception NoSuchAlgorithmException if the cert store isn't available.
--     * @exception CMSException if a general exception prevents creation of the CertStore
--     * @deprecated use base Store returning method and org.bouncycastle.cert.jcajce.JcaCertStoreBuilder
--     */
--    public CertStore getCertificatesAndCRLs(
--        String  type,
--        Provider  provider)
--        throws NoSuchAlgorithmException, CMSException
--    {
--        try
--        {
--            JcaCertStoreBuilder certStoreBuilder = new JcaCertStoreBuilder().setType(type);
--
--            if (provider != null)
--            {
--                certStoreBuilder.setProvider(provider);
--            }
--
--            certStoreBuilder.addCertificates(this.getCertificates());
--            certStoreBuilder.addCRLs(this.getCRLs());
--
--            return certStoreBuilder.build();
--        }
--        catch (NoSuchAlgorithmException e)
--        {
--            throw e;
--        }
--        catch (Exception e)
--        {
--            throw new CMSException("exception creating CertStore: " + e.getMessage(), e);
--        }
--    }
-+    // BEGIN android-removed
-+    // /**
-+    //  * return a X509Store containing the public key certificates, if any, contained
-+    //  * in this message.
-+    //  *
-+    //  * @param type type of store to create
-+    //  * @param provider name of provider to use
-+    //  * @return a store of public key certificates
-+    //  * @exception NoSuchProviderException if the provider requested isn't available.
-+    //  * @exception NoSuchStoreException if the store type isn't available.
-+    //  * @exception CMSException if a general exception prevents creation of the X509Store
-+    //  * @deprecated use base Store returning method
-+    //  */
-+    // public X509Store getCertificates(
-+    //     String type,
-+    //     String provider)
-+    //     throws NoSuchStoreException, NoSuchProviderException, CMSException
-+    // {
-+    //     return getCertificates(type, CMSUtils.getProvider(provider));
-+    // }
-+    //
-+    // /**
-+    //  * return a X509Store containing the public key certificates, if any, contained
-+    //  * in this message.
-+    //  *
-+    //  * @param type type of store to create
-+    //  * @param provider provider to use
-+    //  * @return a store of public key certificates
-+    //  * @exception NoSuchStoreException if the store type isn't available.
-+    //  * @exception CMSException if a general exception prevents creation of the X509Store
-+    //  * @deprecated use base Store returning method
-+    //  */
-+    // public X509Store getCertificates(
-+    //     String type,
-+    //     Provider provider)
-+    //     throws NoSuchStoreException, CMSException
-+    // {
-+    //     if (certificateStore == null)
-+    //     {
-+    //         certificateStore = HELPER.createCertificateStore(type, provider, this.getCertificates());
-+    //     }
-+    //
-+    //     return certificateStore;
-+    // }
-+    //
-+    // /**
-+    //  * return a X509Store containing CRLs, if any, contained
-+    //  * in this message.
-+    //  *
-+    //  * @param type type of store to create
-+    //  * @param provider name of provider to use
-+    //  * @return a store of CRLs
-+    //  * @exception NoSuchProviderException if the provider requested isn't available.
-+    //  * @exception NoSuchStoreException if the store type isn't available.
-+    //  * @exception CMSException if a general exception prevents creation of the X509Store
-+    //  * @deprecated use base Store returning method
-+    //  */
-+    // public X509Store getCRLs(
-+    //     String type,
-+    //     String provider)
-+    //     throws NoSuchStoreException, NoSuchProviderException, CMSException
-+    // {
-+    //     return getCRLs(type, CMSUtils.getProvider(provider));
-+    // }
-+    //
-+    // /**
-+    //  * return a X509Store containing CRLs, if any, contained
-+    //  * in this message.
-+    //  *
-+    //  * @param type type of store to create
-+    //  * @param provider provider to use
-+    //  * @return a store of CRLs
-+    //  * @exception NoSuchStoreException if the store type isn't available.
-+    //  * @exception CMSException if a general exception prevents creation of the X509Store
-+    //  * @deprecated use base Store returning method
-+    //  */
-+    // public X509Store getCRLs(
-+    //     String type,
-+    //     Provider provider)
-+    //     throws NoSuchStoreException, CMSException
-+    // {
-+    //     if (crlStore == null)
-+    //     {
-+    //         crlStore = HELPER.createCRLsStore(type, provider, getCRLs());
-+    //     }
-+    //
-+    //     return crlStore;
-+    // }
-+    //
-+    // /**
-+    //  * return a CertStore containing the certificates and CRLs associated with
-+    //  * this message.
-+    //  *
-+    //  * @exception NoSuchProviderException if the provider requested isn't available.
-+    //  * @exception NoSuchAlgorithmException if the cert store isn't available.
-+    //  * @exception CMSException if a general exception prevents creation of the CertStore
-+    //  * @deprecated use base Store returning method and org.bouncycastle.cert.jcajce.JcaCertStoreBuilder
-+    //  */
-+    // public CertStore getCertificatesAndCRLs(
-+    //     String  type,
-+    //     String  provider)
-+    //     throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
-+    // {
-+    //     return getCertificatesAndCRLs(type, CMSUtils.getProvider(provider));
-+    // }
-+    //
-+    // /**
-+    //  * return a CertStore containing the certificates and CRLs associated with
-+    //  * this message.
-+    //  *
-+    //  * @exception NoSuchAlgorithmException if the cert store isn't available.
-+    //  * @exception CMSException if a general exception prevents creation of the CertStore
-+    //  * @deprecated use base Store returning method and org.bouncycastle.cert.jcajce.JcaCertStoreBuilder
-+    //  */
-+    // public CertStore getCertificatesAndCRLs(
-+    //     String  type,
-+    //     Provider  provider)
-+    //     throws NoSuchAlgorithmException, CMSException
-+    // {
-+    //     try
-+    //     {
-+    //         JcaCertStoreBuilder certStoreBuilder = new JcaCertStoreBuilder().setType(type);
-+    //
-+    //         if (provider != null)
-+    //         {
-+    //             certStoreBuilder.setProvider(provider);
-+    //         }
-+    //
-+    //         certStoreBuilder.addCertificates(this.getCertificates());
-+    //         certStoreBuilder.addCRLs(this.getCRLs());
-+    //
-+    //         return certStoreBuilder.build();
-+    //     }
-+    //     catch (NoSuchAlgorithmException e)
-+    //     {
-+    //         throw e;
-+    //     }
-+    //     catch (Exception e)
-+    //     {
-+    //         throw new CMSException("exception creating CertStore: " + e.getMessage(), e);
-+    //     }
-+    // }
-+    // END android-removed
- 
-     /**
-      * Return any X.509 certificate objects in this SignedData structure as a Store of X509CertificateHolder objects.
-@@ -481,18 +485,20 @@
+diff -Naur bcpkix-jdk15on-150.orig/org/bouncycastle/cms/CMSSignedData.java bcpkix-jdk15on-150/org/bouncycastle/cms/CMSSignedData.java
+--- bcpkix-jdk15on-150.orig/org/bouncycastle/cms/CMSSignedData.java	2013-12-03 20:18:54.000000000 +0000
++++ bcpkix-jdk15on-150/org/bouncycastle/cms/CMSSignedData.java	2013-12-12 00:35:05.000000000 +0000
+@@ -285,18 +285,20 @@
          return HELPER.getAttributeCertificates(signedData.getCertificates());
      }
  
@@ -336,7 +34,7 @@
  
      /**
       * Return the a string representation of the OID associated with the
-@@ -536,71 +542,73 @@
+@@ -331,71 +333,73 @@
          return contentInfo.getEncoded();
      }
  
@@ -475,12 +173,12 @@
  
      /**
       * Replace the SignerInformation store associated with this
-diff -Naur bcpkix-jdk15on-149.orig/org/bouncycastle/cms/CMSSignedGenerator.java bcpkix-jdk15on-149/org/bouncycastle/cms/CMSSignedGenerator.java
---- bcpkix-jdk15on-149.orig/org/bouncycastle/cms/CMSSignedGenerator.java	2013-05-31 21:17:22.000000000 +0000
-+++ bcpkix-jdk15on-149/org/bouncycastle/cms/CMSSignedGenerator.java	2013-05-25 02:14:15.000000000 +0000
-@@ -23,8 +23,10 @@
+diff -Naur bcpkix-jdk15on-150.orig/org/bouncycastle/cms/CMSSignedGenerator.java bcpkix-jdk15on-150/org/bouncycastle/cms/CMSSignedGenerator.java
+--- bcpkix-jdk15on-150.orig/org/bouncycastle/cms/CMSSignedGenerator.java	2013-12-03 20:18:54.000000000 +0000
++++ bcpkix-jdk15on-150/org/bouncycastle/cms/CMSSignedGenerator.java	2013-12-12 00:35:05.000000000 +0000
+@@ -12,8 +12,10 @@
+ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
  import org.bouncycastle.asn1.DERTaggedObject;
- import org.bouncycastle.asn1.cms.AttributeTable;
  import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
 -import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat;
 -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
@@ -491,26 +189,7 @@
  import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-@@ -35,7 +37,9 @@
- import org.bouncycastle.cert.X509AttributeCertificateHolder;
- import org.bouncycastle.cert.X509CRLHolder;
- import org.bouncycastle.cert.X509CertificateHolder;
--import org.bouncycastle.jce.interfaces.GOST3410PrivateKey;
-+// BEGIN android-removed
-+// import org.bouncycastle.jce.interfaces.GOST3410PrivateKey;
-+// END android-removed
- import org.bouncycastle.util.Arrays;
- import org.bouncycastle.util.Store;
- import org.bouncycastle.x509.X509AttributeCertificate;
-@@ -49,25 +53,33 @@
-     public static final String  DATA = CMSObjectIdentifiers.data.getId();
-     
-     public static final String  DIGEST_SHA1 = OIWObjectIdentifiers.idSHA1.getId();
--    public static final String  DIGEST_SHA224 = NISTObjectIdentifiers.id_sha224.getId();
-+    // BEGIN android-removed
-+    // public static final String  DIGEST_SHA224 = NISTObjectIdentifiers.id_sha224.getId();
-+    // END android-removed
-     public static final String  DIGEST_SHA256 = NISTObjectIdentifiers.id_sha256.getId();
+@@ -39,17 +41,21 @@
      public static final String  DIGEST_SHA384 = NISTObjectIdentifiers.id_sha384.getId();
      public static final String  DIGEST_SHA512 = NISTObjectIdentifiers.id_sha512.getId();
      public static final String  DIGEST_MD5 = PKCSObjectIdentifiers.md5.getId();
@@ -537,59 +216,8 @@
 +    // END android-removed
  
      private static final String  ENCRYPTION_ECDSA_WITH_SHA1 = X9ObjectIdentifiers.ecdsa_with_SHA1.getId();
--    private static final String  ENCRYPTION_ECDSA_WITH_SHA224 = X9ObjectIdentifiers.ecdsa_with_SHA224.getId();
-+    // BEGIN android-removed
-+    // private static final String  ENCRYPTION_ECDSA_WITH_SHA224 = X9ObjectIdentifiers.ecdsa_with_SHA224.getId();
-+    // END android-removed
-     private static final String  ENCRYPTION_ECDSA_WITH_SHA256 = X9ObjectIdentifiers.ecdsa_with_SHA256.getId();
-     private static final String  ENCRYPTION_ECDSA_WITH_SHA384 = X9ObjectIdentifiers.ecdsa_with_SHA384.getId();
-     private static final String  ENCRYPTION_ECDSA_WITH_SHA512 = X9ObjectIdentifiers.ecdsa_with_SHA512.getId();
-@@ -80,13 +92,17 @@
-         NO_PARAMS.add(ENCRYPTION_DSA);
-         NO_PARAMS.add(ENCRYPTION_ECDSA);
-         NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA1);
--        NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA224);
-+        // BEGIN android-removed
-+        // NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA224);
-+        // END android-removed
-         NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA256);
-         NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA384);
-         NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA512);
- 
-         EC_ALGORITHMS.put(DIGEST_SHA1, ENCRYPTION_ECDSA_WITH_SHA1);
--        EC_ALGORITHMS.put(DIGEST_SHA224, ENCRYPTION_ECDSA_WITH_SHA224);
-+        // BEGIN android-removed
-+        // EC_ALGORITHMS.put(DIGEST_SHA224, ENCRYPTION_ECDSA_WITH_SHA224);
-+        // END android-removed
-         EC_ALGORITHMS.put(DIGEST_SHA256, ENCRYPTION_ECDSA_WITH_SHA256);
-         EC_ALGORITHMS.put(DIGEST_SHA384, ENCRYPTION_ECDSA_WITH_SHA384);
-         EC_ALGORITHMS.put(DIGEST_SHA512, ENCRYPTION_ECDSA_WITH_SHA512);
-@@ -144,14 +160,16 @@
-                 throw new IllegalArgumentException("can't mix ECDSA with anything but SHA family digests");
-             }
-         }
--        else if (key instanceof GOST3410PrivateKey || "GOST3410".equalsIgnoreCase(key.getAlgorithm()))
--        {
--            encOID = ENCRYPTION_GOST3410;
--        }
--        else if ("ECGOST3410".equalsIgnoreCase(key.getAlgorithm()))
--        {
--            encOID = ENCRYPTION_ECGOST3410;
--        }
-+        // BEGIN android-removed
-+        // else if (key instanceof GOST3410PrivateKey || "GOST3410".equalsIgnoreCase(key.getAlgorithm()))
-+        // {
-+        //     encOID = ENCRYPTION_GOST3410;
-+        // }
-+        // else if ("ECGOST3410".equalsIgnoreCase(key.getAlgorithm()))
-+        // {
-+        //     encOID = ENCRYPTION_ECGOST3410;
-+        // }
-+        // END android-removed
-         
-         return encOID;
-     }
-@@ -270,31 +288,33 @@
+     private static final String  ENCRYPTION_ECDSA_WITH_SHA224 = X9ObjectIdentifiers.ecdsa_with_SHA224.getId();
+@@ -174,31 +180,33 @@
          certs.addAll(CMSUtils.getAttributeCertificatesFromStore(attrStore));
      }
  
@@ -647,11 +275,11 @@
 +    // END android-removed
  
      /**
-      * Add the attribute certificates contained in the passed in store to the
-diff -Naur bcpkix-jdk15on-149.orig/org/bouncycastle/cms/CMSSignedHelper.java bcpkix-jdk15on-149/org/bouncycastle/cms/CMSSignedHelper.java
---- bcpkix-jdk15on-149.orig/org/bouncycastle/cms/CMSSignedHelper.java	2013-05-31 21:17:22.000000000 +0000
-+++ bcpkix-jdk15on-149/org/bouncycastle/cms/CMSSignedHelper.java	2013-05-25 02:14:15.000000000 +0000
-@@ -19,8 +19,10 @@
+      * Add a store of pre-calculated signers to the generator.
+diff -Naur bcpkix-jdk15on-150.orig/org/bouncycastle/cms/CMSSignedHelper.java bcpkix-jdk15on-150/org/bouncycastle/cms/CMSSignedHelper.java
+--- bcpkix-jdk15on-150.orig/org/bouncycastle/cms/CMSSignedHelper.java	2013-12-03 20:18:54.000000000 +0000
++++ bcpkix-jdk15on-150/org/bouncycastle/cms/CMSSignedHelper.java	2013-12-12 00:35:05.000000000 +0000
+@@ -13,8 +13,10 @@
  import org.bouncycastle.asn1.ASN1Set;
  import org.bouncycastle.asn1.ASN1TaggedObject;
  import org.bouncycastle.asn1.DERNull;
@@ -664,28 +292,7 @@
  import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
  import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
-@@ -35,8 +37,10 @@
- import org.bouncycastle.cert.X509AttributeCertificateHolder;
- import org.bouncycastle.cert.X509CRLHolder;
- import org.bouncycastle.cert.X509CertificateHolder;
--import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
--import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-+// BEGIN android-removed
-+// import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
-+// import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-+// END android-removed
- import org.bouncycastle.util.CollectionStore;
- import org.bouncycastle.util.Store;
- import org.bouncycastle.x509.NoSuchStoreException;
-@@ -60,31 +64,43 @@
- 
-     static
-     {
--        addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA");
-+        // BEGIN android-removed
-+        // addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA");
-+        // END android-removed
-         addEntries(NISTObjectIdentifiers.dsa_with_sha256, "SHA256", "DSA");
+@@ -53,12 +55,16 @@
          addEntries(NISTObjectIdentifiers.dsa_with_sha384, "SHA384", "DSA");
          addEntries(NISTObjectIdentifiers.dsa_with_sha512, "SHA512", "DSA");
          addEntries(OIWObjectIdentifiers.dsaWithSHA1, "SHA1", "DSA");
@@ -705,31 +312,8 @@
 +        // END android-removed
          addEntries(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5", "RSA");
          addEntries(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1", "RSA");
--        addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
-+        // BEGIN android-removed
-+        // addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
-+        // END android-removed
-         addEntries(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256", "RSA");
-         addEntries(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384", "RSA");
-         addEntries(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512", "RSA");
-         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1", "ECDSA");
--        addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA");
-+        // BEGIN android-removed
-+        // addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA");
-+        // END android-removed
-         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256", "ECDSA");
-         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384", "ECDSA");
-         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512", "ECDSA");
-         addEntries(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1", "DSA");
-         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1", "ECDSA");
--        addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
-+        // BEGIN android-removed
-+        // addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
-+        // END android-removed
-         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256", "ECDSA");
-         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384", "ECDSA");
-         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512", "ECDSA");
-@@ -97,30 +113,38 @@
+         addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
+@@ -85,27 +91,31 @@
          encryptionAlgs.put(PKCSObjectIdentifiers.rsaEncryption.getId(), "RSA");
          encryptionAlgs.put(TeleTrusTObjectIdentifiers.teleTrusTRSAsignatureAlgorithm, "RSA");
          encryptionAlgs.put(X509ObjectIdentifiers.id_ea_rsa.getId(), "RSA");
@@ -757,10 +341,7 @@
 +        // END android-removed
          digestAlgs.put(PKCSObjectIdentifiers.md5.getId(), "MD5");
          digestAlgs.put(OIWObjectIdentifiers.idSHA1.getId(), "SHA1");
--        digestAlgs.put(NISTObjectIdentifiers.id_sha224.getId(), "SHA224");
-+        // BEGIN android-removed
-+        // digestAlgs.put(NISTObjectIdentifiers.id_sha224.getId(), "SHA224");
-+        // END android-removed
+         digestAlgs.put(NISTObjectIdentifiers.id_sha224.getId(), "SHA224");
          digestAlgs.put(NISTObjectIdentifiers.id_sha256.getId(), "SHA256");
          digestAlgs.put(NISTObjectIdentifiers.id_sha384.getId(), "SHA384");
          digestAlgs.put(NISTObjectIdentifiers.id_sha512.getId(), "SHA512");
@@ -778,141 +359,8 @@
 +        // END android-removed
  
          digestAliases.put("SHA1", new String[] { "SHA-1" });
--        digestAliases.put("SHA224", new String[] { "SHA-224" });
-+        // BEGIN android-removed
-+        // digestAliases.put("SHA224", new String[] { "SHA-224" });
-+        // END android-removed
-         digestAliases.put("SHA256", new String[] { "SHA-256" });
-         digestAliases.put("SHA384", new String[] { "SHA-384" });
-         digestAliases.put("SHA512", new String[] { "SHA-512" });
-@@ -190,65 +214,67 @@
-         }
-     }
- 
--    X509Store createCertificateStore(
--        String type,
--        Provider provider,
--        Store certStore)
--        throws NoSuchStoreException, CMSException
--    {
--        try
--        {
--            JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider(provider);
--            Collection certHldrs = certStore.getMatches(null);
--            List       certs = new ArrayList(certHldrs.size());
--
--            for (Iterator it = certHldrs.iterator(); it.hasNext();)
--            {
--                certs.add(converter.getCertificate((X509CertificateHolder)it.next()));
--            }
--
--            return X509Store.getInstance(
--                         "Certificate/" +type, new X509CollectionStoreParameters(certs), provider);
--        }
--        catch (IllegalArgumentException e)
--        {
--            throw new CMSException("can't setup the X509Store", e);
--        }
--        catch (CertificateException e)
--        {
--            throw new CMSException("can't setup the X509Store", e);
--        }
--    }
--
--    X509Store createCRLsStore(
--        String type,
--        Provider provider,
--        Store    crlStore)
--        throws NoSuchStoreException, CMSException
--    {
--        try
--        {
--            JcaX509CRLConverter converter = new JcaX509CRLConverter().setProvider(provider);
--            Collection crlHldrs = crlStore.getMatches(null);
--            List       crls = new ArrayList(crlHldrs.size());
--
--            for (Iterator it = crlHldrs.iterator(); it.hasNext();)
--            {
--                crls.add(converter.getCRL((X509CRLHolder)it.next()));
--            }
--
--            return X509Store.getInstance(
--                         "CRL/" +type, new X509CollectionStoreParameters(crls), provider);
--        }
--        catch (IllegalArgumentException e)
--        {
--            throw new CMSException("can't setup the X509Store", e);
--        }
--        catch (CRLException e)
--        {
--            throw new CMSException("can't setup the X509Store", e);
--        }
--    }
-+    // BEGIN android-removed
-+    // X509Store createCertificateStore(
-+    //     String type,
-+    //     Provider provider,
-+    //     Store certStore)
-+    //     throws NoSuchStoreException, CMSException
-+    // {
-+    //     try
-+    //     {
-+    //         JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider(provider);
-+    //         Collection certHldrs = certStore.getMatches(null);
-+    //         List       certs = new ArrayList(certHldrs.size());
-+    //
-+    //         for (Iterator it = certHldrs.iterator(); it.hasNext();)
-+    //         {
-+    //             certs.add(converter.getCertificate((X509CertificateHolder)it.next()));
-+    //         }
-+    //
-+    //         return X509Store.getInstance(
-+    //                      "Certificate/" +type, new X509CollectionStoreParameters(certs), provider);
-+    //     }
-+    //     catch (IllegalArgumentException e)
-+    //     {
-+    //         throw new CMSException("can't setup the X509Store", e);
-+    //     }
-+    //     catch (CertificateException e)
-+    //     {
-+    //         throw new CMSException("can't setup the X509Store", e);
-+    //     }
-+    // }
-+    //
-+    // X509Store createCRLsStore(
-+    //     String type,
-+    //     Provider provider,
-+    //     Store    crlStore)
-+    //     throws NoSuchStoreException, CMSException
-+    // {
-+    //     try
-+    //     {
-+    //         JcaX509CRLConverter converter = new JcaX509CRLConverter().setProvider(provider);
-+    //         Collection crlHldrs = crlStore.getMatches(null);
-+    //         List       crls = new ArrayList(crlHldrs.size());
-+    //
-+    //         for (Iterator it = crlHldrs.iterator(); it.hasNext();)
-+    //         {
-+    //             crls.add(converter.getCRL((X509CRLHolder)it.next()));
-+    //         }
-+    //
-+    //         return X509Store.getInstance(
-+    //                      "CRL/" +type, new X509CollectionStoreParameters(crls), provider);
-+    //     }
-+    //     catch (IllegalArgumentException e)
-+    //     {
-+    //         throw new CMSException("can't setup the X509Store", e);
-+    //     }
-+    //     catch (CRLException e)
-+    //     {
-+    //         throw new CMSException("can't setup the X509Store", e);
-+    //     }
-+    // }
-+    // END android-removed
- 
-     AlgorithmIdentifier fixAlgID(AlgorithmIdentifier algId)
-     {
-@@ -336,35 +362,35 @@
+         digestAliases.put("SHA224", new String[] { "SHA-224" });
+@@ -219,35 +229,35 @@
          return new CollectionStore(new ArrayList());
      }
  
@@ -979,13 +427,13 @@
 +    //     return new CollectionStore(new ArrayList());
 +    // }
  }
-diff -Naur bcpkix-jdk15on-149.orig/org/bouncycastle/cms/CMSUtils.java bcpkix-jdk15on-149/org/bouncycastle/cms/CMSUtils.java
---- bcpkix-jdk15on-149.orig/org/bouncycastle/cms/CMSUtils.java	2013-05-31 21:17:22.000000000 +0000
-+++ bcpkix-jdk15on-149/org/bouncycastle/cms/CMSUtils.java	2013-05-25 02:14:15.000000000 +0000
-@@ -30,9 +30,11 @@
+diff -Naur bcpkix-jdk15on-150.orig/org/bouncycastle/cms/CMSUtils.java bcpkix-jdk15on-150/org/bouncycastle/cms/CMSUtils.java
+--- bcpkix-jdk15on-150.orig/org/bouncycastle/cms/CMSUtils.java	2013-12-03 20:18:54.000000000 +0000
++++ bcpkix-jdk15on-150/org/bouncycastle/cms/CMSUtils.java	2013-12-12 00:35:05.000000000 +0000
+@@ -19,9 +19,11 @@
+ import org.bouncycastle.asn1.DERTaggedObject;
  import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
  import org.bouncycastle.asn1.cms.ContentInfo;
- import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
 -import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat;
 -import org.bouncycastle.asn1.ocsp.OCSPResponse;
 -import org.bouncycastle.asn1.ocsp.OCSPResponseStatus;
@@ -994,10 +442,10 @@
 +// import org.bouncycastle.asn1.ocsp.OCSPResponse;
 +// import org.bouncycastle.asn1.ocsp.OCSPResponseStatus;
 +// END android-removed
- import org.bouncycastle.asn1.x509.Certificate;
- import org.bouncycastle.asn1.x509.CertificateList;
- import org.bouncycastle.asn1.x509.TBSCertificate;
-@@ -189,29 +191,31 @@
+ import org.bouncycastle.cert.X509AttributeCertificateHolder;
+ import org.bouncycastle.cert.X509CRLHolder;
+ import org.bouncycastle.cert.X509CertificateHolder;
+@@ -116,29 +118,31 @@
          }
      }
  
@@ -1052,9 +500,9 @@
  
      static ASN1Set createBerSetFromList(List derObjects)
      {
-diff -Naur bcpkix-jdk15on-149.orig/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java bcpkix-jdk15on-149/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java
---- bcpkix-jdk15on-149.orig/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java	2013-05-31 21:17:22.000000000 +0000
-+++ bcpkix-jdk15on-149/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java	2012-09-17 23:04:47.000000000 +0000
+diff -Naur bcpkix-jdk15on-150.orig/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java bcpkix-jdk15on-150/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java
+--- bcpkix-jdk15on-150.orig/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java	2013-12-03 20:18:54.000000000 +0000
++++ bcpkix-jdk15on-150/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java	2013-09-26 18:06:21.000000000 +0000
 @@ -4,7 +4,9 @@
  import java.util.Map;
  
@@ -1066,15 +514,7 @@
  import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
  import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
-@@ -28,31 +30,43 @@
- 
-     public DefaultCMSSignatureAlgorithmNameGenerator()
-     {
--        addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA");
-+        // BEGIN android-removed
-+        // addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA");
-+        // END android-removed
-         addEntries(NISTObjectIdentifiers.dsa_with_sha256, "SHA256", "DSA");
+@@ -33,12 +35,16 @@
          addEntries(NISTObjectIdentifiers.dsa_with_sha384, "SHA384", "DSA");
          addEntries(NISTObjectIdentifiers.dsa_with_sha512, "SHA512", "DSA");
          addEntries(OIWObjectIdentifiers.dsaWithSHA1, "SHA1", "DSA");
@@ -1094,31 +534,8 @@
 +        // END android-removed
          addEntries(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5", "RSA");
          addEntries(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1", "RSA");
--        addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
-+        // BEGIN android-removed
-+        // addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
-+        // END android-removed
-         addEntries(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256", "RSA");
-         addEntries(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384", "RSA");
-         addEntries(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512", "RSA");
-         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1", "ECDSA");
--        addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA");
-+        // BEGIN android-removed
-+        // addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA");
-+        // END android-removed
-         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256", "ECDSA");
-         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384", "ECDSA");
-         addEntries(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512", "ECDSA");
-         addEntries(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1", "DSA");
-         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1", "ECDSA");
--        addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
-+        // BEGIN android-removed
-+        // addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
-+        // END android-removed
-         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256", "ECDSA");
-         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384", "ECDSA");
-         addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512", "ECDSA");
-@@ -66,26 +80,32 @@
+         addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
+@@ -66,26 +72,30 @@
          encryptionAlgs.put(TeleTrusTObjectIdentifiers.teleTrusTRSAsignatureAlgorithm, "RSA");
          encryptionAlgs.put(X509ObjectIdentifiers.id_ea_rsa, "RSA");
          encryptionAlgs.put(PKCSObjectIdentifiers.id_RSASSA_PSS, "RSAandMGF1");
@@ -1144,10 +561,7 @@
 +        // END android-removed
          digestAlgs.put(PKCSObjectIdentifiers.md5, "MD5");
          digestAlgs.put(OIWObjectIdentifiers.idSHA1, "SHA1");
--        digestAlgs.put(NISTObjectIdentifiers.id_sha224, "SHA224");
-+        // BEGIN android-removed
-+        // digestAlgs.put(NISTObjectIdentifiers.id_sha224, "SHA224");
-+        // END android-removed
+         digestAlgs.put(NISTObjectIdentifiers.id_sha224, "SHA224");
          digestAlgs.put(NISTObjectIdentifiers.id_sha256, "SHA256");
          digestAlgs.put(NISTObjectIdentifiers.id_sha384, "SHA384");
          digestAlgs.put(NISTObjectIdentifiers.id_sha512, "SHA512");
@@ -1166,10 +580,10 @@
      }
  
      /**
-diff -Naur bcpkix-jdk15on-149.orig/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java bcpkix-jdk15on-149/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java
---- bcpkix-jdk15on-149.orig/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java	2013-05-31 21:17:22.000000000 +0000
-+++ bcpkix-jdk15on-149/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java	2012-09-17 23:04:47.000000000 +0000
-@@ -16,21 +16,29 @@
+diff -Naur bcpkix-jdk15on-150.orig/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java bcpkix-jdk15on-150/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java
+--- bcpkix-jdk15on-150.orig/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java	2013-12-03 20:18:54.000000000 +0000
++++ bcpkix-jdk15on-150/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java	2013-09-26 18:06:21.000000000 +0000
+@@ -16,21 +16,27 @@
  
      static
      {
@@ -1181,10 +595,7 @@
 +        // END android-removed
          RSA_PKCS1d5.add(PKCSObjectIdentifiers.md5WithRSAEncryption);
          RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha1WithRSAEncryption);
--        RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
-+        // BEGIN android-removed
-+        // RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
-+        // END android-removed
+         RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
          RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha256WithRSAEncryption);
          RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha384WithRSAEncryption);
          RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha512WithRSAEncryption);
@@ -1207,9 +618,9 @@
      }
  
      public AlgorithmIdentifier findEncryptionAlgorithm(AlgorithmIdentifier signatureAlgorithm)
-diff -Naur bcpkix-jdk15on-149.orig/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java bcpkix-jdk15on-149/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
---- bcpkix-jdk15on-149.orig/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java	2013-05-31 21:17:22.000000000 +0000
-+++ bcpkix-jdk15on-149/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcpkix-jdk15on-150.orig/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java bcpkix-jdk15on-150/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
+--- bcpkix-jdk15on-150.orig/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java	2013-12-03 20:18:54.000000000 +0000
++++ bcpkix-jdk15on-150/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java	2013-09-26 18:06:21.000000000 +0000
 @@ -5,7 +5,9 @@
  
  import org.bouncycastle.asn1.ASN1ObjectIdentifier;
@@ -1221,7 +632,7 @@
  import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-@@ -25,53 +27,71 @@
+@@ -25,16 +27,20 @@
          //
          // digests
          //
@@ -1233,10 +644,7 @@
 +        // END android-removed
          digestOids.put(OIWObjectIdentifiers.sha1WithRSA, OIWObjectIdentifiers.idSHA1);
  
--        digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
-+        // BEGIN android-removed
-+        // digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
-+        // END android-removed
+         digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
          digestOids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256);
          digestOids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384);
          digestOids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512);
@@ -1249,21 +657,7 @@
          digestOids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, PKCSObjectIdentifiers.md5);
          digestOids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, OIWObjectIdentifiers.idSHA1);
  
-         digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, OIWObjectIdentifiers.idSHA1);
--        digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, NISTObjectIdentifiers.id_sha224);
-+        // BEGIN android-removed
-+        // digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, NISTObjectIdentifiers.id_sha224);
-+        // END android-removed
-         digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, NISTObjectIdentifiers.id_sha256);
-         digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, NISTObjectIdentifiers.id_sha384);
-         digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, NISTObjectIdentifiers.id_sha512);
-         digestOids.put(X9ObjectIdentifiers.id_dsa_with_sha1, OIWObjectIdentifiers.idSHA1);
- 
--        digestOids.put(NISTObjectIdentifiers.dsa_with_sha224, NISTObjectIdentifiers.id_sha224);
-+        // BEGIN android-removed
-+        // digestOids.put(NISTObjectIdentifiers.dsa_with_sha224, NISTObjectIdentifiers.id_sha224);
-+        // END android-removed
-         digestOids.put(NISTObjectIdentifiers.dsa_with_sha256, NISTObjectIdentifiers.id_sha256);
+@@ -50,12 +56,14 @@
          digestOids.put(NISTObjectIdentifiers.dsa_with_sha384, NISTObjectIdentifiers.id_sha384);
          digestOids.put(NISTObjectIdentifiers.dsa_with_sha512, NISTObjectIdentifiers.id_sha512);
  
@@ -1283,11 +677,8 @@
 +        // END android-removed
  
          digestNameToOids.put("SHA-1", OIWObjectIdentifiers.idSHA1);
--        digestNameToOids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
-+        // BEGIN android-removed
-+        // digestNameToOids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
-+        // END android-removed
-         digestNameToOids.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+         digestNameToOids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+@@ -63,15 +71,19 @@
          digestNameToOids.put("SHA-384", NISTObjectIdentifiers.id_sha384);
          digestNameToOids.put("SHA-512", NISTObjectIdentifiers.id_sha512);
  
@@ -1314,9 +705,9 @@
      }
  
      public AlgorithmIdentifier find(AlgorithmIdentifier sigAlgId)
-diff -Naur bcpkix-jdk15on-149.orig/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java bcpkix-jdk15on-149/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
---- bcpkix-jdk15on-149.orig/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java	2013-05-31 21:17:22.000000000 +0000
-+++ bcpkix-jdk15on-149/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcpkix-jdk15on-150.orig/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java bcpkix-jdk15on-150/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
+--- bcpkix-jdk15on-150.orig/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java	2013-12-03 20:18:54.000000000 +0000
++++ bcpkix-jdk15on-150/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java	2013-09-26 18:06:21.000000000 +0000
 @@ -9,7 +9,9 @@
  import org.bouncycastle.asn1.ASN1Integer;
  import org.bouncycastle.asn1.ASN1ObjectIdentifier;
@@ -1328,7 +719,7 @@
  import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-@@ -32,19 +34,25 @@
+@@ -32,13 +34,17 @@
      private static final ASN1ObjectIdentifier ENCRYPTION_DSA = X9ObjectIdentifiers.id_dsa_with_sha1;
      private static final ASN1ObjectIdentifier ENCRYPTION_ECDSA = X9ObjectIdentifiers.ecdsa_with_SHA1;
      private static final ASN1ObjectIdentifier ENCRYPTION_RSA_PSS = PKCSObjectIdentifiers.id_RSASSA_PSS;
@@ -1350,24 +741,7 @@
          algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
          algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
          algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
-         algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
--        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
--        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-+        // 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);
-@@ -52,45 +60,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
+@@ -56,12 +62,14 @@
          algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
          algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
          algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
@@ -1387,19 +761,8 @@
 +        // 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("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+@@ -74,11 +82,13 @@
          algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
          algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
          algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
@@ -1418,25 +781,7 @@
                 
          //
          // 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);
-@@ -98,20 +120,26 @@
+@@ -98,8 +108,10 @@
          //
          // RFC 4491
          //
@@ -1449,12 +794,7 @@
  
          //
          // PKCS 1.5 encrypted  algorithms
-         //
-         pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha1WithRSAEncryption);
--        pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
-+        // BEGIN android-removed
-+        // pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
-+        // END android-removed
+@@ -109,9 +121,11 @@
          pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha256WithRSAEncryption);
          pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha384WithRSAEncryption);
          pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha512WithRSAEncryption);
@@ -1469,27 +809,7 @@
  
          //
          // explicit params
-@@ -119,8 +147,10 @@
-         AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
-         params.put("SHA1WITHRSAANDMGF1", createPSSParams(sha1AlgId, 20));
- 
--        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
--        params.put("SHA224WITHRSAANDMGF1", createPSSParams(sha224AlgId, 28));
-+        // BEGIN android-removed
-+        // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
-+        // params.put("SHA224WITHRSAANDMGF1", createPSSParams(sha224AlgId, 28));
-+        // END android-removed
- 
-         AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
-         params.put("SHA256WITHRSAANDMGF1", createPSSParams(sha256AlgId, 32));
-@@ -134,19 +164,25 @@
-         //
-         // digests
-         //
--        digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
-+        // BEGIN android-removed
-+        // digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
-+        // END android-removed
+@@ -138,15 +152,19 @@
          digestOids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256);
          digestOids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384);
          digestOids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512);
@@ -1516,10 +836,10 @@
      }
  
      private static AlgorithmIdentifier generate(String signatureAlgorithm)
-diff -Naur bcpkix-jdk15on-149.orig/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java bcpkix-jdk15on-149/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java
---- bcpkix-jdk15on-149.orig/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java	2013-05-31 21:17:22.000000000 +0000
-+++ bcpkix-jdk15on-149/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java	2013-05-25 02:14:15.000000000 +0000
-@@ -4,22 +4,30 @@
+diff -Naur bcpkix-jdk15on-150.orig/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java bcpkix-jdk15on-150/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java
+--- bcpkix-jdk15on-150.orig/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java	2013-12-03 20:18:54.000000000 +0000
++++ bcpkix-jdk15on-150/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java	2013-09-26 18:06:21.000000000 +0000
+@@ -4,20 +4,26 @@
  import java.util.HashMap;
  import java.util.Map;
  
@@ -1551,37 +871,9 @@
 +// import org.bouncycastle.crypto.digests.RIPEMD256Digest;
 +// END android-removed
  import org.bouncycastle.crypto.digests.SHA1Digest;
--import org.bouncycastle.crypto.digests.SHA224Digest;
-+// BEGIN android-removed
-+// import org.bouncycastle.crypto.digests.SHA224Digest;
-+// END android-removed
+ import org.bouncycastle.crypto.digests.SHA224Digest;
  import org.bouncycastle.crypto.digests.SHA256Digest;
- import org.bouncycastle.crypto.digests.SHA384Digest;
- import org.bouncycastle.crypto.digests.SHA512Digest;
-@@ -41,13 +49,15 @@
-                 return new SHA1Digest();
-             }
-         });
--        table.put(NISTObjectIdentifiers.id_sha224, new BcDigestProvider()
--        {
--            public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
--            {
--                return new SHA224Digest();
--            }
--        });
-+        // BEGIN android-removed
-+        // table.put(NISTObjectIdentifiers.id_sha224, new BcDigestProvider()
-+        // {
-+        //     public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
-+        //     {
-+        //         return new SHA224Digest();
-+        //     }
-+        // });
-+        // END android-removed
-         table.put(NISTObjectIdentifiers.id_sha256, new BcDigestProvider()
-         {
-             public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
-@@ -76,48 +86,50 @@
+@@ -76,48 +82,50 @@
                  return new MD5Digest();
              }
          });
@@ -1674,10 +966,10 @@
  
          return Collections.unmodifiableMap(table);
      }
-diff -Naur bcpkix-jdk15on-149.orig/org/bouncycastle/operator/jcajce/OperatorHelper.java bcpkix-jdk15on-149/org/bouncycastle/operator/jcajce/OperatorHelper.java
---- bcpkix-jdk15on-149.orig/org/bouncycastle/operator/jcajce/OperatorHelper.java	2013-05-31 21:17:22.000000000 +0000
-+++ bcpkix-jdk15on-149/org/bouncycastle/operator/jcajce/OperatorHelper.java	2013-01-31 02:26:40.000000000 +0000
-@@ -20,7 +20,9 @@
+diff -Naur bcpkix-jdk15on-150.orig/org/bouncycastle/operator/jcajce/OperatorHelper.java bcpkix-jdk15on-150/org/bouncycastle/operator/jcajce/OperatorHelper.java
+--- bcpkix-jdk15on-150.orig/org/bouncycastle/operator/jcajce/OperatorHelper.java	2013-12-03 20:18:54.000000000 +0000
++++ bcpkix-jdk15on-150/org/bouncycastle/operator/jcajce/OperatorHelper.java	2013-12-12 00:35:05.000000000 +0000
+@@ -24,7 +24,9 @@
  import org.bouncycastle.asn1.ASN1Encodable;
  import org.bouncycastle.asn1.ASN1ObjectIdentifier;
  import org.bouncycastle.asn1.DERNull;
@@ -1688,14 +980,7 @@
  import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
  import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
  import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
-@@ -47,24 +49,34 @@
-         // reverse mappings
-         //
-         oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
--        oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
-+        // BEGIN android-removed
-+        // oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
-+        // END android-removed
+@@ -57,11 +59,15 @@
          oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
          oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
          oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
@@ -1713,40 +998,8 @@
 +        // END android-removed
          oids.put(new ASN1ObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
          oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
--        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
-+        // 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");
- 
-         oids.put(OIWObjectIdentifiers.idSHA1, "SHA-1");
-@@ -305,10 +317,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";
-@@ -321,22 +335,24 @@
+         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+@@ -362,22 +368,24 @@
          {
              return "SHA512";
          }
diff --git a/patches/bcprov.patch b/patches/bcprov.patch
index 50255e5..25de3dc 100644
--- a/patches/bcprov.patch
+++ b/patches/bcprov.patch
@@ -1,6 +1,6 @@
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/asn1/ASN1Null.java bcprov-jdk15on-149/org/bouncycastle/asn1/ASN1Null.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/asn1/ASN1Null.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/asn1/ASN1Null.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/ASN1Null.java bcprov-jdk15on-150/org/bouncycastle/asn1/ASN1Null.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/ASN1Null.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/ASN1Null.java	2013-01-31 02:26:40.000000000 +0000
 @@ -11,9 +11,11 @@
      /**
       * @deprecated use DERNull.INSTANCE
@@ -14,9 +14,9 @@
  
      public static ASN1Null getInstance(Object o)
      {
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/asn1/DERBoolean.java bcprov-jdk15on-149/org/bouncycastle/asn1/DERBoolean.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/asn1/DERBoolean.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/asn1/DERBoolean.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/DERBoolean.java bcprov-jdk15on-150/org/bouncycastle/asn1/DERBoolean.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/DERBoolean.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/DERBoolean.java	2013-12-12 00:35:05.000000000 +0000
 @@ -10,7 +10,9 @@
      private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };
      private static final byte[] FALSE_VALUE = new byte[] { 0 };
@@ -69,9 +69,9 @@
      {
          this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
      }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/asn1/DERNull.java bcprov-jdk15on-149/org/bouncycastle/asn1/DERNull.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/asn1/DERNull.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/asn1/DERNull.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/DERNull.java bcprov-jdk15on-150/org/bouncycastle/asn1/DERNull.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/DERNull.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/DERNull.java	2013-01-31 02:26:40.000000000 +0000
 @@ -15,7 +15,9 @@
      /**
       * @deprecated use DERNull.INSTANCE
@@ -83,10 +83,10 @@
      {
      }
  
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/asn1/DERObjectIdentifier.java bcprov-jdk15on-149/org/bouncycastle/asn1/DERObjectIdentifier.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/asn1/DERObjectIdentifier.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/asn1/DERObjectIdentifier.java	2013-05-25 02:14:15.000000000 +0000
-@@ -144,7 +144,13 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/DERObjectIdentifier.java bcprov-jdk15on-150/org/bouncycastle/asn1/DERObjectIdentifier.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/DERObjectIdentifier.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/DERObjectIdentifier.java	2013-12-12 00:35:05.000000000 +0000
+@@ -162,7 +162,13 @@
              }
          }
  
@@ -101,7 +101,7 @@
          this.body = Arrays.clone(bytes);
      }
  
-@@ -160,7 +166,13 @@
+@@ -181,7 +187,13 @@
              throw new IllegalArgumentException("string " + identifier + " not an OID");
          }
  
@@ -116,9 +116,9 @@
      }
  
      DERObjectIdentifier(DERObjectIdentifier oid, String branchID)
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/asn1/DERPrintableString.java bcprov-jdk15on-149/org/bouncycastle/asn1/DERPrintableString.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/asn1/DERPrintableString.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/asn1/DERPrintableString.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/DERPrintableString.java bcprov-jdk15on-150/org/bouncycastle/asn1/DERPrintableString.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/DERPrintableString.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/DERPrintableString.java	2013-01-31 02:26:40.000000000 +0000
 @@ -12,7 +12,9 @@
      extends ASN1Primitive
      implements ASN1String
@@ -130,11 +130,11 @@
  
      /**
       * return a printable string from the passed in object.
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/asn1/cms/ContentInfo.java bcprov-jdk15on-149/org/bouncycastle/asn1/cms/ContentInfo.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/asn1/cms/ContentInfo.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/asn1/cms/ContentInfo.java	2013-05-25 02:14:15.000000000 +0000
-@@ -12,7 +12,9 @@
- 
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/cms/ContentInfo.java bcprov-jdk15on-150/org/bouncycastle/asn1/cms/ContentInfo.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/cms/ContentInfo.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/cms/ContentInfo.java	2013-12-12 00:35:05.000000000 +0000
+@@ -28,7 +28,9 @@
+  */
  public class ContentInfo
      extends ASN1Object
 -    implements CMSObjectIdentifiers
@@ -144,39 +144,34 @@
  {
      private ASN1ObjectIdentifier contentType;
      private ASN1Encodable        content;
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java bcprov-jdk15on-149/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2013-01-31 02:26:40.000000000 +0000
-@@ -10,8 +10,10 @@
-     //
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java bcprov-jdk15on-150/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java	2013-12-12 00:35:05.000000000 +0000
+@@ -13,10 +13,12 @@
      static final ASN1ObjectIdentifier    pkcs_1                    = new ASN1ObjectIdentifier("1.2.840.113549.1.1");
+     /** PKCS#1: 1.2.840.113549.1.1.1 */
      static final ASN1ObjectIdentifier    rsaEncryption             = pkcs_1.branch("1");
+-    /** PKCS#1: 1.2.840.113549.1.1.2 */
 -    static final ASN1ObjectIdentifier    md2WithRSAEncryption      = pkcs_1.branch("2");
+-    /** PKCS#1: 1.2.840.113549.1.1.3 */
 -    static final ASN1ObjectIdentifier    md4WithRSAEncryption      = pkcs_1.branch("3");
 +    // BEGIN android-removed
++    // /** PKCS#1: 1.2.840.113549.1.1.2 */
 +    // static final ASN1ObjectIdentifier    md2WithRSAEncryption      = pkcs_1.branch("2");
++    // /** PKCS#1: 1.2.840.113549.1.1.3 */
 +    // static final ASN1ObjectIdentifier    md4WithRSAEncryption      = pkcs_1.branch("3");
 +    // END android-removed
+     /** PKCS#1: 1.2.840.113549.1.1.4 */
      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 ::= {
-@@ -66,13 +70,17 @@
+     /** PKCS#1: 1.2.840.113549.1.1.5 */
+@@ -96,15 +98,19 @@
      // md2 OBJECT IDENTIFIER ::=
      //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2}
      //
+-    /**  1.2.840.113549.2.2 */
 -    static final ASN1ObjectIdentifier    md2                    = digestAlgorithm.branch("2");
 +    // BEGIN android-removed
++    // /**  1.2.840.113549.2.2 */
 +    // static final ASN1ObjectIdentifier    md2                    = digestAlgorithm.branch("2");
 +    // END android-removed
  
@@ -184,27 +179,18 @@
      // md4 OBJECT IDENTIFIER ::=
      //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4}
      //
--    static final ASN1ObjectIdentifier    md4 = digestAlgorithm.branch("4");
+-    /**  1.2.840.113549.2.4 */
+-    static final ASN1ObjectIdentifier    md4                    = digestAlgorithm.branch("4");
 +    // BEGIN android-removed
-+    // static final ASN1ObjectIdentifier    md4 = digestAlgorithm.branch("4");
++    // /**  1.2.840.113549.2.4 */
++    // static final ASN1ObjectIdentifier    md4                    = digestAlgorithm.branch("4");
 +    // END android-removed
  
      //
      // md5 OBJECT IDENTIFIER ::=
-@@ -81,7 +89,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-jdk15on-149.orig/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java bcprov-jdk15on-149/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java bcprov-jdk15on-150/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java	2013-05-25 02:14:15.000000000 +0000
 @@ -14,7 +14,9 @@
  import org.bouncycastle.asn1.DERSequence;
  import org.bouncycastle.asn1.DERTaggedObject;
@@ -238,9 +224,9 @@
          byte[]  resBuf = new byte[digest.getDigestSize()];
  
          byte[] bytes = spki.getPublicKeyData().getBytes();
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java bcprov-jdk15on-149/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java bcprov-jdk15on-150/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java	2013-01-31 02:26:40.000000000 +0000
 @@ -6,7 +6,9 @@
  import org.bouncycastle.asn1.ASN1TaggedObject;
  import org.bouncycastle.asn1.DEROctetString;
@@ -263,9 +249,9 @@
          byte[]  resBuf = new byte[digest.getDigestSize()];
  
          byte[] bytes = spki.getPublicKeyData().getBytes();
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/asn1/x509/X509Name.java bcprov-jdk15on-149/org/bouncycastle/asn1/x509/X509Name.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/asn1/x509/X509Name.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/asn1/x509/X509Name.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/x509/X509Name.java bcprov-jdk15on-150/org/bouncycastle/asn1/x509/X509Name.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/x509/X509Name.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/x509/X509Name.java	2013-12-12 00:35:05.000000000 +0000
 @@ -255,8 +255,10 @@
       */
      public static final Hashtable SymbolLookUp = DefaultLookUp;
@@ -290,9 +276,9 @@
              }
          }
      }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java bcprov-jdk15on-149/org/bouncycastle/asn1/x509/X509NameTokenizer.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java bcprov-jdk15on-150/org/bouncycastle/asn1/x509/X509NameTokenizer.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/x509/X509NameTokenizer.java	2013-05-25 02:14:15.000000000 +0000
 @@ -78,6 +78,17 @@
                  }
                  else
@@ -311,10 +297,69 @@
                      buf.append(c);
                  }
              }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/digests/AndroidDigestFactory.java bcprov-jdk15on-149/org/bouncycastle/crypto/digests/AndroidDigestFactory.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/digests/AndroidDigestFactory.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/digests/AndroidDigestFactory.java	2013-05-01 01:48:41.000000000 +0000
-@@ -0,0 +1,83 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/asn1/x9/ECNamedCurveTable.java bcprov-jdk15on-150/org/bouncycastle/asn1/x9/ECNamedCurveTable.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/asn1/x9/ECNamedCurveTable.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/asn1/x9/ECNamedCurveTable.java	2013-12-12 00:35:05.000000000 +0000
+@@ -6,7 +6,9 @@
+ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+ 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
+ 
+ /**
+  * A general class that reads all X9.62 style EC curve tables.
+@@ -30,10 +32,12 @@
+             ecP = SECNamedCurves.getByName(name);
+         }
+ 
+-        if (ecP == null)
+-        {
+-            ecP = TeleTrusTNamedCurves.getByName(name);
+-        }
++        // BEGIN android-removed
++        // if (ecP == null)
++        // {
++        //     ecP = TeleTrusTNamedCurves.getByName(name);
++        // }
++        // END android-removed
+ 
+         if (ecP == null)
+         {
+@@ -60,10 +64,12 @@
+             ecP = SECNamedCurves.getByOID(oid);
+         }
+ 
+-        if (ecP == null)
+-        {
+-            ecP = TeleTrusTNamedCurves.getByOID(oid);
+-        }
++        // BEGIN android-removed
++        // if (ecP == null)
++        // {
++        //     ecP = TeleTrusTNamedCurves.getByOID(oid);
++        // }
++        // END android-removed
+ 
+         // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup
+ 
+@@ -82,7 +88,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-jdk15on-150.orig/org/bouncycastle/crypto/digests/AndroidDigestFactory.java bcprov-jdk15on-150/org/bouncycastle/crypto/digests/AndroidDigestFactory.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/digests/AndroidDigestFactory.java	1970-01-01 00:00:00.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/digests/AndroidDigestFactory.java	2013-09-26 18:06:21.000000000 +0000
+@@ -0,0 +1,87 @@
 +/*
 + * Copyright (C) 2012 The Android Open Source Project
 + *
@@ -386,6 +431,10 @@
 +        return FACTORY.getSHA1();
 +    }
 +
++    public static Digest getSHA224() {
++        return FACTORY.getSHA224();
++    }
++
 +    public static Digest getSHA256() {
 +        return FACTORY.getSHA256();
 +    }
@@ -398,10 +447,10 @@
 +        return FACTORY.getSHA512();
 +    }
 +}
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java bcprov-jdk15on-149/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java	2012-09-17 23:04:47.000000000 +0000
-@@ -0,0 +1,37 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java bcprov-jdk15on-150/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java	1970-01-01 00:00:00.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java	2013-09-26 18:06:21.000000000 +0000
+@@ -0,0 +1,40 @@
 +/*
 + * Copyright (C) 2012 The Android Open Source Project
 + *
@@ -429,6 +478,9 @@
 +    public Digest getSHA1() {
 +        return new SHA1Digest();
 +    }
++    public Digest getSHA224() {
++        return new SHA224Digest();
++    }
 +    public Digest getSHA256() {
 +        return new SHA256Digest();
 +    }
@@ -439,10 +491,10 @@
 +        return new SHA512Digest();
 +    }
 +}
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java bcprov-jdk15on-149/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java	2012-09-17 23:04:47.000000000 +0000
-@@ -0,0 +1,27 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java bcprov-jdk15on-150/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java	1970-01-01 00:00:00.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java	2013-09-26 18:06:21.000000000 +0000
+@@ -0,0 +1,28 @@
 +/*
 + * Copyright (C) 2012 The Android Open Source Project
 + *
@@ -466,14 +518,15 @@
 +interface AndroidDigestFactoryInterface {
 +    public Digest getMD5();
 +    public Digest getSHA1();
++    public Digest getSHA224();
 +    public Digest getSHA256();
 +    public Digest getSHA384();
 +    public Digest getSHA512();
 +}
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java bcprov-jdk15on-149/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java	2012-09-17 23:04:47.000000000 +0000
-@@ -0,0 +1,37 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java bcprov-jdk15on-150/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java	1970-01-01 00:00:00.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java	2013-09-26 18:06:21.000000000 +0000
+@@ -0,0 +1,40 @@
 +/*
 + * Copyright (C) 2012 The Android Open Source Project
 + *
@@ -501,6 +554,9 @@
 +    public Digest getSHA1() {
 +        return new OpenSSLDigest.SHA1();
 +    }
++    public Digest getSHA224() {
++        return new OpenSSLDigest.SHA224();
++    }
 +    public Digest getSHA256() {
 +        return new OpenSSLDigest.SHA256();
 +    }
@@ -511,10 +567,10 @@
 +        return new OpenSSLDigest.SHA512();
 +    }
 +}
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java bcprov-jdk15on-149/org/bouncycastle/crypto/digests/OpenSSLDigest.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/digests/OpenSSLDigest.java	2013-04-24 05:37:59.000000000 +0000
-@@ -0,0 +1,159 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java bcprov-jdk15on-150/org/bouncycastle/crypto/digests/OpenSSLDigest.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/digests/OpenSSLDigest.java	1970-01-01 00:00:00.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/digests/OpenSSLDigest.java	2013-09-26 18:06:21.000000000 +0000
+@@ -0,0 +1,166 @@
 +/*
 + * Copyright (C) 2008 The Android Open Source Project
 + *
@@ -653,6 +709,13 @@
 +        public SHA1() { super("SHA-1", EVP_MD, SIZE, BLOCK_SIZE); }
 +    }
 +
++    public static class SHA224 extends OpenSSLDigest {
++        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha224");
++        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
++        private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
++        public SHA224() { super("SHA-224", EVP_MD, SIZE, BLOCK_SIZE); }
++    }
++
 +    public static class SHA256 extends OpenSSLDigest {
 +        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256");
 +        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
@@ -674,9 +737,9 @@
 +        public SHA512() { super("SHA-512", EVP_MD, SIZE, BLOCK_SIZE); }
 +    }
 +}
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/encodings/OAEPEncoding.java bcprov-jdk15on-149/org/bouncycastle/crypto/encodings/OAEPEncoding.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/encodings/OAEPEncoding.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/encodings/OAEPEncoding.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/encodings/OAEPEncoding.java bcprov-jdk15on-150/org/bouncycastle/crypto/encodings/OAEPEncoding.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/encodings/OAEPEncoding.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/encodings/OAEPEncoding.java	2013-05-25 02:14:15.000000000 +0000
 @@ -6,7 +6,9 @@
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.Digest;
@@ -699,9 +762,9 @@
      }
      
      public OAEPEncoding(
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/encodings/PKCS1Encoding.java bcprov-jdk15on-149/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/encodings/PKCS1Encoding.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/encodings/PKCS1Encoding.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/encodings/PKCS1Encoding.java bcprov-jdk15on-150/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/encodings/PKCS1Encoding.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/encodings/PKCS1Encoding.java	2013-01-31 02:26:40.000000000 +0000
 @@ -216,6 +216,12 @@
                  throw new InvalidCipherTextException("unknown block type");
              }
@@ -715,9 +778,9 @@
  
          if (useStrictLength && block.length != engine.getOutputBlockSize())
          {
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/engines/DESedeWrapEngine.java bcprov-jdk15on-149/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/engines/DESedeWrapEngine.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/engines/DESedeWrapEngine.java	2012-09-17 23:04:47.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/engines/DESedeWrapEngine.java bcprov-jdk15on-150/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/engines/DESedeWrapEngine.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/engines/DESedeWrapEngine.java	2012-09-17 23:04:47.000000000 +0000
 @@ -6,7 +6,9 @@
  import org.bouncycastle.crypto.Digest;
  import org.bouncycastle.crypto.InvalidCipherTextException;
@@ -740,9 +803,9 @@
      byte[]  digest = new byte[20];
  
     /**
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/generators/DHParametersHelper.java bcprov-jdk15on-149/org/bouncycastle/crypto/generators/DHParametersHelper.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/generators/DHParametersHelper.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/generators/DHParametersHelper.java	2012-09-17 23:04:47.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/generators/DHParametersHelper.java bcprov-jdk15on-150/org/bouncycastle/crypto/generators/DHParametersHelper.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/generators/DHParametersHelper.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/generators/DHParametersHelper.java	2012-09-17 23:04:47.000000000 +0000
 @@ -3,10 +3,17 @@
  import java.math.BigInteger;
  import java.security.SecureRandom;
@@ -793,9 +856,9 @@
  
          return new BigInteger[] { p, q };
      }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/generators/DSAParametersGenerator.java bcprov-jdk15on-149/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/generators/DSAParametersGenerator.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/generators/DSAParametersGenerator.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/generators/DSAParametersGenerator.java bcprov-jdk15on-150/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/generators/DSAParametersGenerator.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/generators/DSAParametersGenerator.java	2013-12-12 00:35:05.000000000 +0000
 @@ -4,7 +4,9 @@
  import java.security.SecureRandom;
  
@@ -829,9 +892,9 @@
          {
              throw new IllegalStateException("can only use SHA-1 for generating FIPS 186-2 parameters");
          }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java bcprov-jdk15on-149/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java	2012-09-17 23:04:47.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java bcprov-jdk15on-150/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java	2012-09-17 23:04:47.000000000 +0000
 @@ -3,7 +3,9 @@
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.Digest;
@@ -854,9 +917,9 @@
  
      /**
       * Construct a OpenSSL Parameters generator. 
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java bcprov-jdk15on-149/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java bcprov-jdk15on-150/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java	2013-12-12 00:35:05.000000000 +0000
 @@ -4,7 +4,9 @@
  import org.bouncycastle.crypto.Digest;
  import org.bouncycastle.crypto.Mac;
@@ -879,10 +942,10 @@
      }
  
      public PKCS5S2ParametersGenerator(Digest digest)
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/macs/HMac.java bcprov-jdk15on-149/org/bouncycastle/crypto/macs/HMac.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/macs/HMac.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/macs/HMac.java	2013-05-25 02:14:15.000000000 +0000
-@@ -36,23 +36,31 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/macs/HMac.java bcprov-jdk15on-150/org/bouncycastle/crypto/macs/HMac.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/macs/HMac.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/macs/HMac.java	2013-09-26 18:06:21.000000000 +0000
+@@ -36,14 +36,18 @@
      {
          blockLengths = new Hashtable();
          
@@ -906,11 +969,8 @@
 +        // END android-removed
          
          blockLengths.put("SHA-1", Integers.valueOf(64));
--        blockLengths.put("SHA-224", Integers.valueOf(64));
-+        // BEGIN android-removed
-+        // blockLengths.put("SHA-224", Integers.valueOf(64));
-+        // END android-removed
-         blockLengths.put("SHA-256", Integers.valueOf(64));
+         blockLengths.put("SHA-224", Integers.valueOf(64));
+@@ -51,8 +55,10 @@
          blockLengths.put("SHA-384", Integers.valueOf(128));
          blockLengths.put("SHA-512", Integers.valueOf(128));
          
@@ -923,88 +983,10 @@
      }
      
      private static int getByteLength(
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/modes/GCMBlockCipher.java bcprov-jdk15on-149/org/bouncycastle/crypto/modes/GCMBlockCipher.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/modes/GCMBlockCipher.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/modes/GCMBlockCipher.java	2015-11-12 22:10:47.000000000 +0000
-@@ -22,6 +22,11 @@
-     implements AEADBlockCipher
- {
-     private static final int BLOCK_SIZE = 16;
-+    // BEGIN android-added
-+    // 2^36-32 : limitation imposed by NIST GCM as otherwise the counter is wrapped and it can leak
-+    // plaintext and authentication key
-+    private static final long MAX_INPUT_SIZE = 68719476704L;
-+    // END android-added
- 
-     // not final due to a compiler bug 
-     private BlockCipher   cipher;
-@@ -194,6 +199,14 @@
-         return totalData < macSize ? 0 : totalData - macSize;
-     }
- 
-+    // BEGIN android-added
-+    /** Helper used to ensure that {@link #MAX_INPUT_SIZE} is not exceeded. */
-+    private long getTotalInputSizeAfterNewInput(int newInputLen)
-+    {
-+        return totalLength + newInputLen + bufOff;
-+    }
-+    // END android-added
-+
-     public int getUpdateOutputSize(int len)
-     {
-         int totalData = len + bufOff;
-@@ -210,6 +223,11 @@
- 
-     public void processAADByte(byte in)
-     {
-+        // BEGIN android-added
-+        if (getTotalInputSizeAfterNewInput(1) > MAX_INPUT_SIZE) {
-+            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
-+        }
-+        // END android-added
-         atBlock[atBlockPos] = in;
-         if (++atBlockPos == BLOCK_SIZE)
-         {
-@@ -222,6 +240,11 @@
- 
-     public void processAADBytes(byte[] in, int inOff, int len)
-     {
-+        // BEGIN android-added
-+        if (getTotalInputSizeAfterNewInput(len) > MAX_INPUT_SIZE) {
-+            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
-+        }
-+        // END android-added
-         for (int i = 0; i < len; ++i)
-         {
-             atBlock[atBlockPos] = in[inOff + i];
-@@ -259,6 +282,11 @@
-     public int processByte(byte in, byte[] out, int outOff)
-         throws DataLengthException
-     {
-+        // BEGIN android-added
-+        if (getTotalInputSizeAfterNewInput(1) > MAX_INPUT_SIZE) {
-+            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
-+        }
-+        // END android-added
-         bufBlock[bufOff] = in;
-         if (++bufOff == bufBlock.length)
-         {
-@@ -271,6 +299,11 @@
-     public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
-         throws DataLengthException
-     {
-+        // BEGIN android-added
-+        if (getTotalInputSizeAfterNewInput(len) > MAX_INPUT_SIZE) {
-+            throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes");
-+        }
-+        // END android-added
-         int resultLen = 0;
- 
-         for (int i = 0; i < len; ++i)
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java bcprov-jdk15on-149/org/bouncycastle/crypto/signers/RSADigestSigner.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/signers/RSADigestSigner.java	2012-09-17 23:04:47.000000000 +0000
-@@ -39,18 +39,24 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java bcprov-jdk15on-150/org/bouncycastle/crypto/signers/RSADigestSigner.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/signers/RSADigestSigner.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/signers/RSADigestSigner.java	2013-12-12 00:35:05.000000000 +0000
+@@ -39,9 +39,11 @@
       */
      static
      {
@@ -1018,11 +1000,8 @@
 +        // END android-removed
  
          oidMap.put("SHA-1", X509ObjectIdentifiers.id_SHA1);
--        oidMap.put("SHA-224", NISTObjectIdentifiers.id_sha224);
-+        // BEGIN android-removed
-+        // oidMap.put("SHA-224", NISTObjectIdentifiers.id_sha224);
-+        // END android-removed
-         oidMap.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+         oidMap.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+@@ -49,8 +51,10 @@
          oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384);
          oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
  
@@ -1035,13 +1014,13 @@
          oidMap.put("MD5", PKCSObjectIdentifiers.md5);
      }
  
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java bcprov-jdk15on-149/org/bouncycastle/crypto/util/PrivateKeyFactory.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2013-01-31 02:26:40.000000000 +0000
-@@ -11,7 +11,9 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java bcprov-jdk15on-150/org/bouncycastle/crypto/util/PrivateKeyFactory.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/util/PrivateKeyFactory.java	2013-12-12 00:35:05.000000000 +0000
+@@ -10,7 +10,9 @@
+ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
  import org.bouncycastle.asn1.ASN1Primitive;
  import org.bouncycastle.asn1.ASN1Sequence;
- import org.bouncycastle.asn1.nist.NISTNamedCurves;
 -import org.bouncycastle.asn1.oiw.ElGamalParameter;
 +// BEGIN android-removed
 +// import org.bouncycastle.asn1.oiw.ElGamalParameter;
@@ -1049,18 +1028,7 @@
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
  import org.bouncycastle.asn1.pkcs.DHParameter;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-@@ -19,7 +21,9 @@
- import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
- import org.bouncycastle.asn1.sec.ECPrivateKey;
- 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.x509.AlgorithmIdentifier;
- import org.bouncycastle.asn1.x509.DSAParameter;
- import org.bouncycastle.asn1.x9.X962NamedCurves;
-@@ -33,8 +37,10 @@
+@@ -30,8 +32,10 @@
  import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
  import org.bouncycastle.crypto.params.ECDomainParameters;
  import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
@@ -1073,7 +1041,7 @@
  import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
  
  /**
-@@ -100,14 +106,16 @@
+@@ -97,14 +101,16 @@
  
              return new DHPrivateKeyParameters(derX.getValue(), dhParams);
          }
@@ -1098,30 +1066,13 @@
          else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa))
          {
              ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey();
-@@ -140,10 +148,12 @@
-                     {
-                         x9 = NISTNamedCurves.getByOID(oid);
- 
--                        if (x9 == null)
--                        {
--                            x9 = TeleTrusTNamedCurves.getByOID(oid);
--                        }
-+                        // BEGIN android-removed
-+                        // if (x9 == null)
-+                        // {
-+                        //     x9 = TeleTrusTNamedCurves.getByOID(oid);
-+                        // }
-+                        // END android-removed
-                     }
-                 }
-             }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java bcprov-jdk15on-149/org/bouncycastle/crypto/util/PublicKeyFactory.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/crypto/util/PublicKeyFactory.java	2013-01-31 02:26:40.000000000 +0000
-@@ -13,13 +13,17 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java bcprov-jdk15on-150/org/bouncycastle/crypto/util/PublicKeyFactory.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/crypto/util/PublicKeyFactory.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/crypto/util/PublicKeyFactory.java	2013-12-12 00:35:05.000000000 +0000
+@@ -12,7 +12,9 @@
+ import org.bouncycastle.asn1.ASN1Primitive;
  import org.bouncycastle.asn1.ASN1Sequence;
  import org.bouncycastle.asn1.DEROctetString;
- import org.bouncycastle.asn1.nist.NISTNamedCurves;
 -import org.bouncycastle.asn1.oiw.ElGamalParameter;
 +// BEGIN android-removed
 +// import org.bouncycastle.asn1.oiw.ElGamalParameter;
@@ -1129,16 +1080,7 @@
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
  import org.bouncycastle.asn1.pkcs.DHParameter;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
- import org.bouncycastle.asn1.pkcs.RSAPublicKey;
- 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.x509.AlgorithmIdentifier;
- import org.bouncycastle.asn1.x509.DSAParameter;
- import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-@@ -40,8 +44,10 @@
+@@ -37,8 +39,10 @@
  import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
  import org.bouncycastle.crypto.params.ECDomainParameters;
  import org.bouncycastle.crypto.params.ECPublicKeyParameters;
@@ -1151,7 +1093,7 @@
  import org.bouncycastle.crypto.params.RSAKeyParameters;
  
  /**
-@@ -135,14 +141,16 @@
+@@ -132,14 +136,16 @@
  
              return new DHPublicKeyParameters(derY.getValue(), dhParams);
          }
@@ -1176,26 +1118,9 @@
          else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa)
              || algId.getAlgorithm().equals(OIWObjectIdentifiers.dsaWithSHA1))
          {
-@@ -177,10 +185,12 @@
-                     {
-                         x9 = NISTNamedCurves.getByOID(oid);
- 
--                        if (x9 == null)
--                        {
--                            x9 = TeleTrusTNamedCurves.getByOID(oid);
--                        }
-+                        // BEGIN android-removed
-+                        // if (x9 == null)
-+                        // {
-+                        //     x9 = TeleTrusTNamedCurves.getByOID(oid);
-+                        // }
-+                        // END android-removed
-                     }
-                 }
-             }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/DH.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/DH.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/DH.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/DH.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/DH.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/DH.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/DH.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/DH.java	2013-05-25 02:14:15.000000000 +0000
 @@ -32,10 +32,12 @@
  
              provider.addAlgorithm("AlgorithmParameterGenerator.DH", PREFIX + "AlgorithmParameterGeneratorSpi");
@@ -1213,10 +1138,10 @@
          }
      }
  }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/DSA.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/DSA.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/DSA.java	2013-01-31 02:26:40.000000000 +0000
-@@ -27,33 +27,43 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/DSA.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/DSA.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/DSA.java	2013-12-16 16:39:58.000000000 +0000
+@@ -27,40 +27,53 @@
              provider.addAlgorithm("KeyPairGenerator.DSA", PREFIX + "KeyPairGeneratorSpi");
              provider.addAlgorithm("KeyFactory.DSA", PREFIX + "KeyFactorySpi");
  
@@ -1228,23 +1153,26 @@
  
              provider.addAlgorithm("Alg.Alias.Signature.RAWDSA", "NONEWITHDSA");
  
--            addSignatureAlgorithm(provider, "SHA224", "DSA", PREFIX + "DSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
--            addSignatureAlgorithm(provider, "SHA256", "DSA", PREFIX + "DSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
+-            provider.addAlgorithm("Signature.DETDSA", PREFIX + "DSASigner$detDSA");
+-            provider.addAlgorithm("Signature.SHA1WITHDETDSA", PREFIX + "DSASigner$detDSA");
+-            provider.addAlgorithm("Signature.SHA224WITHDETDSA", PREFIX + "DSASigner$detDSA224");
+-            provider.addAlgorithm("Signature.SHA256WITHDETDSA", PREFIX + "DSASigner$detDSA256");
+-            provider.addAlgorithm("Signature.SHA384WITHDETDSA", PREFIX + "DSASigner$detDSA384");
+-            provider.addAlgorithm("Signature.SHA512WITHDETDSA", PREFIX + "DSASigner$detDSA512");
++            // BEGIN android-removed
++            // provider.addAlgorithm("Signature.DETDSA", PREFIX + "DSASigner$detDSA");
++            // provider.addAlgorithm("Signature.SHA1WITHDETDSA", PREFIX + "DSASigner$detDSA");
++            // provider.addAlgorithm("Signature.SHA224WITHDETDSA", PREFIX + "DSASigner$detDSA224");
++            // provider.addAlgorithm("Signature.SHA256WITHDETDSA", PREFIX + "DSASigner$detDSA256");
++            // provider.addAlgorithm("Signature.SHA384WITHDETDSA", PREFIX + "DSASigner$detDSA384");
++            // provider.addAlgorithm("Signature.SHA512WITHDETDSA", PREFIX + "DSASigner$detDSA512");
++            // END android-removed
+ 
+             addSignatureAlgorithm(provider, "SHA224", "DSA", PREFIX + "DSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
+             addSignatureAlgorithm(provider, "SHA256", "DSA", PREFIX + "DSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
 -            addSignatureAlgorithm(provider, "SHA384", "DSA", PREFIX + "DSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384);
 -            addSignatureAlgorithm(provider, "SHA512", "DSA", PREFIX + "DSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512);
--
--            provider.addAlgorithm("Alg.Alias.Signature.SHA/DSA", "DSA");
--            provider.addAlgorithm("Alg.Alias.Signature.SHA1withDSA", "DSA");
--            provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDSA", "DSA");
--            provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "DSA");
--            provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "DSA");
--            provider.addAlgorithm("Alg.Alias.Signature.DSAwithSHA1", "DSA");
--            provider.addAlgorithm("Alg.Alias.Signature.DSAWITHSHA1", "DSA");
--            provider.addAlgorithm("Alg.Alias.Signature.SHA1WithDSA", "DSA");
--            provider.addAlgorithm("Alg.Alias.Signature.DSAWithSHA1", "DSA");
 +            // BEGIN android-removed
-+            // addSignatureAlgorithm(provider, "SHA224", "DSA", PREFIX + "DSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
-+            // addSignatureAlgorithm(provider, "SHA256", "DSA", PREFIX + "DSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
 +            // addSignatureAlgorithm(provider, "SHA384", "DSA", PREFIX + "DSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384);
 +            // addSignatureAlgorithm(provider, "SHA512", "DSA", PREFIX + "DSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512);
 +            // END android-removed
@@ -1254,6 +1182,7 @@
 +            // END android-added
 +            // BEGIN android-changed
 +            provider.addAlgorithm("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA");
++            provider.addAlgorithm("Alg.Alias.Signature.SHA1withDSA", "SHA1withDSA");
 +            provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDSA", "SHA1withDSA");
 +            provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "SHA1withDSA");
 +            provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA");
@@ -1262,6 +1191,16 @@
 +            provider.addAlgorithm("Alg.Alias.Signature.SHA1WithDSA", "SHA1withDSA");
 +            provider.addAlgorithm("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
  
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA/DSA", "DSA");
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA1withDSA", "DSA");
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDSA", "DSA");
+-            provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "DSA");
+-            provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "DSA");
+-            provider.addAlgorithm("Alg.Alias.Signature.DSAwithSHA1", "DSA");
+-            provider.addAlgorithm("Alg.Alias.Signature.DSAWITHSHA1", "DSA");
+-            provider.addAlgorithm("Alg.Alias.Signature.SHA1WithDSA", "DSA");
+-            provider.addAlgorithm("Alg.Alias.Signature.DSAWithSHA1", "DSA");
+-
 -            provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10040.4.3", "DSA");
 +            provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA");
 +            // END android-changed
@@ -1277,9 +1216,9 @@
  
                  registerOid(provider, DSAUtil.dsaOids[i], "DSA", keyFact);
                  registerOidAlgorithmParameters(provider, DSAUtil.dsaOids[i], "DSA");
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/EC.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/EC.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/EC.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/EC.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/EC.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/EC.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/EC.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/EC.java	2013-12-12 00:35:05.000000000 +0000
 @@ -1,7 +1,9 @@
  package org.bouncycastle.jcajce.provider.asymmetric;
  
@@ -1367,20 +1306,30 @@
  
              provider.addAlgorithm("Signature.ECDSA", PREFIX + "SignatureSpi$ecDSA");
              provider.addAlgorithm("Signature.NONEwithECDSA", PREFIX + "SignatureSpi$ecDSAnone");
-@@ -65,25 +77,31 @@
+@@ -65,32 +77,36 @@
              provider.addAlgorithm("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA");
              provider.addAlgorithm("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA");
              provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
 -            provider.addAlgorithm("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
 -
--            addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
+-            provider.addAlgorithm("Signature.DETECDSA", PREFIX + "SignatureSpi$ecDetDSA");
+-            provider.addAlgorithm("Signature.SHA1WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA");
+-            provider.addAlgorithm("Signature.SHA224WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA224");
+-            provider.addAlgorithm("Signature.SHA256WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA256");
+-            provider.addAlgorithm("Signature.SHA384WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA384");
+-            provider.addAlgorithm("Signature.SHA512WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA512");
 +            // BEGIN android-removed
 +            // provider.addAlgorithm("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
++            //
++            // provider.addAlgorithm("Signature.DETECDSA", PREFIX + "SignatureSpi$ecDetDSA");
++            // provider.addAlgorithm("Signature.SHA1WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA");
++            // provider.addAlgorithm("Signature.SHA224WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA224");
++            // provider.addAlgorithm("Signature.SHA256WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA256");
++            // provider.addAlgorithm("Signature.SHA384WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA384");
++            // provider.addAlgorithm("Signature.SHA512WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA512");
 +            // END android-removed
-+
-+            // BEGIN android-removed
-+            // addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
-+            // END android-removed
+ 
+             addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
              addSignatureAlgorithm(provider, "SHA256", "ECDSA", PREFIX + "SignatureSpi$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
              addSignatureAlgorithm(provider, "SHA384", "ECDSA", PREFIX + "SignatureSpi$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
              addSignatureAlgorithm(provider, "SHA512", "ECDSA", PREFIX + "SignatureSpi$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
@@ -1415,9 +1364,9 @@
          }
      }
  }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/RSA.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/RSA.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/RSA.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/RSA.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/RSA.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/RSA.java	2013-09-26 18:06:21.000000000 +0000
 @@ -3,7 +3,9 @@
  import org.bouncycastle.asn1.ASN1ObjectIdentifier;
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
@@ -1509,7 +1458,7 @@
  
              provider.addAlgorithm("KeyFactory.RSA", PREFIX + "KeyFactorySpi");
              provider.addAlgorithm("KeyPairGenerator.RSA", PREFIX + "KeyPairGeneratorSpi");
-@@ -68,101 +78,113 @@
+@@ -68,73 +78,81 @@
              registerOid(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA", keyFact);
              registerOid(provider, X509ObjectIdentifiers.id_ea_rsa, "RSA", keyFact);
              registerOid(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA", keyFact);
@@ -1647,12 +1596,7 @@
                  provider.addAlgorithm("Alg.Alias.Signature." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
                  provider.addAlgorithm("Alg.Alias.Signature.OID." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
              }
- 
--            addDigestSignature(provider, "SHA224", PREFIX + "DigestSignatureSpi$SHA224", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-+            // BEGIN android-removed
-+            // addDigestSignature(provider, "SHA224", PREFIX + "DigestSignatureSpi$SHA224", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-+            // END android-removed
-             addDigestSignature(provider, "SHA256", PREFIX + "DigestSignatureSpi$SHA256", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+@@ -144,25 +162,27 @@
              addDigestSignature(provider, "SHA384", PREFIX + "DigestSignatureSpi$SHA384", PKCSObjectIdentifiers.sha384WithRSAEncryption);
              addDigestSignature(provider, "SHA512", PREFIX + "DigestSignatureSpi$SHA512", PKCSObjectIdentifiers.sha512WithRSAEncryption);
  
@@ -1699,9 +1643,9 @@
          }
  
          private void addDigestSignature(
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/X509.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/X509.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/X509.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/X509.java	2012-09-17 23:04:47.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/X509.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/X509.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/X509.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/X509.java	2012-09-17 23:04:47.000000000 +0000
 @@ -18,8 +18,10 @@
  
          public void configure(ConfigurableProvider provider)
@@ -1715,10 +1659,10 @@
  
              //
              // certificate factories.
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java	2013-05-25 02:14:15.000000000 +0000
-@@ -23,11 +23,16 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java	2013-12-12 00:35:05.000000000 +0000
+@@ -23,13 +23,20 @@
  import org.bouncycastle.crypto.DSA;
  import org.bouncycastle.crypto.Digest;
  import org.bouncycastle.crypto.digests.NullDigest;
@@ -1738,9 +1682,14 @@
 +// import org.bouncycastle.crypto.digests.SHA512Digest;
 +// END android-removed
  import org.bouncycastle.crypto.params.ParametersWithRandom;
+-import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
++// END android-removed
  
  public class DSASigner
-@@ -216,45 +221,49 @@
+     extends SignatureSpi
+@@ -217,90 +224,102 @@
      {
          public stdDSA()
          {
@@ -1751,24 +1700,77 @@
          }
      }
  
--    static public class dsa224
+-    static public class detDSA
 -        extends DSASigner
 -    {
--        public dsa224()
+-        public detDSA()
 -        {
+-            super(new SHA1Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA1Digest())));
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class detDSA
++    //     extends DSASigner
++    // {
++    //     public detDSA()
++    //     {
++    //         super(new SHA1Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA1Digest())));
++    //     }
++    // }
++    // END android-removed
+ 
+     static public class dsa224
+         extends DSASigner
+     {
+         public dsa224()
+         {
 -            super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner());
--        }
--    }
--    
--    static public class dsa256
++            // BEGIN android-changed
++            super(AndroidDigestFactory.getSHA224(), new org.bouncycastle.crypto.signers.DSASigner());
++            // END android-changed
+         }
+     }
+ 
+-    static public class detDSA224
 -        extends DSASigner
 -    {
--        public dsa256()
+-        public detDSA224()
 -        {
--            super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+-            super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA224Digest())));
 -        }
 -    }
--    
++    // BEGIN android-removed
++    // static public class detDSA224
++    //     extends DSASigner
++    // {
++    //     public detDSA224()
++    //     {
++    //         super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA224Digest())));
++    //     }
++    // }
++    // END android-removed
+ 
+     static public class dsa256
+         extends DSASigner
+     {
+         public dsa256()
+         {
+-            super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner());
++            // BEGIN android-changed
++            super(AndroidDigestFactory.getSHA256(), new org.bouncycastle.crypto.signers.DSASigner());
++            // END android-changed
+         }
+     }
+ 
+-    static public class detDSA256
+-        extends DSASigner
+-    {
+-        public detDSA256()
+-        {
+-            super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA256Digest())));
+-        }
+-    }
+-
 -    static public class dsa384
 -        extends DSASigner
 -    {
@@ -1777,7 +1779,16 @@
 -            super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner());
 -        }
 -    }
--    
+-
+-    static public class detDSA384
+-        extends DSASigner
+-    {
+-        public detDSA384()
+-        {
+-            super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA384Digest())));
+-        }
+-    }
+-
 -    static public class dsa512
 -        extends DSASigner
 -    {
@@ -1786,22 +1797,22 @@
 -            super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner());
 -        }
 -    }
+-
+-    static public class detDSA512
+-        extends DSASigner
+-    {
+-        public detDSA512()
+-        {
+-            super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA512Digest())));
+-        }
+-    }
 +    // BEGIN android-removed
-+    // static public class dsa224
++    // static public class detDSA256
 +    //     extends DSASigner
 +    // {
-+    //     public dsa224()
++    //     public detDSA256()
 +    //     {
-+    //         super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner());
-+    //     }
-+    // }
-+    //
-+    // static public class dsa256
-+    //     extends DSASigner
-+    // {
-+    //     public dsa256()
-+    //     {
-+    //         super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner());
++    //         super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA256Digest())));
 +    //     }
 +    // }
 +    //
@@ -1814,6 +1825,15 @@
 +    //     }
 +    // }
 +    //
++    // static public class detDSA384
++    //     extends DSASigner
++    // {
++    //     public detDSA384()
++    //     {
++    //         super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA384Digest())));
++    //     }
++    // }
++    //
 +    // static public class dsa512
 +    //     extends DSASigner
 +    // {
@@ -1822,87 +1842,22 @@
 +    //         super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner());
 +    //     }
 +    // }
++    //
++    // static public class detDSA512
++    //     extends DSASigner
++    // {
++    //     public detDSA512()
++    //     {
++    //         super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA512Digest())));
++    //     }
++    // }
 +    // END android-removed
  
      static public class noneDSA
          extends DSASigner
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java	2013-05-25 02:14:15.000000000 +0000
-@@ -19,8 +19,10 @@
- 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.cryptopro.ECGOST3410NamedCurves;
-+// BEGIN android-removed
-+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
-+// END android-removed
- import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
- import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
- import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-@@ -224,21 +226,23 @@
-             ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
-             X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
- 
--            if (ecP == null) // GOST Curve
--            {
--                ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
--                EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
--
--                ecSpec = new ECNamedCurveSpec(
--                        ECGOST3410NamedCurves.getName(oid),
--                        ellipticCurve,
--                        new ECPoint(
--                                gParam.getG().getX().toBigInteger(),
--                                gParam.getG().getY().toBigInteger()),
--                        gParam.getN(),
--                        gParam.getH());
--            }
--            else
-+            // BEGIN android-removed
-+            // if (ecP == null) // GOST Curve
-+            // {
-+            //     ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
-+            //     EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
-+            //
-+            //     ecSpec = new ECNamedCurveSpec(
-+            //             ECGOST3410NamedCurves.getName(oid),
-+            //             ellipticCurve,
-+            //             new ECPoint(
-+            //                     gParam.getG().getX().toBigInteger(),
-+            //                     gParam.getG().getY().toBigInteger()),
-+            //             gParam.getN(),
-+            //             gParam.getH());
-+            // }
-+            // else
-+            // END android-removed
-             {
-                 EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
- 
-@@ -352,11 +356,13 @@
- 
-         try
-         {
--            if (algorithm.equals("ECGOST3410"))
--            {
--                info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive());
--            }
--            else
-+            // BEGIN android-removed
-+            // if (algorithm.equals("ECGOST3410"))
-+            // {
-+            //     info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive());
-+            // }
-+            // else
-+            // END android-removed
-             {
- 
-                 info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java	2013-12-12 00:35:05.000000000 +0000
 @@ -23,21 +23,27 @@
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.DerivationFunction;
@@ -2040,7 +1995,7 @@
 -            
 -            int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
 -
--            DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
+-            DHKDFParameters params = new DHKDFParameters(new ASN1ObjectIdentifier(algorithm), keySize, secret);
 -
 -            byte[] keyBytes = new byte[keySize / 8];
 -            kdf.init(params);
@@ -2055,10 +2010,10 @@
 +        //     {
 +        //         throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
 +        //     }
-+        //  
++        //     
 +        //     int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
 +        //
-+        //     DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
++        //     DHKDFParameters params = new DHKDFParameters(new ASN1ObjectIdentifier(algorithm), keySize, secret);
 +        //
 +        //     byte[] keyBytes = new byte[keySize / 8];
 +        //     kdf.init(params);
@@ -2227,9 +2182,9 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java	2013-05-25 02:14:15.000000000 +0000
 @@ -201,14 +201,16 @@
          }
      }
@@ -2255,21 +2210,10 @@
  
      public static class ECDH
          extends KeyFactorySpi
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java	2013-05-25 02:14:15.000000000 +0000
-@@ -12,7 +12,9 @@
- import org.bouncycastle.asn1.ASN1ObjectIdentifier;
- 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.crypto.AsymmetricCipherKeyPair;
-@@ -87,7 +89,13 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java	2013-12-12 00:35:05.000000000 +0000
+@@ -84,7 +84,13 @@
              SecureRandom    random)
          {
              this.strength = strength;
@@ -2283,7 +2227,7 @@
              ECGenParameterSpec ecParams = (ECGenParameterSpec)ecParameters.get(Integers.valueOf(strength));
  
              if (ecParams != null)
-@@ -112,6 +120,11 @@
+@@ -109,6 +115,11 @@
              SecureRandom            random)
              throws InvalidAlgorithmParameterException
          {
@@ -2295,44 +2239,10 @@
              if (params instanceof ECParameterSpec)
              {
                  ECParameterSpec p = (ECParameterSpec)params;
-@@ -156,10 +169,12 @@
-                     {
-                         ecP = NISTNamedCurves.getByName(curveName);
-                     }
--                    if (ecP == null)
--                    {
--                        ecP = TeleTrusTNamedCurves.getByName(curveName);
--                    }
-+                    // BEGIN android-removed
-+                    // if (ecP == null)
-+                    // {
-+                    //     ecP = TeleTrusTNamedCurves.getByName(curveName);
-+                    // }
-+                    // END android-removed
-                     if (ecP == null)
-                     {
-                         // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
-@@ -175,10 +190,12 @@
-                             {
-                                 ecP = NISTNamedCurves.getByOID(oid);
-                             }
--                            if (ecP == null)
--                            {
--                                ecP = TeleTrusTNamedCurves.getByOID(oid);
--                            }
-+                            // BEGIN android-removed
-+                            // if (ecP == null)
-+                            // {
-+                            //     ecP = TeleTrusTNamedCurves.getByOID(oid);
-+                            // }
-+                            // END android-removed
-                             if (ecP == null)
-                             {
-                                 throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java	2013-05-25 02:14:15.000000000 +0000
-@@ -16,15 +16,22 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java	2013-12-12 00:35:05.000000000 +0000
+@@ -16,16 +16,23 @@
  import org.bouncycastle.crypto.DSA;
  import org.bouncycastle.crypto.Digest;
  import org.bouncycastle.crypto.digests.NullDigest;
@@ -2356,13 +2266,15 @@
  import org.bouncycastle.crypto.params.ParametersWithRandom;
  import org.bouncycastle.crypto.signers.ECDSASigner;
 -import org.bouncycastle.crypto.signers.ECNRSigner;
+-import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.signers.ECNRSigner;
++// import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
 +// END android-removed
  import org.bouncycastle.jcajce.provider.asymmetric.util.DSABase;
  import org.bouncycastle.jcajce.provider.asymmetric.util.DSAEncoder;
  import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
-@@ -69,7 +76,9 @@
+@@ -70,18 +77,22 @@
      {
          public ecDSA()
          {
@@ -2373,25 +2285,53 @@
          }
      }
  
-@@ -82,21 +91,25 @@
-         }
-     }
- 
--    static public class ecDSA224
+-    static public class ecDetDSA
 -        extends SignatureSpi
 -    {
--        public ecDSA224()
+-        public ecDetDSA()
 -        {
--            super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
+-            super(new SHA1Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA1Digest())), new StdDSAEncoder());
 -        }
 -    }
 +    // BEGIN android-removed
-+    // static public class ecDSA224
++    // static public class ecDetDSA
 +    //     extends SignatureSpi
 +    // {
-+    //     public ecDSA224()
++    //     public ecDetDSA()
 +    //     {
-+    //         super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
++    //         super(new SHA1Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA1Digest())), new StdDSAEncoder());
++    //     }
++    // }
++    // END android-removed
+ 
+     static public class ecDSAnone
+         extends SignatureSpi
+@@ -97,171 +108,187 @@
+     {
+         public ecDSA224()
+         {
+-            super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
++            // BEGIN android-changed
++            super(AndroidDigestFactory.getSHA224(), new ECDSASigner(), new StdDSAEncoder());
++            // END android-changed
+         }
+     }
+ 
+-    static public class ecDetDSA224
+-        extends SignatureSpi
+-    {
+-        public ecDetDSA224()
+-        {
+-            super(new SHA224Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA224Digest())), new StdDSAEncoder());
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class ecDetDSA224
++    //     extends SignatureSpi
++    // {
++    //     public ecDetDSA224()
++    //     {
++    //         super(new SHA224Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA224Digest())), new StdDSAEncoder());
 +    //     }
 +    // }
 +    // END android-removed
@@ -2408,7 +2348,27 @@
          }
      }
  
-@@ -105,7 +118,9 @@
+-    static public class ecDetDSA256
+-        extends SignatureSpi
+-    {
+-        public ecDetDSA256()
+-        {
+-            super(new SHA256Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest())), new StdDSAEncoder());
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class ecDetDSA256
++    //     extends SignatureSpi
++    // {
++    //     public ecDetDSA256()
++    //     {
++    //         super(new SHA256Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest())), new StdDSAEncoder());
++    //     }
++    // }
++    // END android-removed
+ 
+     static public class ecDSA384
+         extends SignatureSpi
      {
          public ecDSA384()
          {
@@ -2419,7 +2379,27 @@
          }
      }
  
-@@ -114,108 +129,112 @@
+-    static public class ecDetDSA384
+-        extends SignatureSpi
+-    {
+-        public ecDetDSA384()
+-        {
+-            super(new SHA384Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA384Digest())), new StdDSAEncoder());
+-        }
+-    }
++    // BEGIN android-removed
++    // static public class ecDetDSA384
++    //     extends SignatureSpi
++    // {
++    //     public ecDetDSA384()
++    //     {
++    //         super(new SHA384Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA384Digest())), new StdDSAEncoder());
++    //     }
++    // }
++    // END android-removed
+ 
+     static public class ecDSA512
+         extends SignatureSpi
      {
          public ecDSA512()
          {
@@ -2427,6 +2407,15 @@
 -        }
 -    }
 -
+-    static public class ecDetDSA512
+-        extends SignatureSpi
+-    {
+-        public ecDetDSA512()
+-        {
+-            super(new SHA512Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA512Digest())), new StdDSAEncoder());
+-        }
+-    }
+-
 -    static public class ecDSARipeMD160
 -        extends SignatureSpi
 -    {
@@ -2532,6 +2521,15 @@
 +    }
 +
 +    // BEGIN android-removed
++    // static public class ecDetDSA512
++    //     extends SignatureSpi
++    // {
++    //     public ecDetDSA512()
++    //     {
++    //         super(new SHA512Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA512Digest())), new StdDSAEncoder());
++    //     }
++    // }
++    //
 +    // static public class ecDSARipeMD160
 +    //     extends SignatureSpi
 +    // {
@@ -2634,16 +2632,16 @@
  
      private static class StdDSAEncoder
          implements DSAEncoder
-@@ -309,4 +328,4 @@
+@@ -355,4 +382,4 @@
              return sig;
          }
      }
 -}
 \ No newline at end of file
 +}
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java	2013-09-26 18:06:21.000000000 +0000
 @@ -26,7 +26,9 @@
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.Digest;
@@ -2672,24 +2670,7 @@
          else if (pad.equals("OAEPWITHMD5ANDMGF1PADDING"))
          {
              initFromSpec(new OAEPParameterSpec("MD5", "MGF1", new MGF1ParameterSpec("MD5"), PSource.PSpecified.DEFAULT));
-@@ -213,10 +217,12 @@
-         {
-             initFromSpec(OAEPParameterSpec.DEFAULT);
-         }
--        else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-224ANDMGF1PADDING"))
--        {
--            initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), PSource.PSpecified.DEFAULT));
--        }
-+        // BEGIN android-removed
-+        // else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-224ANDMGF1PADDING"))
-+        // {
-+        //     initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), PSource.PSpecified.DEFAULT));
-+        // }
-+        // END android-removed
-         else if (pad.equals("OAEPWITHSHA256ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-256ANDMGF1PADDING"))
-         {
-             initFromSpec(new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
-@@ -539,48 +545,50 @@
+@@ -539,48 +543,50 @@
          }
      }
  
@@ -2784,9 +2765,9 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java	2012-09-17 23:04:47.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java	2013-09-26 18:06:21.000000000 +0000
 @@ -17,24 +17,31 @@
  import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
@@ -2832,7 +2813,7 @@
  import org.bouncycastle.crypto.encodings.PKCS1Encoding;
  import org.bouncycastle.crypto.engines.RSABlindedEngine;
  
-@@ -261,25 +268,31 @@
+@@ -261,7 +268,9 @@
      {
          public SHA1()
          {
@@ -2843,27 +2824,18 @@
          }
      }
  
--    static public class SHA224
--        extends DigestSignatureSpi
--    {
--        public SHA224()
--        {
+@@ -270,7 +279,9 @@
+     {
+         public SHA224()
+         {
 -            super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
-+    // BEGIN android-removed
-+    // static public class SHA224
-+    //     extends DigestSignatureSpi
-+    // {
-+    //     public SHA224()
-+    //     {
-+    //         super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine()));
-+    //     }
-+    // }
-+    // END android-removed
++            // BEGIN android-changed
++            super(NISTObjectIdentifiers.id_sha224, AndroidDigestFactory.getSHA224(), new PKCS1Encoding(new RSABlindedEngine()));
++            // END android-changed
+         }
+     }
  
-     static public class SHA256
-         extends DigestSignatureSpi
+@@ -279,7 +290,9 @@
      {
          public SHA256()
          {
@@ -2890,21 +2862,21 @@
          public SHA512()
          {
 -            super(NISTObjectIdentifiers.id_sha512, new SHA512Digest(), new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
--
--    static public class MD2
--        extends DigestSignatureSpi
--    {
--        public MD2()
--        {
--            super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine()));
 +            // BEGIN android-changed
 +            super(NISTObjectIdentifiers.id_sha512, AndroidDigestFactory.getSHA512(), new PKCS1Encoding(new RSABlindedEngine()));
 +            // END android-changed
          }
      }
  
+-    static public class MD2
+-        extends DigestSignatureSpi
+-    {
+-        public MD2()
+-        {
+-            super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+-        }
+-    }
+-
 -    static public class MD4
 -        extends DigestSignatureSpi
 -    {
@@ -2939,21 +2911,21 @@
          public MD5()
          {
 -            super(PKCSObjectIdentifiers.md5, new MD5Digest(), new PKCS1Encoding(new RSABlindedEngine()));
-+            // BEGIN android-changed
-+            super(PKCSObjectIdentifiers.md5, AndroidDigestFactory.getMD5(), new PKCS1Encoding(new RSABlindedEngine()));
-+            // END android-changed
-         }
-     }
- 
+-        }
+-    }
+-
 -    static public class RIPEMD160
 -        extends DigestSignatureSpi
 -    {
 -        public RIPEMD160()
 -        {
 -            super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine()));
--        }
--    }
--
++            // BEGIN android-changed
++            super(PKCSObjectIdentifiers.md5, AndroidDigestFactory.getMD5(), new PKCS1Encoding(new RSABlindedEngine()));
++            // END android-changed
+         }
+     }
+ 
 -    static public class RIPEMD128
 -        extends DigestSignatureSpi
 -    {
@@ -3018,9 +2990,9 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java	2012-09-17 23:04:47.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java	2012-09-17 23:04:47.000000000 +0000
 @@ -18,8 +18,10 @@
  import javax.crypto.NoSuchPaddingException;
  import javax.crypto.spec.IvParameterSpec;
@@ -3047,9 +3019,9 @@
                                      };
  
  
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java	2013-05-25 02:14:15.000000000 +0000
 @@ -5,11 +5,15 @@
  import java.security.PublicKey;
  
@@ -3135,9 +3107,9 @@
          }
  
          return name;
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java	2013-02-21 00:01:31.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java	2013-02-21 00:01:31.000000000 +0000
 @@ -36,7 +36,9 @@
  import org.bouncycastle.asn1.pkcs.SignedData;
  import org.bouncycastle.jce.provider.BouncyCastleProvider;
@@ -3211,9 +3183,9 @@
          else
          {
              throw new CertificateEncodingException("unsupported encoding: " + encoding);
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java	2013-05-25 02:14:15.000000000 +0000
 @@ -57,6 +57,9 @@
  import org.bouncycastle.asn1.x509.Extensions;
  import org.bouncycastle.asn1.x509.GeneralName;
@@ -3257,9 +3229,9 @@
                      break;
                  case GeneralName.dNSName:
                  case GeneralName.rfc822Name:
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java	2013-05-25 02:14:15.000000000 +0000
 @@ -14,12 +14,16 @@
  import org.bouncycastle.asn1.ASN1Sequence;
  import org.bouncycastle.asn1.DERNull;
@@ -3320,9 +3292,9 @@
          else
          {
              return digestAlgOID.getId();            
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/digest/SHA256.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/digest/SHA256.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/digest/SHA256.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/digest/SHA256.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/digest/SHA256.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/digest/SHA256.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/digest/SHA256.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/digest/SHA256.java	2013-05-25 02:14:15.000000000 +0000
 @@ -45,17 +45,19 @@
          }
      }
@@ -3369,9 +3341,9 @@
  
              addHMACAlgorithm(provider, "SHA256", PREFIX + "$HashMac",  PREFIX + "$KeyGenerator");
              addHMACAlias(provider, "SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/digest/SHA384.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/digest/SHA384.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/digest/SHA384.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/digest/SHA384.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/digest/SHA384.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/digest/SHA384.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/digest/SHA384.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/digest/SHA384.java	2013-05-25 02:14:15.000000000 +0000
 @@ -5,7 +5,9 @@
  import org.bouncycastle.crypto.CipherKeyGenerator;
  import org.bouncycastle.crypto.digests.SHA384Digest;
@@ -3419,9 +3391,9 @@
  
              addHMACAlgorithm(provider, "SHA384", PREFIX + "$HashMac",  PREFIX + "$KeyGenerator");
              addHMACAlias(provider, "SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/digest/SHA512.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/digest/SHA512.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/digest/SHA512.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/digest/SHA512.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/digest/SHA512.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/digest/SHA512.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/digest/SHA512.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/digest/SHA512.java	2013-05-25 02:14:15.000000000 +0000
 @@ -4,9 +4,13 @@
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
  import org.bouncycastle.crypto.CipherKeyGenerator;
@@ -3666,9 +3638,9 @@
          }
      }
  
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/keystore/BC.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/keystore/BC.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/keystore/BC.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/keystore/BC.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/keystore/BC.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/keystore/BC.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/keystore/BC.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/keystore/BC.java	2013-05-25 02:14:15.000000000 +0000
 @@ -17,7 +17,9 @@
          public void configure(ConfigurableProvider provider)
          {
@@ -3680,9 +3652,9 @@
              provider.addAlgorithm("KeyStore.BouncyCastle", PREFIX + "BcKeyStoreSpi$BouncyCastleStore");
              provider.addAlgorithm("Alg.Alias.KeyStore.UBER", "BouncyCastle");
              provider.addAlgorithm("Alg.Alias.KeyStore.BOUNCYCASTLE", "BouncyCastle");
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/keystore/PKCS12.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/keystore/PKCS12.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/keystore/PKCS12.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/keystore/PKCS12.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/keystore/PKCS12.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/keystore/PKCS12.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/keystore/PKCS12.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/keystore/PKCS12.java	2013-05-25 02:14:15.000000000 +0000
 @@ -17,14 +17,16 @@
          public void configure(ConfigurableProvider provider)
          {
@@ -3708,10 +3680,57 @@
          }
      }
  }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java	2013-05-25 02:14:15.000000000 +0000
-@@ -1594,32 +1594,34 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java	2013-12-12 00:35:05.000000000 +0000
+@@ -61,8 +61,10 @@
+ import org.bouncycastle.asn1.DEROutputStream;
+ import org.bouncycastle.asn1.DERSequence;
+ import org.bouncycastle.asn1.DERSet;
+-import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+-import org.bouncycastle.asn1.cryptopro.GOST28147Parameters;
++// BEGIN android-removed
++// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
++// import org.bouncycastle.asn1.cryptopro.GOST28147Parameters;
++// END android-removed
+ import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+ import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
+ import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
+@@ -86,7 +88,9 @@
+ import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+ import org.bouncycastle.jcajce.provider.config.PKCS12StoreParameter;
+ import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
+-import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
++// BEGIN android-removed
++// import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
++// END android-removed
+ import org.bouncycastle.jcajce.spec.PBKDF2KeySpec;
+ import org.bouncycastle.jce.interfaces.BCKeyStore;
+ import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+@@ -736,13 +740,15 @@
+         {
+             cipher.init(mode, key, new IvParameterSpec(ASN1OctetString.getInstance(encParams).getOctets()));
+         }
+-        else
+-        {
+-            // TODO: at the moment it's just GOST, but...
+-            GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams);
+-
+-            cipher.init(mode, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV()));
+-        }
++        // BEGIN android-removed
++        // else
++        // {
++        //     // TODO: at the moment it's just GOST, but...
++        //     GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams);
++        //
++        //     cipher.init(mode, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV()));
++        // }
++        // END android-removed
+         return cipher;
+     }
+ 
+@@ -1659,32 +1665,34 @@
          }
      }
  
@@ -3772,12 +3791,24 @@
  
      private static class IgnoresCaseHashtable
      {
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/AES.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/AES.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/AES.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/AES.java	2013-05-25 02:14:15.000000000 +0000
-@@ -1,11 +1,15 @@
- package org.bouncycastle.jcajce.provider.symmetric;
+@@ -1757,7 +1765,9 @@
+             keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192));
+             keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256));
  
+-            keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256));
++            // BEGIN android-removed
++            // keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256));
++            // END android-removed
+ 
+             KEY_SIZES = Collections.unmodifiableMap(keySizes);
+         }
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/AES.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/AES.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/AES.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/AES.java	2013-12-12 00:35:05.000000000 +0000
+@@ -3,13 +3,17 @@
+ import java.io.IOException;
+ import java.lang.reflect.Constructor;
+ import java.lang.reflect.Method;
 -import java.security.AlgorithmParameters;
 -import java.security.InvalidAlgorithmParameterException;
 +// BEGIN android-removed
@@ -3785,26 +3816,27 @@
 +// import java.security.InvalidAlgorithmParameterException;
 +// END android-removed
  import java.security.SecureRandom;
--import java.security.spec.AlgorithmParameterSpec;
--
+ import java.security.spec.AlgorithmParameterSpec;
+ import java.security.spec.InvalidParameterSpecException;
+ 
 -import javax.crypto.spec.IvParameterSpec;
 +// BEGIN android-removed
-+// import java.security.spec.AlgorithmParameterSpec;
-+//
 +// import javax.crypto.spec.IvParameterSpec;
 +// END android-removed
  
  import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
- import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-@@ -14,23 +18,31 @@
+ import org.bouncycastle.asn1.cms.GCMParameters;
+@@ -19,25 +23,33 @@
  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.generators.Poly1305KeyGenerator;
 -import org.bouncycastle.crypto.macs.CMac;
 -import org.bouncycastle.crypto.macs.GMac;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
++// import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
 +// import org.bouncycastle.crypto.macs.CMac;
 +// import org.bouncycastle.crypto.macs.GMac;
 +// END android-removed
@@ -3817,6 +3849,7 @@
 +// BEGIN android-removed
 +// import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
 +// END android-removed
+ import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
  import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
  import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
 -import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
@@ -3831,10 +3864,10 @@
 +// BEGIN android-removed
 +// import org.bouncycastle.jce.provider.BouncyCastleProvider;
 +// END android-removed
+ import org.bouncycastle.util.Integers;
  
  public final class AES
- {
-@@ -80,23 +92,25 @@
+@@ -99,41 +111,43 @@
          }
      }
  
@@ -3855,6 +3888,24 @@
 -            super(new GMac(new GCMBlockCipher(new AESFastEngine())));
 -        }
 -    }
+-
+-    public static class Poly1305
+-        extends BaseMac
+-    {
+-        public Poly1305()
+-        {
+-            super(new org.bouncycastle.crypto.macs.Poly1305(new AESFastEngine()));
+-        }
+-    }
+-
+-    public static class Poly1305KeyGen
+-        extends BaseKeyGenerator
+-    {
+-        public Poly1305KeyGen()
+-        {
+-            super("Poly1305-AES", 256, new Poly1305KeyGenerator());
+-        }
+-    }
 +    // BEGIN android-removed
 +    // public static class AESCMAC
 +    //     extends BaseMac
@@ -3873,11 +3924,29 @@
 +    //         super(new GMac(new GCMBlockCipher(new AESFastEngine())));
 +    //     }
 +    // }
++    //
++    // public static class Poly1305
++    //     extends BaseMac
++    // {
++    //     public Poly1305()
++    //     {
++    //         super(new org.bouncycastle.crypto.macs.Poly1305(new AESFastEngine()));
++    //     }
++    // }
++    //
++    // public static class Poly1305KeyGen
++    //     extends BaseKeyGenerator
++    // {
++    //     public Poly1305KeyGen()
++    //     {
++    //         super("Poly1305-AES", 256, new Poly1305KeyGenerator());
++    //     }
++    // }
 +    // END android-removed
  
      static public class Wrap
          extends BaseWrapCipher
-@@ -106,15 +120,17 @@
+@@ -143,15 +157,17 @@
              super(new AESWrapEngine());
          }
      }
@@ -3904,7 +3973,7 @@
  
      
      /**
-@@ -143,32 +159,34 @@
+@@ -180,32 +196,34 @@
          }
      }
  
@@ -3965,7 +4034,7 @@
      
      /**
       * PBEWithSHA1And128BitAES-BC
-@@ -278,43 +296,45 @@
+@@ -315,43 +333,45 @@
          }
      }
      
@@ -4048,9 +4117,9 @@
  
      public static class AlgParams
          extends IvAlgorithmParameters
-@@ -353,58 +373,66 @@
-             provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
-             provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+@@ -484,35 +504,41 @@
+             provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_GCM, "GCM");
+             provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_GCM, "GCM");
  
 -            provider.addAlgorithm("AlgorithmParameterGenerator.AES", PREFIX + "$AlgParamGen");
 -            provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
@@ -4108,6 +4177,11 @@
 +            // provider.addAlgorithm("Cipher.AESRFC3211WRAP", PREFIX + "$RFC3211Wrap");
 +            // END android-removed
  
+             provider.addAlgorithm("Cipher.GCM", PREFIX + "$GCM");
+             provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_GCM, "GCM");
+@@ -520,27 +546,29 @@
+             provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_GCM, "GCM");
+ 
              provider.addAlgorithm("KeyGenerator.AES", PREFIX + "$KeyGen");
 -            provider.addAlgorithm("KeyGenerator." + wrongAES128, PREFIX + "$KeyGen128");
 -            provider.addAlgorithm("KeyGenerator." + wrongAES192, PREFIX + "$KeyGen192");
@@ -4156,20 +4230,22 @@
              
              provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
              provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
-@@ -483,7 +511,9 @@
+@@ -619,8 +647,10 @@
              provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
              provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
  
 -            addGMacAlgorithm(provider, "AES", PREFIX + "$AESGMAC", PREFIX + "$KeyGen128");
+-            addPoly1305Algorithm(provider, "AES", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
 +            // BEGIN android-removed
 +            // addGMacAlgorithm(provider, "AES", PREFIX + "$AESGMAC", PREFIX + "$KeyGen128");
++            // addPoly1305Algorithm(provider, "AES", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
 +            // END android-removed
          }
      }
- }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/ARC4.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/ARC4.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/ARC4.java	2013-05-25 02:14:15.000000000 +0000
+ 
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/ARC4.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/ARC4.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/ARC4.java	2013-05-25 02:14:15.000000000 +0000
 @@ -29,7 +29,9 @@
      {
          public KeyGen()
@@ -4181,9 +4257,9 @@
          }
      }
  
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java	2012-09-17 23:04:47.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java	2012-09-17 23:04:47.000000000 +0000
 @@ -64,7 +64,9 @@
          {
  
@@ -4195,9 +4271,9 @@
              provider.addAlgorithm("KeyGenerator.BLOWFISH", PREFIX + "$KeyGen");
              provider.addAlgorithm("Alg.Alias.KeyGenerator.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
              provider.addAlgorithm("AlgorithmParameters.BLOWFISH", PREFIX + "$AlgParams");
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/DES.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/DES.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/DES.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/DES.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/DES.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/DES.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/DES.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/DES.java	2013-05-25 02:14:15.000000000 +0000
 @@ -19,12 +19,16 @@
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.KeyGenerationParameters;
@@ -4514,9 +4590,9 @@
              provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
              provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
          }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/DESede.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/DESede.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/DESede.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/DESede.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/DESede.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/DESede.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/DESede.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/DESede.java	2013-05-25 02:14:15.000000000 +0000
 @@ -1,30 +1,42 @@
  package org.bouncycastle.jcajce.provider.symmetric;
  
@@ -4837,9 +4913,9 @@
  
              provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES3KeyFactory");
              provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES2KeyFactory");
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/RC2.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/RC2.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/RC2.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/RC2.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/RC2.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/RC2.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/RC2.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/RC2.java	2013-05-25 02:14:15.000000000 +0000
 @@ -12,24 +12,34 @@
  
  import org.bouncycastle.asn1.ASN1Primitive;
@@ -5602,10 +5678,10 @@
  
              provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
  
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java	2013-05-25 02:14:15.000000000 +0000
-@@ -6,16 +6,18 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java	2013-12-12 00:35:05.000000000 +0000
+@@ -6,29 +6,31 @@
  abstract class SymmetricAlgorithmProvider
      extends AlgorithmProvider
  {
@@ -5621,6 +5697,18 @@
 -        provider.addAlgorithm("KeyGenerator." + algorithm + "-GMAC", keyGeneratorClassName);
 -        provider.addAlgorithm("Alg.Alias.KeyGenerator." + algorithm + "GMAC",  algorithm + "-GMAC");
 -    }
+-
+-    protected void addPoly1305Algorithm(ConfigurableProvider provider,
+-                                        String algorithm,
+-                                        String algorithmClassName,
+-                                        String keyGeneratorClassName)
+-    {
+-        provider.addAlgorithm("Mac.POLY1305-" + algorithm, algorithmClassName);
+-        provider.addAlgorithm("Alg.Alias.Mac.POLY1305" + algorithm, "POLY1305-" + algorithm);
+-
+-        provider.addAlgorithm("KeyGenerator.POLY1305-" + algorithm, keyGeneratorClassName);
+-        provider.addAlgorithm("Alg.Alias.KeyGenerator.POLY1305" + algorithm, "POLY1305-" + algorithm);
+-    }
 +    // BEGIN android-removed
 +    // protected void addGMacAlgorithm(
 +    //     ConfigurableProvider provider,
@@ -5634,12 +5722,25 @@
 +    //     provider.addAlgorithm("KeyGenerator." + algorithm + "-GMAC", keyGeneratorClassName);
 +    //     provider.addAlgorithm("Alg.Alias.KeyGenerator." + algorithm + "GMAC",  algorithm + "-GMAC");
 +    // }
++    //
++    // protected void addPoly1305Algorithm(ConfigurableProvider provider,
++    //                                     String algorithm,
++    //                                     String algorithmClassName,
++    //                                     String keyGeneratorClassName)
++    // {
++    //     provider.addAlgorithm("Mac.POLY1305-" + algorithm, algorithmClassName);
++    //     provider.addAlgorithm("Alg.Alias.Mac.POLY1305" + algorithm, "POLY1305-" + algorithm);
++    //
++    //     provider.addAlgorithm("KeyGenerator.POLY1305-" + algorithm, keyGeneratorClassName);
++    //     provider.addAlgorithm("Alg.Alias.KeyGenerator.POLY1305" + algorithm, "POLY1305-" + algorithm);
++    // }
 +    // END android-removed
+ 
  }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/Twofish.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/Twofish.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/Twofish.java	2013-05-25 02:14:15.000000000 +0000
-@@ -1,17 +1,25 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/Twofish.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/Twofish.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/Twofish.java	2013-12-12 00:35:05.000000000 +0000
+@@ -1,18 +1,26 @@
  package org.bouncycastle.jcajce.provider.symmetric;
  
 -import org.bouncycastle.crypto.BlockCipher;
@@ -5649,8 +5750,10 @@
 +// import org.bouncycastle.crypto.CipherKeyGenerator;
 +// END android-removed
  import org.bouncycastle.crypto.engines.TwofishEngine;
+-import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
 -import org.bouncycastle.crypto.macs.GMac;
 +// BEGIN android-removed
++// import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
 +// import org.bouncycastle.crypto.macs.GMac;
 +// END android-removed
  import org.bouncycastle.crypto.modes.CBCBlockCipher;
@@ -5673,7 +5776,7 @@
  import org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
  
  public final class Twofish
-@@ -20,38 +28,40 @@
+@@ -21,56 +29,58 @@
      {
      }
  
@@ -5709,6 +5812,24 @@
 -            super(new GMac(new GCMBlockCipher(new TwofishEngine())));
 -        }
 -    }
+-
+-    public static class Poly1305
+-        extends BaseMac
+-    {
+-        public Poly1305()
+-        {
+-            super(new org.bouncycastle.crypto.macs.Poly1305(new TwofishEngine()));
+-        }
+-    }
+-
+-    public static class Poly1305KeyGen
+-        extends BaseKeyGenerator
+-    {
+-        public Poly1305KeyGen()
+-        {
+-            super("Poly1305-Twofish", 256, new Poly1305KeyGenerator());
+-        }
+-    }
 +    // BEGIN android-removed
 +    // public static class ECB
 +    //     extends BaseBlockCipher
@@ -5742,11 +5863,29 @@
 +    //         super(new GMac(new GCMBlockCipher(new TwofishEngine())));
 +    //     }
 +    // }
++    //
++    // public static class Poly1305
++    //     extends BaseMac
++    // {
++    //     public Poly1305()
++    //     {
++    //         super(new org.bouncycastle.crypto.macs.Poly1305(new TwofishEngine()));
++    //     }
++    // }
++    //
++    // public static class Poly1305KeyGen
++    //     extends BaseKeyGenerator
++    // {
++    //     public Poly1305KeyGen()
++    //     {
++    //         super("Poly1305-Twofish", 256, new Poly1305KeyGenerator());
++    //     }
++    // }
 +    // END android-removed
  
      /**
       * PBEWithSHAAndTwofish-CBC
-@@ -77,14 +87,16 @@
+@@ -96,14 +106,16 @@
          }
      }
  
@@ -5771,7 +5910,7 @@
  
      public static class Mappings
          extends SymmetricAlgorithmProvider
-@@ -97,16 +109,20 @@
+@@ -116,17 +128,21 @@
  
          public void configure(ConfigurableProvider provider)
          {
@@ -5790,16 +5929,18 @@
              provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAANDTWOFISH-CBC", PREFIX + "$PBEWithSHAKeyFactory");
  
 -            addGMacAlgorithm(provider, "Twofish", PREFIX + "$GMAC", PREFIX + "$KeyGen");
+-            addPoly1305Algorithm(provider, "Twofish", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
 +            // BEGIN android-removed
 +            // addGMacAlgorithm(provider, "Twofish", PREFIX + "$GMAC", PREFIX + "$KeyGen");
++            // addPoly1305Algorithm(provider, "Twofish", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
 +            // END android-removed
          }
      }
  }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java	2013-05-25 02:14:15.000000000 +0000
-@@ -17,8 +17,10 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java	2013-12-13 23:56:53.000000000 +0000
+@@ -19,8 +19,10 @@
  import javax.crypto.ShortBufferException;
  import javax.crypto.spec.IvParameterSpec;
  import javax.crypto.spec.PBEParameterSpec;
@@ -5810,15 +5951,17 @@
 +// import javax.crypto.spec.RC5ParameterSpec;
 +// END android-removed
  
+ import org.bouncycastle.asn1.cms.GCMParameters;
  import org.bouncycastle.crypto.BlockCipher;
- import org.bouncycastle.crypto.BufferedBlockCipher;
-@@ -31,13 +33,19 @@
+@@ -34,14 +36,20 @@
  import org.bouncycastle.crypto.modes.CCMBlockCipher;
  import org.bouncycastle.crypto.modes.CFBBlockCipher;
  import org.bouncycastle.crypto.modes.CTSBlockCipher;
 -import org.bouncycastle.crypto.modes.EAXBlockCipher;
+-import org.bouncycastle.crypto.modes.GCFBBlockCipher;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.modes.EAXBlockCipher;
++// import org.bouncycastle.crypto.modes.GCFBBlockCipher;
 +// END android-removed
  import org.bouncycastle.crypto.modes.GCMBlockCipher;
 -import org.bouncycastle.crypto.modes.GOFBBlockCipher;
@@ -5837,7 +5980,7 @@
  import org.bouncycastle.crypto.modes.SICBlockCipher;
  import org.bouncycastle.crypto.paddings.BlockCipherPadding;
  import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
-@@ -49,11 +57,17 @@
+@@ -54,11 +62,15 @@
  import org.bouncycastle.crypto.params.KeyParameter;
  import org.bouncycastle.crypto.params.ParametersWithIV;
  import org.bouncycastle.crypto.params.ParametersWithRandom;
@@ -5847,18 +5990,17 @@
 +// END android-removed
  import org.bouncycastle.crypto.params.RC2Parameters;
 -import org.bouncycastle.crypto.params.RC5Parameters;
+-import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
+-import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec;
 +// BEGIN android-removed
 +// import org.bouncycastle.crypto.params.RC5Parameters;
++// import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
++// import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec;
 +// END android-removed
  import org.bouncycastle.jce.provider.BouncyCastleProvider;
--import org.bouncycastle.jce.spec.GOST28147ParameterSpec;
-+// BEGIN android-removed
-+// import org.bouncycastle.jce.spec.GOST28147ParameterSpec;
-+// END android-removed
- import org.bouncycastle.jce.spec.RepeatedSecretKeySpec;
  import org.bouncycastle.util.Strings;
  
-@@ -66,11 +80,15 @@
+@@ -73,11 +85,15 @@
      //
      private Class[]                 availableSpecs =
                                      {
@@ -5870,14 +6012,26 @@
 +                                        // END android-removed
                                          IvParameterSpec.class,
                                          PBEParameterSpec.class,
--                                        GOST28147ParameterSpec.class
+-                                        GOST28147ParameterSpec.class,
 +                                        // BEGIN android-removed
-+                                        // GOST28147ParameterSpec.class
++                                        // GOST28147ParameterSpec.class,
 +                                        // END android-removed
+                                         gcmSpecClass
                                      };
  
-     private BlockCipher             baseEngine;
-@@ -235,20 +253,22 @@
+@@ -162,6 +178,11 @@
+ 
+     protected byte[] engineGetIV()
+     {
++        // BEGIN android-added
++        if (aeadParams != null) {
++            return aeadParams.getNonce();
++        }
++        // END android-added
+         return (ivParam != null) ? ivParam.getIV() : null;
+     }
+ 
+@@ -278,48 +299,52 @@
                          new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
              }
          }
@@ -5895,11 +6049,21 @@
 -            cipher = new BufferedGenericBlockCipher(
 -                new OpenPGPCFBBlockCipher(baseEngine));
 -        }
+-        else if (modeName.startsWith("SIC"))
+-        {
+-            ivLength = baseEngine.getBlockSize();
+-            if (ivLength < 16)
+-            {
+-                throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
+-            }
+-            cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+-                        new SICBlockCipher(baseEngine)));
+-        }
 +        // BEGIN android-removed
 +        // else if (modeName.startsWith("PGP"))
 +        // {
 +        //     boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
-+
++        //
 +        //     ivLength = baseEngine.getBlockSize();
 +        //     cipher = new BufferedGenericBlockCipher(
 +        //         new PGPCFBBlockCipher(baseEngine, inlineIV));
@@ -5910,11 +6074,20 @@
 +        //     cipher = new BufferedGenericBlockCipher(
 +        //         new OpenPGPCFBBlockCipher(baseEngine));
 +        // }
++        // else if (modeName.startsWith("SIC"))
++        // {
++        //     ivLength = baseEngine.getBlockSize();
++        //     if (ivLength < 16)
++        //     {
++        //         throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
++        //     }
++        //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
++        //                 new SICBlockCipher(baseEngine)));
++        // }
 +        // END android-removed
-         else if (modeName.startsWith("SIC"))
+         else if (modeName.startsWith("CTR"))
          {
              ivLength = baseEngine.getBlockSize();
-@@ -265,12 +285,14 @@
              cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
                          new SICBlockCipher(baseEngine)));
          }
@@ -5924,6 +6097,12 @@
 -            cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
 -                        new GOFBBlockCipher(baseEngine)));
 -        }
+-        else if (modeName.startsWith("GCFB"))
+-        {
+-            ivLength = baseEngine.getBlockSize();
+-            cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+-                        new GCFBBlockCipher(baseEngine)));
+-        }
 +        // BEGIN android-removed
 +        // else if (modeName.startsWith("GOFB"))
 +        // {
@@ -5931,19 +6110,26 @@
 +        //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
 +        //                 new GOFBBlockCipher(baseEngine)));
 +        // }
++        // else if (modeName.startsWith("GCFB"))
++        // {
++        //     ivLength = baseEngine.getBlockSize();
++        //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
++        //                 new GCFBBlockCipher(baseEngine)));
++        // }
 +        // END android-removed
          else if (modeName.startsWith("CTS"))
          {
              ivLength = baseEngine.getBlockSize();
-@@ -281,23 +303,25 @@
-             ivLength = baseEngine.getBlockSize();
+@@ -330,24 +355,26 @@
+             ivLength = 13; // CCM nonce 7..13 bytes
              cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
          }
 -        else if (modeName.startsWith("OCB"))
 -        {
 -            if (engineProvider != null)
 -            {
--                ivLength = baseEngine.getBlockSize();
+-                // Nonce restricted to max 120 bits over 128 bit block cipher since draft-irtf-cfrg-ocb-03
+-                ivLength = 15;
 -                cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get()));
 -            }
 -            else
@@ -5961,7 +6147,8 @@
 +        // {
 +        //     if (engineProvider != null)
 +        //     {
-+        //         ivLength = baseEngine.getBlockSize();
++        //         // Nonce restricted to max 120 bits over 128 bit block cipher since draft-irtf-cfrg-ocb-03
++        //         ivLength = 15;
 +        //         cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get()));
 +        //     }
 +        //     else
@@ -5978,7 +6165,61 @@
          else if (modeName.startsWith("GCM"))
          {
              ivLength = baseEngine.getBlockSize();
-@@ -471,63 +495,65 @@
+@@ -470,18 +497,20 @@
+ 
+                     param = new ParametersWithIV(param, iv.getIV());
+                 }
+-                else if (params instanceof GOST28147ParameterSpec)
+-                {
+-                    // need to pick up IV and SBox.
+-                    GOST28147ParameterSpec    gost28147Param = (GOST28147ParameterSpec)params;
+-
+-                    param = new ParametersWithSBox(param, gost28147Param.getSbox());
+-
+-                    if (gost28147Param.getIV() != null && ivLength != 0)
+-                    {
+-                        param = new ParametersWithIV(param, gost28147Param.getIV());
+-                    }
+-                }
++                // BEGIN android-removed
++                // else if (params instanceof GOST28147ParameterSpec)
++                // {
++                //     // need to pick up IV and SBox.
++                //     GOST28147ParameterSpec    gost28147Param = (GOST28147ParameterSpec)params;
++                //
++                //     param = new ParametersWithSBox(param, gost28147Param.getSbox());
++                //
++                //     if (gost28147Param.getIV() != null && ivLength != 0)
++                //     {
++                //         param = new ParametersWithIV(param, gost28147Param.getIV());
++                //     }
++                // }
++                // END android-removed
+             }
+             else if (params instanceof PBEParameterSpec)
+             {
+@@ -513,12 +542,14 @@
+                     throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
+                 }
+ 
+-                if (key instanceof RepeatedSecretKeySpec)
+-                {
+-                    param = new ParametersWithIV(null, p.getIV());
+-                    ivParam = (ParametersWithIV)param;
+-                }
+-                else
++                // BEGIN android-removed
++                // if (key instanceof RepeatedSecretKeySpec)
++                // {
++                //     param = new ParametersWithIV(null, p.getIV());
++                //     ivParam = (ParametersWithIV)param;
++                // }
++                // else
++                // END android-removed
+                 {
+                     param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
+                     ivParam = (ParametersWithIV)param;
+@@ -534,63 +565,65 @@
                  param = new KeyParameter(key.getEncoded());
              }
          }
@@ -6098,10 +6339,29 @@
 +        //     }
 +        // }
 +        // END android-removed
-         else
+         else if (gcmSpecClass != null && gcmSpecClass.isInstance(params))
          {
-             throw new InvalidAlgorithmParameterException("unknown parameter type.");
-@@ -761,7 +787,9 @@
+             if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher))
+@@ -603,11 +636,13 @@
+                 Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
+                 Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
+ 
+-                if (key instanceof RepeatedSecretKeySpec)
+-                {
+-                    param = aeadParams = new AEADParameters(null, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+-                }
+-                else
++                // BEGIN android-removed
++                // if (key instanceof RepeatedSecretKeySpec)
++                // {
++                //     param = aeadParams = new AEADParameters(null, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
++                // }
++                // else
++                // END android-removed
+                 {
+                     param = aeadParams = new AEADParameters(new KeyParameter(key.getEncoded()), ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+                 }
+@@ -867,7 +902,9 @@
      private boolean isAEADModeName(
          String modeName)
      {
@@ -6112,10 +6372,43 @@
      }
  
      /*
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java	2012-09-17 23:04:47.000000000 +0000
-@@ -13,8 +13,10 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java	2013-12-12 00:35:05.000000000 +0000
+@@ -16,8 +16,10 @@
+ import org.bouncycastle.crypto.Mac;
+ import org.bouncycastle.crypto.params.KeyParameter;
+ import org.bouncycastle.crypto.params.ParametersWithIV;
+-import org.bouncycastle.crypto.params.SkeinParameters;
+-import org.bouncycastle.jcajce.spec.SkeinParameterSpec;
++// BEGIN android-removed
++// import org.bouncycastle.crypto.params.SkeinParameters;
++// import org.bouncycastle.jcajce.spec.SkeinParameterSpec;
++// END android-removed
+ 
+ public class BaseMac
+     extends MacSpi implements PBE
+@@ -79,10 +81,12 @@
+         {
+             param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+         }
+-        else if (params instanceof SkeinParameterSpec)
+-        {
+-            param = new SkeinParameters.Builder(copyMap(((SkeinParameterSpec)params).getParameters())).setKey(key.getEncoded()).build();
+-        }
++        // BEGIN android-removed
++        // else if (params instanceof SkeinParameterSpec)
++        // {
++        //     param = new SkeinParameters.Builder(copyMap(((SkeinParameterSpec)params).getParameters())).setKey(key.getEncoded()).build();
++        // }
++        // END android-removed
+         else if (params == null)
+         {
+             param = new KeyParameter(key.getEncoded());
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java	2013-12-12 00:35:05.000000000 +0000
+@@ -14,8 +14,10 @@
  import javax.crypto.ShortBufferException;
  import javax.crypto.spec.IvParameterSpec;
  import javax.crypto.spec.PBEParameterSpec;
@@ -6128,7 +6421,7 @@
  
  import org.bouncycastle.crypto.BlockCipher;
  import org.bouncycastle.crypto.CipherParameters;
-@@ -34,8 +36,10 @@
+@@ -35,8 +37,10 @@
      //
      private Class[]                 availableSpecs =
                                      {
@@ -6141,9 +6434,9 @@
                                          IvParameterSpec.class,
                                          PBEParameterSpec.class
                                      };
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java	2013-01-31 02:26:40.000000000 +0000
 @@ -22,8 +22,10 @@
  import javax.crypto.ShortBufferException;
  import javax.crypto.spec.IvParameterSpec;
@@ -6187,9 +6480,9 @@
  
      protected byte[] engineWrap(
          Key     key)
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java	2013-12-12 00:35:05.000000000 +0000
 @@ -7,13 +7,18 @@
  
  import org.bouncycastle.crypto.CipherParameters;
@@ -6262,7 +6555,64 @@
                      break;
                  default:
                      throw new IllegalStateException("PKCS5 scheme 1 only supports MD2, MD5 and SHA1.");
-@@ -78,27 +93,39 @@
+@@ -74,27 +89,39 @@
+             {
+                 switch (hash)
+                 {
+-                case MD2:
+-                    generator = new PKCS5S2ParametersGenerator(new MD2Digest());
+-                    break;
++                // BEGIN android-removed
++                // case MD2:
++                //     generator = new PKCS5S2ParametersGenerator(new MD2Digest());
++                //     break;
++                // END android-removed
+                 case MD5:
+-                    generator = new PKCS5S2ParametersGenerator(new MD5Digest());
++                    // BEGIN android-changed
++                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getMD5());
++                    // END android-changed
+                     break;
+                 case SHA1:
+-                    generator = new PKCS5S2ParametersGenerator(new SHA1Digest());
+-                    break;
+-                case RIPEMD160:
+-                    generator = new PKCS5S2ParametersGenerator(new RIPEMD160Digest());
+-                    break;
+-                case TIGER:
+-                    generator = new PKCS5S2ParametersGenerator(new TigerDigest());
+-                    break;
++                    // BEGIN android-changed
++                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA1());
++                    // END android-changed
++                    break;
++                // BEGIN android-removed
++                // case RIPEMD160:
++                //     generator = new PKCS5S2ParametersGenerator(new RIPEMD160Digest());
++                //     break;
++                // case TIGER:
++                //     generator = new PKCS5S2ParametersGenerator(new TigerDigest());
++                //     break;
++                // END android-removed
+                 case SHA256:
+-                    generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
+-                    break;
+-                case GOST3411:
+-                    generator = new PKCS5S2ParametersGenerator(new GOST3411Digest());
+-                    break;
++                    // BEGIN android-changed
++                    generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA256());
++                    // END android-changed
++                    break;
++                // BEGIN android-removed
++                // case GOST3411:
++                //     generator = new PKCS5S2ParametersGenerator(new GOST3411Digest());
++                //     break;
++                // END android-removed
+                 default:
+                     throw new IllegalStateException("unknown digest scheme for PBE PKCS5S2 encryption.");
+                 }
+@@ -103,27 +130,39 @@
              {
                  switch (hash)
                  {
@@ -6319,10 +6669,10 @@
                  default:
                      throw new IllegalStateException("unknown digest scheme for PBE encryption.");
                  }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/util/DigestFactory.java bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/util/DigestFactory.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jcajce/provider/util/DigestFactory.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jcajce/provider/util/DigestFactory.java	2012-09-17 23:04:47.000000000 +0000
-@@ -10,19 +10,26 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/util/DigestFactory.java bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/util/DigestFactory.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jcajce/provider/util/DigestFactory.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jcajce/provider/util/DigestFactory.java	2013-09-26 18:06:21.000000000 +0000
+@@ -10,12 +10,17 @@
  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
  import org.bouncycastle.crypto.Digest;
@@ -6346,47 +6696,7 @@
  import org.bouncycastle.util.Strings;
  
  public class DigestFactory
- {
-     private static Set md5 = new HashSet();
-     private static Set sha1 = new HashSet();
--    private static Set sha224 = new HashSet();
-+    // BEGIN android-removed
-+    // private static Set sha224 = new HashSet();
-+    // END android-removed
-     private static Set sha256 = new HashSet();
-     private static Set sha384 = new HashSet();
-     private static Set sha512 = new HashSet();
-@@ -38,9 +45,11 @@
-         sha1.add("SHA-1");
-         sha1.add(OIWObjectIdentifiers.idSHA1.getId());
-         
--        sha224.add("SHA224");
--        sha224.add("SHA-224");
--        sha224.add(NISTObjectIdentifiers.id_sha224.getId());
-+        // BEGIN android-removed
-+        // sha224.add("SHA224");
-+        // sha224.add("SHA-224");
-+        // sha224.add(NISTObjectIdentifiers.id_sha224.getId());
-+        // END android-removed
-         
-         sha256.add("SHA256");
-         sha256.add("SHA-256");
-@@ -61,9 +70,11 @@
-         oids.put("SHA-1", OIWObjectIdentifiers.idSHA1);
-         oids.put(OIWObjectIdentifiers.idSHA1.getId(), OIWObjectIdentifiers.idSHA1);
-         
--        oids.put("SHA224", NISTObjectIdentifiers.id_sha224);
--        oids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
--        oids.put(NISTObjectIdentifiers.id_sha224.getId(), NISTObjectIdentifiers.id_sha224);
-+        // BEGIN android-removed
-+        // oids.put("SHA224", NISTObjectIdentifiers.id_sha224);
-+        // oids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
-+        // oids.put(NISTObjectIdentifiers.id_sha224.getId(), NISTObjectIdentifiers.id_sha224);
-+        // END android-removed
-         
-         oids.put("SHA256", NISTObjectIdentifiers.id_sha256);
-         oids.put("SHA-256", NISTObjectIdentifiers.id_sha256);
-@@ -85,27 +96,39 @@
+@@ -85,27 +90,39 @@
          
          if (sha1.contains(digestName))
          {
@@ -6398,21 +6708,17 @@
          if (md5.contains(digestName))
          {
 -            return new MD5Digest();
--        }
--        if (sha224.contains(digestName))
--        {
--            return new SHA224Digest();
--        }
 +            // BEGIN android-changed
 +            return AndroidDigestFactory.getMD5();
 +            // END android-changed
-+        }
-+        // BEGIN android-removed
-+        // if (sha224.contains(digestName))
-+        // {
-+        //     return new SHA224Digest();
-+        // }
-+        // END android-removed
+         }
+         if (sha224.contains(digestName))
+         {
+-            return new SHA224Digest();
++            // BEGIN android-changed
++            return AndroidDigestFactory.getSHA224();
++            // END android-changed
+         }
          if (sha256.contains(digestName))
          {
 -            return new SHA256Digest();
@@ -6436,20 +6742,9 @@
          }
          
          return null;
-@@ -116,7 +139,9 @@
-         String digest2)
-     {
-         return (sha1.contains(digest1) && sha1.contains(digest2))
--            || (sha224.contains(digest1) && sha224.contains(digest2))
-+            // BEGIN android-removed
-+            // || (sha224.contains(digest1) && sha224.contains(digest2))
-+            // END android-removed
-             || (sha256.contains(digest1) && sha256.contains(digest2))
-             || (sha384.contains(digest1) && sha384.contains(digest2))
-             || (sha512.contains(digest1) && sha512.contains(digest2))
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java bcprov-jdk15on-149/org/bouncycastle/jce/PKCS10CertificationRequest.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jce/PKCS10CertificationRequest.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java bcprov-jdk15on-150/org/bouncycastle/jce/PKCS10CertificationRequest.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jce/PKCS10CertificationRequest.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jce/PKCS10CertificationRequest.java	2013-09-26 18:06:21.000000000 +0000
 @@ -30,14 +30,18 @@
  import org.bouncycastle.asn1.DERBitString;
  import org.bouncycastle.asn1.DERNull;
@@ -6471,7 +6766,7 @@
  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
  import org.bouncycastle.asn1.x509.X509Name;
-@@ -81,15 +85,20 @@
+@@ -81,8 +85,11 @@
  
      static
      {
@@ -6485,26 +6780,7 @@
          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"));
-         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,57 +106,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);
+@@ -102,12 +109,14 @@
          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"));
@@ -6524,19 +6800,8 @@
 +        // 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("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+@@ -120,11 +129,13 @@
          algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
          algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
          algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
@@ -6555,12 +6820,7 @@
  
          //
          // 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
+@@ -134,11 +145,16 @@
          oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
          oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
          oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
@@ -6579,40 +6839,8 @@
 +        // 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");
-         
-         //
-@@ -161,27 +191,35 @@
-         // 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);
- 
+         oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+@@ -172,8 +188,10 @@
          //
          // RFC 4491
          //
@@ -6625,36 +6853,7 @@
          //
          // explicit params
          //
-         AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
-         params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
- 
--        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
--        params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
-+        // BEGIN android-removed
-+        // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
-+        // params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
-+        // END android-removed
- 
-         AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
-         params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
-@@ -600,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";
-@@ -616,22 +656,24 @@
+@@ -616,22 +634,24 @@
          {
              return "SHA512";
          }
@@ -6695,10 +6894,10 @@
          else
          {
              return digestAlgOID.getId();            
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java bcprov-jdk15on-149/org/bouncycastle/jce/provider/BouncyCastleProvider.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2013-05-25 02:14:15.000000000 +0000
-@@ -64,13 +64,20 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java bcprov-jdk15on-150/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jce/provider/BouncyCastleProvider.java	2013-12-12 00:35:05.000000000 +0000
+@@ -64,15 +64,22 @@
  
      private static final String[] SYMMETRIC_MACS =
      {
@@ -6710,19 +6909,23 @@
  
      private static final String[] SYMMETRIC_CIPHERS =
      {
--        "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DES", "DESede", "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
--        "Noekeon", "RC2", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
+-        "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede",
+-        "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5",
+-        "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "TEA", "Twofish", "Threefish",
+-        "VMPC", "VMPCKSA3", "XTEA", "XSalsa20"
 +        // BEGIN android-removed
-+        // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DES", "DESede", "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
-+        // "Noekeon", "RC2", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
++        // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede",
++        // "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5",
++        // "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "TEA", "Twofish", "Threefish",
++        // "VMPC", "VMPCKSA3", "XTEA", "XSalsa20"
 +        // END android-removed
 +        // BEGIN android-added
-+        "AES", "ARC4", "Blowfish", "DES", "DESede", "RC2", "Twofish"
++        "AES", "ARC4", "Blowfish", "DES", "DESede", "RC2", "Twofish",
 +        // END android-added
      };
  
       /*
-@@ -82,12 +89,22 @@
+@@ -84,12 +91,22 @@
      // later ones configure it.
      private static final String[] ASYMMETRIC_GENERIC =
      {
@@ -6747,21 +6950,21 @@
      };
  
      /*
-@@ -96,7 +113,12 @@
+@@ -98,7 +115,12 @@
      private static final String DIGEST_PACKAGE = "org.bouncycastle.jcajce.provider.digest.";
      private static final String[] DIGESTS =
      {
--        "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Tiger", "Whirlpool"
+-        "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool"
 +        // BEGIN android-removed
-+        // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Tiger", "Whirlpool"
++        // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool"
 +        // END android-removed
 +        // BEGIN android-added
-+        "MD5", "SHA1", "SHA256", "SHA384", "SHA512",
++        "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512",
 +        // END android-added
      };
  
      /*
-@@ -143,48 +165,52 @@
+@@ -145,48 +167,52 @@
  
          loadAlgorithms(KEYSTORE_PACKAGE, KEYSTORES);
  
@@ -6853,9 +7056,9 @@
      }
  
      private void loadAlgorithms(String packageName, String[] names)
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/CertBlacklist.java bcprov-jdk15on-149/org/bouncycastle/jce/provider/CertBlacklist.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/CertBlacklist.java	1970-01-01 00:00:00.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jce/provider/CertBlacklist.java	2013-12-10 21:31:49.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/CertBlacklist.java bcprov-jdk15on-150/org/bouncycastle/jce/provider/CertBlacklist.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/CertBlacklist.java	1970-01-01 00:00:00.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jce/provider/CertBlacklist.java	2013-12-10 21:31:49.000000000 +0000
 @@ -0,0 +1,228 @@
 +/*
 + * Copyright (C) 2012 The Android Open Source Project
@@ -7085,10 +7288,10 @@
 +    }
 +
 +}
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java bcprov-jdk15on-149/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2013-01-31 02:26:40.000000000 +0000
-@@ -61,14 +61,18 @@
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java bcprov-jdk15on-150/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java	2013-12-12 00:35:05.000000000 +0000
+@@ -61,18 +61,24 @@
  import org.bouncycastle.asn1.x509.PolicyInformation;
  import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
  import org.bouncycastle.asn1.x509.X509Extension;
@@ -7109,7 +7312,14 @@
  import org.bouncycastle.x509.X509AttributeCertificate;
  import org.bouncycastle.x509.X509CRLStoreSelector;
  import org.bouncycastle.x509.X509CertStoreSelector;
-@@ -656,38 +660,40 @@
+-import org.bouncycastle.x509.X509Store;
++// BEGIN android-removed
++// import org.bouncycastle.x509.X509Store;
++// END android-removed
+ 
+ public class CertPathValidatorUtilities
+ {
+@@ -656,38 +662,40 @@
          {
              try
              {
@@ -7182,7 +7392,44 @@
              }
              catch (Exception e)
              {
-@@ -752,33 +758,35 @@
+@@ -720,20 +728,22 @@
+         {
+             Object obj = iter.next();
+ 
+-            if (obj instanceof X509Store)
+-            {
+-                X509Store certStore = (X509Store)obj;
+-                try
+-                {
+-                    certs.addAll(certStore.getMatches(certSelect));
+-                }
+-                catch (StoreException e)
+-                {
+-                    throw new AnnotatedException(
+-                            "Problem while picking certificates from X.509 store.", e);
+-                }
+-            }
+-            else
++            // BEGIN android-removed
++            // if (obj instanceof X509Store)
++            // {
++            //     X509Store certStore = (X509Store)obj;
++            //     try
++            //     {
++            //         certs.addAll(certStore.getMatches(certSelect));
++            //     }
++            //     catch (StoreException e)
++            //     {
++            //         throw new AnnotatedException(
++            //                 "Problem while picking certificates from X.509 store.", e);
++            //     }
++            // }
++            // else
++            // END android-removed
+             {
+                 CertStore certStore = (CertStore)obj;
+ 
+@@ -752,33 +762,35 @@
          return certs;
      }
  
@@ -7245,9 +7492,9 @@
  
      protected static void addAdditionalStoresFromCRLDistributionPoint(
          CRLDistPoint crldp, ExtendedPKIXParameters pkixParams)
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java bcprov-jdk15on-149/org/bouncycastle/jce/provider/JCEECPrivateKey.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java bcprov-jdk15on-150/org/bouncycastle/jce/provider/JCEECPrivateKey.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jce/provider/JCEECPrivateKey.java	2013-12-12 00:35:05.000000000 +0000
 @@ -20,8 +20,10 @@
  import org.bouncycastle.asn1.DERInteger;
  import org.bouncycastle.asn1.DERNull;
@@ -7274,8 +7521,8 @@
 -                        ECGOST3410NamedCurves.getName(oid),
 -                        ellipticCurve,
 -                        new ECPoint(
--                                gParam.getG().getX().toBigInteger(),
--                                gParam.getG().getY().toBigInteger()),
+-                                gParam.getG().getAffineXCoord().toBigInteger(),
+-                                gParam.getG().getAffineYCoord().toBigInteger()),
 -                        gParam.getN(),
 -                        gParam.getH());
 -            }
@@ -7290,8 +7537,8 @@
 +            //             ECGOST3410NamedCurves.getName(oid),
 +            //             ellipticCurve,
 +            //             new ECPoint(
-+            //                     gParam.getG().getX().toBigInteger(),
-+            //                     gParam.getG().getY().toBigInteger()),
++            //                     gParam.getG().getAffineXCoord().toBigInteger(),
++            //                     gParam.getG().getAffineYCoord().toBigInteger()),
 +            //             gParam.getN(),
 +            //             gParam.getH());
 +            // }
@@ -7319,9 +7566,9 @@
              {
  
                  info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java bcprov-jdk15on-149/org/bouncycastle/jce/provider/JCEECPublicKey.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jce/provider/JCEECPublicKey.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java bcprov-jdk15on-150/org/bouncycastle/jce/provider/JCEECPublicKey.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/JCEECPublicKey.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jce/provider/JCEECPublicKey.java	2013-12-12 00:35:05.000000000 +0000
 @@ -18,9 +18,11 @@
  import org.bouncycastle.asn1.DERBitString;
  import org.bouncycastle.asn1.DERNull;
@@ -7375,7 +7622,7 @@
      }
      
      public JCEECPublicKey(
-@@ -179,54 +189,56 @@
+@@ -179,54 +189,55 @@
  
      private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
      {
@@ -7421,13 +7668,12 @@
 -                    ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
 -                    ellipticCurve,
 -                    new ECPoint(
--                            spec.getG().getX().toBigInteger(),
--                            spec.getG().getY().toBigInteger()),
+-                            spec.getG().getAffineXCoord().toBigInteger(),
+-                            spec.getG().getAffineYCoord().toBigInteger()),
 -                            spec.getN(), spec.getH());
 -
 -        }
 -        else
-+        // BEGIN android-removed
 +        // if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
 +        // {
 +        //     DERBitString bits = info.getPublicKeyData();
@@ -7470,8 +7716,8 @@
 +        //             ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
 +        //             ellipticCurve,
 +        //             new ECPoint(
-+        //                     spec.getG().getX().toBigInteger(),
-+        //                     spec.getG().getY().toBigInteger()),
++        //                     spec.getG().getAffineXCoord().toBigInteger(),
++        //                     spec.getG().getAffineYCoord().toBigInteger()),
 +        //                     spec.getN(), spec.getH());
 +        //
 +        // }
@@ -7480,7 +7726,7 @@
          {
              X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithmId().getParameters());
              ECCurve                 curve;
-@@ -315,52 +327,54 @@
+@@ -315,52 +326,54 @@
          ASN1Encodable        params;
          SubjectPublicKeyInfo info;
  
@@ -7513,8 +7759,8 @@
 -                }
 -            }
 -
--            BigInteger      bX = this.q.getX().toBigInteger();
--            BigInteger      bY = this.q.getY().toBigInteger();
+-            BigInteger      bX = this.q.getAffineXCoord().toBigInteger();
+-            BigInteger      bY = this.q.getAffineYCoord().toBigInteger();
 -            byte[]          encKey = new byte[64];
 -
 -            extractBytes(encKey, 0, bX);
@@ -7560,8 +7806,8 @@
 +        //         }
 +        //     }
 +        //
-+        //     BigInteger      bX = this.q.getX().toBigInteger();
-+        //     BigInteger      bY = this.q.getY().toBigInteger();
++        //     BigInteger      bX = this.q.getAffineXCoord().toBigInteger();
++        //     BigInteger      bY = this.q.getAffineYCoord().toBigInteger();
 +        //     byte[]          encKey = new byte[64];
 +        //
 +        //     extractBytes(encKey, 0, bX);
@@ -7581,9 +7827,9 @@
          {
              if (ecSpec instanceof ECNamedCurveSpec)
              {
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java bcprov-jdk15on-149/org/bouncycastle/jce/provider/JCEStreamCipher.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jce/provider/JCEStreamCipher.java	2013-05-25 02:14:15.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java bcprov-jdk15on-150/org/bouncycastle/jce/provider/JCEStreamCipher.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jce/provider/JCEStreamCipher.java	2013-05-25 02:14:15.000000000 +0000
 @@ -23,8 +23,10 @@
  import javax.crypto.ShortBufferException;
  import javax.crypto.spec.IvParameterSpec;
@@ -7877,9 +8123,64 @@
 +    // }
 +    // END android-removed
  }
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java bcprov-jdk15on-149/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2012-09-17 23:04:47.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/PKIXCRLUtil.java bcprov-jdk15on-150/org/bouncycastle/jce/provider/PKIXCRLUtil.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/PKIXCRLUtil.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jce/provider/PKIXCRLUtil.java	2013-12-12 00:35:05.000000000 +0000
+@@ -15,7 +15,9 @@
+ import org.bouncycastle.util.StoreException;
+ import org.bouncycastle.x509.ExtendedPKIXParameters;
+ import org.bouncycastle.x509.X509CRLStoreSelector;
+-import org.bouncycastle.x509.X509Store;
++// BEGIN android-removed
++// import org.bouncycastle.x509.X509Store;
++// END android-removed
+ 
+ public class PKIXCRLUtil
+ {
+@@ -114,22 +116,24 @@
+         {
+             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
++            // BEGIN android-removed
++            // 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
++            // END android-removed
+             {
+                 CertStore store = (CertStore)obj;
+ 
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java bcprov-jdk15on-150/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java	2012-09-17 23:04:47.000000000 +0000
 @@ -1,5 +1,8 @@
  package org.bouncycastle.jce.provider;
  
@@ -7938,9 +8239,9 @@
              // try
              // {
              //
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/X509CertificateObject.java bcprov-jdk15on-149/org/bouncycastle/jce/provider/X509CertificateObject.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/X509CertificateObject.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jce/provider/X509CertificateObject.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/X509CertificateObject.java bcprov-jdk15on-150/org/bouncycastle/jce/provider/X509CertificateObject.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/X509CertificateObject.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jce/provider/X509CertificateObject.java	2013-01-31 02:26:40.000000000 +0000
 @@ -57,6 +57,9 @@
  import org.bouncycastle.asn1.x509.Extensions;
  import org.bouncycastle.asn1.x509.GeneralName;
@@ -7984,9 +8285,9 @@
                      break;
                  case GeneralName.dNSName:
                  case GeneralName.rfc822Name:
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java bcprov-jdk15on-149/org/bouncycastle/jce/provider/X509SignatureUtil.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/jce/provider/X509SignatureUtil.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java bcprov-jdk15on-150/org/bouncycastle/jce/provider/X509SignatureUtil.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/jce/provider/X509SignatureUtil.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/jce/provider/X509SignatureUtil.java	2013-09-26 18:06:21.000000000 +0000
 @@ -14,7 +14,9 @@
  import org.bouncycastle.asn1.ASN1Sequence;
  import org.bouncycastle.asn1.DERNull;
@@ -8019,24 +8320,7 @@
              if (sigAlgId.getObjectId().equals(X9ObjectIdentifiers.ecdsa_with_SHA2))
              {
                  ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params);
-@@ -98,10 +102,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";
-@@ -114,22 +120,24 @@
+@@ -114,22 +118,24 @@
          {
              return "SHA512";
          }
@@ -8077,9 +8361,9 @@
          else
          {
              return digestAlgOID.getId();            
-diff -Naur bcprov-jdk15on-149.orig/org/bouncycastle/x509/X509Util.java bcprov-jdk15on-149/org/bouncycastle/x509/X509Util.java
---- bcprov-jdk15on-149.orig/org/bouncycastle/x509/X509Util.java	2013-05-31 13:16:46.000000000 +0000
-+++ bcprov-jdk15on-149/org/bouncycastle/x509/X509Util.java	2013-01-31 02:26:40.000000000 +0000
+diff -Naur bcprov-jdk15on-150.orig/org/bouncycastle/x509/X509Util.java bcprov-jdk15on-150/org/bouncycastle/x509/X509Util.java
+--- bcprov-jdk15on-150.orig/org/bouncycastle/x509/X509Util.java	2013-12-03 20:18:20.000000000 +0000
++++ bcprov-jdk15on-150/org/bouncycastle/x509/X509Util.java	2013-09-26 18:06:21.000000000 +0000
 @@ -25,12 +25,16 @@
  import org.bouncycastle.asn1.ASN1Integer;
  import org.bouncycastle.asn1.DERNull;
@@ -8099,7 +8383,7 @@
  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
  import org.bouncycastle.jce.X509Principal;
-@@ -44,14 +48,18 @@
+@@ -44,8 +48,10 @@
      
      static
      {   
@@ -8112,24 +8396,7 @@
          algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
          algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
          algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
-         algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
--        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
--        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
-+        // 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 +67,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
+@@ -63,12 +69,14 @@
          algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
          algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
          algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
@@ -8149,19 +8416,8 @@
 +        // 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("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+@@ -81,11 +89,13 @@
          algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
          algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
          algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
@@ -8180,25 +8436,7 @@
  
          //
          // 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,8 +127,10 @@
+@@ -105,8 +115,10 @@
          //
          // RFC 4491
          //
@@ -8211,16 +8449,3 @@
  
          //
          // explicit params
-@@ -114,8 +138,10 @@
-         AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
-         params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
- 
--        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
--        params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
-+        // BEGIN android-removed
-+        // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
-+        // params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
-+        // END android-removed
- 
-         AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
-         params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));